message db "Enter a digit ", 0xA,0xD
Length equ $- message
是否用于获取字符串的长度?
它在内部如何运作?
答案 0 :(得分:12)
$
是在发出其出现的行的字节(如果有)之前的当前位置的地址。 Section 3.5 of the manual没有详细说明。
$ - msg
就像在做here - msg
,即当前位置(在字符串末尾)和字符串开头之间的字节距离。 (See also this tutorial在NASM标签和指令上,如resb
)
(相关:大多数其他x86汇编程序也以相同的方式使用$
,但使用.
(句点)的GAS除外。MMIX assembler使用@
正确的语义意义)。
为了更好地理解它,可能有助于了解当你弄错时会发生什么:In NASM labels next to each other in memory are causing printing issues。这个人用过
HELLO_MSG db 'Hello, World!',0
GOODBYE_MSG db 'Goodbye!',0
hlen equ $ - HELLO_MSG
glen equ $ - GOODBYE_MSG
导致hlen
包括两个字符串的长度。
EQU
立即评估右手边的恒定值。 (在某些汇编程序中,如FASM,equ
是文本替换,您必须使用glen = $ - GOODBYE_MSG
在此位置使用$
进行评估,而不是在后期评估$
{ {1}}指令或其他内容。但NASM mov ecx, glen
当场评估;使用equ
进行文字替换)
使用%define
完全等同于在行的开头添加标签并使用它而不是$
。
也可以使用常规标签来完成对象大小示例:
$
您可以将msg: db "Enter a digit "
msgend:
Length equ msgend - msg
Length2 equ $ - msg ; Length2 = Length
newline: db 0xA,0xD
Length3 equ $ - msg ; Length3 includes the \n\r LF CR sequence as well.
; sometimes that *is* what you want
放在任何地方,或直接Length equ msgend - msg
。 (有时在某些内容上贴上标签很有用,例如在循环底部有mov ecx, msgend - msg
/ cmp rsi, msgend
。
jb .loop
汇编与此相同(但不创建符号表条目或与现有名称冲突):
times 4 dd $
在here: times 4 dd here
中,times 4 dd $
不会为每个dword更新自己的地址,它仍然是该行开头的地址。 (在文件中单独尝试并将hexdump用于平面二进制文件:它全部为零。)
但是$
块在%rep
之前展开,所以
$
确实生成0,4,8,12(从本例中的平面二进制文件中的%rep 4
dd $
%endrep
的输出位置开始。)
0
正常直接call
is E8 rel32
,相对于指令的 end 计算位移。 (即,在执行指令时相对于EIP / RIP,因为RIP保存下一条指令的地址.RIP相对寻址模式也是这样工作的。)dword是4字节,因此在$ nasm -o foo rep.asm && hd foo
00000000 00 00 00 00 04 00 00 00 08 00 00 00 0c 00 00 00
伪 - 使用一个操作数的指令,结尾的地址是dd
。您当然可以在 next 行上添加标签并使用它。
$+4
反汇编输出(来自earlyfunc: ; before the call
call func ; let NASM calculate the offset
db 0xE8
dd func - ($ + 4) ; or do it ourselves
db 0xE8
dd earlyfunc - ($ + 4) ; and it still works for negative offsets
...
func: ; after the call
):
objdump -drwC -Mintel
如果偏移错误,objdump会将符号部分设为0000000000400080 <earlyfunc>:
400080: e8 34 00 00 00 call 4000b9 <func> # encoded by NASM
400085: e8 2f 00 00 00 call 4000b9 <func> # encoded manually
40008a: e8 f1 ff ff ff call 400080 <earlyfunc> # and backwards works too.
。前2个调用指令中的相对位移相差5,因为func+8
长度为5个字节且它们具有相同的实际目标,不相同的相对位移。请注意,反汇编程序负责将rel32添加到调用指令的地址,以显示绝对目标地址。
您可以使用call rel32
对短db target - ($+1)
或jmp
的偏移进行编码。 (但要注意:jcc
不对,因为当你将操作码和置换作为同一db 0xEB, target - ($+1)
伪的多个参数时,指令的结尾实际为$+2
指令。)
相关: db
是当前部分的开头 ,因此$$
是您当前部分的距离。但这仅在当前文件中,因此链接两个放置$ - $$
内容的文件与同一源文件中有两个.rodata
块不同。请参阅What's the real meaning of $$ in nasm。
到目前为止,最常见的用途是section .rodata
/ times 510-($-$$) db 0
填充(带dw 0xAA55
)引导扇区到510字节,然后添加引导扇区签名以生成512字节。 (The NASM manual explains how this works)