我遇到了以下代码,并试图从概念上理解它:
mov si,offset v5
mov di,offset v2
sub si,di
v5
和v2
引用以下数据:
v2 dw 4
v5 dw 3
因此,根据我的理解,这似乎触及了x86汇编语言中间接寻址的概念。我知道si和di寄存器不等于值,而只是指向位置。因此,从上面的代码中减去两个指针,将得到什么答案?可行吗?
答案 0 :(得分:3)
是的,指针只是整数,您当然可以 减去它们,例如与sub si, di
。
假定它们相对于同一段基(例如,小/小或平坦的内存模型)偏移,则结果实际上是有意义的:指向的内存位置之间的距离(以字节为单位)。
@fuz提到的一个用例是:从指针获取数组索引。例如您可以通过增加指针来实现strlen
,然后最后执行sub ax, si
以返回长度。
当然,对于当前文件中定义的标签,该距离是一个汇编时间常数,因此您只需要请汇编器为您计算即可。我认为mov si, OFFSET v5 - v2
是正确的MASM语法。在NASM中,它只是mov si, v5 - v2
。有了这些定义,无论您是在汇编时使用si=2
还是使用运行时v5 - v2
指令,都将得到sub
,因为dw 4
的宽度为2个字节。 / p>
或者将2个数组输入作为2个指针+一个长度的函数可以通过减去并取绝对值以查看其是否小于长度来检查重叠。参见Should pointer comparisons be signed or unsigned in 64-bit x86?
就像在C语言中减去指针一样,不同之处在于您控制静态数据的布局,因此对有意义的操作或任何未定义的行为没有任何限制。 (除了在C中,指针减法根据类型的宽度缩放。因此,实际上就像在减去之前强制转换为uintptr_t
。)