【问题标题】:EX6.x86 in The Art of Assembly装配艺术中的 EX6.x86
【发布时间】:2012-09-13 19:50:39
【问题描述】:

我正在尝试手动完成Art of Assembly 中的 3.6.7 自我修改代码练习部分,并且不禁想到我在高/低顺序上做错了什么字节交错(我知道作者是如何为他想象的 x86 变体做到这一点的)或者文本中有错误。

也就是说,文中的程序是

   sub  ax, ax
   mov  [100], ax

a: mov  ax, [100]
   cmp  ax, 0
   je   b
   halt

b: mov  ax, 00c6
   mov [100], ax
   mov  ax, 0710
   mov [102], ax
   mov  ax, a6a0
   mov [104], ax
   mov  ax, 1000
   mov [106], ax
   mov  ax, 8007
   mov [108], ax
   mov  ax, 00e6
   mov [10a], ax
   mov  ax, 0e10
   mov [10c], ax
   mov  ax, 4
   mov [10e], ax
   jmp 100

据称“将以下代码写入位置 100,然后执行它:”

   mov  ax, [1000]
   put
   add  ax, ax
   add  ax, [1000]
   put
   sub  ax, ax
   mov [1000], ax
   jmp 0004  

但是,由于多种原因,这对我来说没有意义(首先,它将 00 写入字节 100,这是一条应该跳转到的非法指令;其次,在地址似乎被切换了,等等)另一方面,如果我只是在 b 循环中的mov ax, c 语句中交换高/低位字节,那么这似乎是正确的。所以:

我错了吗(如果是,为什么?)还是应该交换 b 循环常量中的高位/低位字节?

【问题讨论】:

    标签: assembly x86 hla


    【解决方案1】:

    它不会在地址 100 存储 00,因为 x86 处理器是“小端”。将 00c6 存储为单词时,首先存储 c6。

    另一方面,自修改代码早已过时了。在现代处理器上,您不能写入代码段,也不能执行数据(至少在不跳过大量循环的情况下是这样)。另一个问题是指令缓存可能在您更改它之前很久就加载了未修改的代码。

    您要么冒着执行旧代码的风险,要么必须刷新所有缓存,这会对性能产生巨大影响。简而言之 - 自我修改代码是不值得的。自从 1980 年代初的 PC/XT 以来,我就没有使用过它。

    你为什么不跳过书中的一章?

    【讨论】:

    • 您能指出 AoA 的“x86”处理器在哪里详细介绍了它们的小端序吗?我想区分 AoA 中名义上的 886/8286/8486/8686 和现实世界的 80x86 处理器系列。
    • 抱歉,没看过那本书。我从 Intel 的文档中学习了 x86 系列(从 8088 开始 :-)。
    • 现代 x86 具有一致的指令缓存。我认为您的意思是“其他现代建筑”之类的。在循环中自我修改的代码在 x86 上是垃圾,但编写或修改一次然后执行多次是 JIT 的重点。这也是 .plt 部分在 Linux 上用于动态链接的方式(其中 jmp 目标由惰性动态链接重写)。 Linux 内核也有像 bool _static_cpu_has(u16 bit) Only pass if-statement once 这样的东西,它将 asm 修补到 jmpnop 而不是 cmp/jcc。
    • 请参阅Observing stale instruction fetching on x86 with self-modifying code,了解有关现代 x86 如何侦听 EIP/RIP 附近的存储以保持管道连贯性的更多信息。 “80486 和更早的处理器需要在修改代码和修改代码之间跳转,以刷新代码缓存。” (但即使没有jmp,P5 及更高版本也会检测到 SMC)。并不是说我鼓励人们编写更多的 SMC,只是它是一回事,不需要 x86 上的额外障碍/刷新。修改一次/执行 many 是一个胜利。
    猜你喜欢
    • 2013-06-27
    • 2016-10-12
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多