我目前正在研究Irvine x86汇编书,目前正在学习第四章。
他们引入了OFFSET
指令,但是我对为什么要使用它感到困惑。为什么我不只是拿标签(已经是该数据的地址)?似乎OFFSET
只会增加额外的噪音。
我有这个小程序来说明我的观点。我有一个名为array
的数据标签,可以将数组的元素移到al
中。但是这本书讨论的是使用OFFSET
指令获取array
的地址并将其移动到esi
。但这对我来说似乎是不必要的,因为我可以只使用标签。
我有两段代码在下面做同样的事情。一个是在我使用标签访问数组元素的位置,另一个是在我使用OFFSET
将地址移至esi
,然后访问数组的元素的位置。
.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode: DWORD
.data
array BYTE 10h, 20h, 30h, 40h, 50h
.code
main PROC
xor eax, eax ; set eax to 0
; Using Labels
mov al, array
mov al, [array + 1]
mov al, [array + 2]
mov al, [array + 3]
mov al, [array + 4]
; Using Offset
mov esi, OFFSET array
mov al, [esi]
mov al, [esi + 1]
mov al, [esi + 2]
mov al, [esi + 3]
mov al, [esi + 4]
INVOKE ExitProcess, 0
main ENDP
END main
他们真的只是实现同一件事的两种方法吗?
本书中稍后讨论指针时,他们有这个例子:
.data
arrayB byte 10h, 20h, 30h, 40h
ptrB dword arrayB
这对我来说很有意义。 ptrB
保存arrayB
的地址。但是他们接着说:“您可以选择使用OFFSET
运算符来delcare ptrB以使关系更清晰:”
ptrB dword OFFSET arrayB
这一点一点都让我不清楚。我已经知道arrayB
是一个地址。似乎OFFSET
只是扔在那里,它实际上并没有做任何事情。从最后一行删除OFFSET
可以实现相同的目的。如果我仍然只能使用标签来获取地址,OFFSET
究竟会做什么?
他们真的只是实现同一件事的两种方法吗?
是,程序集具有许多的处理方式。
C等价于char *p = array;
然后使用p[0]
,p[1]
等与array[0]
,array[1]
等一起使用
将指针放在寄存器中的优势在于,当您反复使用它时,它可以节省一些代码大小;仅使用操作码+ ModRM的2字节mov
指令,而不是将绝对地址分别编码为[disp32]
寻址模式的每条指令。
另一个优点是您可以使用inc esi
increment指针。在其他情况下,如果您没有完全展开循环,则需要在寄存器中使用指针或索引。普通指针通常比[array + ecx]
好,尤其是比[array + ecx*4]
好,因为索引寻址模式有一些缺点。 ([array + ecx]
从技术上讲没有索引;它是[base + disp32]
,不需要SIB字节,也不算作Micro fusion and addressing modes的索引))>
顺便说一句,为了保持一致,我建议在mov al, array
上使用此选项>
的NASM语法中查看过,但是有些人甚至建议即使您仅使用MASM,也要使用该约定。 (但是请注意,在某些情况下,当没有寄存器时,[[0]时,MASM会使用ignore括号:Confusing brackets in MASM32,所以请不要以为在MASM中使用括号会使它像NASM一样工作。)mov al, [array + 0] mov al, [array + 1] ...
您可以这样写(我认为)
mov al, array mov al, array + 1
[但是为了清晰起见,我总是建议在内存操作数周围使用方括号。
特别是如果您曾经在需要[[总是
movzx eax, byte ptr [esi]