assembly 此指令会发生什么情况:移动电子数据交换,双字指针[电子数据交换+偏移量32]

mfuanj7w  于 2022-12-19  发布在  其他
关注(0)|答案(1)|浏览(129)

这是一个32位的Windows程序随机崩溃。我用Visual Studio 2019调试了它。下面是我看到的。
执行前,

点击“单步执行”后:

CPU似乎将指令分为3个部分:8B BB, 4C, F6 07 00。什么是8B BB?我确认地址[ebx +7F64C]有效且可访问。
编辑:如果我点击“步过”,EDI没有像预期的那样改变,添加寄存器的截图。
要关闭:我意识到这个问题是调试器特有的,断点在指令的中间。随机崩溃反正和这个无关。

oknrviil

oknrviil1#

正如Peter Cordes所解释的,在x86架构上,跳转到指令中间是可能的。%rip寄存器在解码指令时并不考虑其后面的内容,它只关注指令现在和将来的位置。因此,根据您开始查看的位置,代码可能完全不同。字节本身根本没有改变。只是对它们的诠释。
有趣的是,这可以在许多CISC架构上被滥用来更有效地工作。我最喜欢的一个例子来自6502汇编:

LDA $30   ;load the byte at address 0x0030
CMP $31   ;compare that value to the byte at address 0x0031
BEQ skip  ;if they're equal, return 32, otherwise return 16.
LDA #$10
jmp done  
skip:
LDA #$20
done:
RTS

JMP指令需要3个字节来编码,当您试图在有限的机器上尽可能地保存空间,并且只想跳过2个字节的指令(在本例中为LDA #$20)时,这是很不幸的。

LDA $30
CMP $31
BEQ skip
LDA #$10
.byte $2c
skip:
LDA #$20
RTS

如果比较结果相等,则LDA #$20正常执行,否则,CPU将代码解释为:

LDA $30
CMP $31
BEQ skip    ;branch not taken
LDA #$10
BIT $20A9   ;set the flags as if we ANDed the accumulator with the byte at 0x20A9.
            ;no registers are changed.
RTS

对于上下文,BIT $20A9的编码是2C A9 20LDA #$20的编码是A9 20。实际上,我们破坏了下面的指令以避免分支,这在代码中节省了2个字节。这种技巧可能对内存Map硬件有副作用,因此,对于某些常量,您可能无法也可能无法安全地使用此方法(此示例不应在内斯上使用,但在Commodore 64或Apple II上应该可以。)

相关问题