HELLO_MSG db 'Hello, World!',0 ; normally you don't want ,0
GOODBYE_MSG db 'Goodbye!',0 ; in explicit-length strings, unless it also needs to be a C-string
hlen equ $ - HELLO_MSG
glen equ $ - GOODBYE_MSG
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
一般直接call is E8 rel32,其位移是相对于指令的 end 计算的。(即在指令执行时相对于EIP/RIP,因为RIP保存下一条指令的地址。RIP相对寻址模式也是这样工作的。)双字是4个字节,因此在具有一个操作数的dd伪指令中,结束的地址是$+4。当然,您可以在 next 行上放置一个标签并使用它。
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
2条答案
按热度按时间busg9geu1#
这会让汇编器在汇编时为您计算字符串长度
$
是当前位置的地址,* 在 * 发出它所在行的字节(如果有的话)之前。手册的第3.5节没有详细介绍。$ - msg
类似于here - msg
,即当前位置(字符串末尾)和字符串开头之间的字节距离。(NASM标签和指令(如resb
)上的See also this tutorial)(相关:除了GAS使用
.
(句点)之外,大多数其他x86汇编程序也以相同的方式使用$
。MMIX assembler使用@
,这具有正确的语义)。为了更好地理解它,看看当你出错时会发生什么可能会有所帮助:In NASM labels next to each other in memory are printing both strings instead of first one。此人使用了
从而得到包括两个串的长度的
hlen
。EQU
立即计算右边的值,得到一个常量值。(在一些汇编器中,比如FASM,equ
是一个文本替换,你必须使用glen = $ - GOODBYE_MSG
来计算这个位置上的$
,而不是在后面的mov ecx, glen
指令中计算$
。但是NASM的equ
当场计算;使用%define
进行文本替换)使用
$
完全等同于在行首放置一个标签,并使用它来代替$
。对象大小示例也可以使用常规标签来完成:
你可以把
Length equ msgend - msg
放在任何地方,或者直接把mov ecx, msgend - msg
放在任何地方。(有时候在某个东西的末尾加上一个标签是很有用的,例如在循环的底部加上cmp rsi, msgend
/jb .loop
。顺便说一句,它通常是CR LF,而不是LF CR。
不太明显的例子:
汇编与此相同的内容(但不创建符号表条目或与现有名称冲突):
在
times 4 dd $
中,$
并不会为每个双字更新到它自己的地址,它仍然是行的起始地址。(在一个文件中尝试它自己,并将平面二进制文件进行hexdump:都是零。)但是
%rep
块在$
之前扩展,因此会产生0、4、8、12(在此范例中,从平面二进制中
0
的输出位置开始)。手动编码跳转位移:
一般直接
call
isE8 rel32
,其位移是相对于指令的 end 计算的。(即在指令执行时相对于EIP/RIP,因为RIP保存下一条指令的地址。RIP相对寻址模式也是这样工作的。)双字是4个字节,因此在具有一个操作数的dd
伪指令中,结束的地址是$+4
。当然,您可以在 next 行上放置一个标签并使用它。反汇编输出(来自
objdump -drwC -Mintel
):例如,如果偏移量错误,objdump会将符号部分放置为
func+8
.前两个调用指令中的相对位移相差5,因为call rel32
的长度为5个字节,并且它们具有相同的实际目的地,* 不 * 相同的相对位移。请注意,反汇编器负责将rel 32添加到调用指令的地址,以显示绝对目标地址。您可以使用
db target - ($+1)
来编码较短的jmp
或jcc
的偏移量。(但要注意:db 0xEB, target - ($+1)
是不正确的,因为当您将操作码和位移作为同一条db
伪指令的多个参数放置时,指令的结尾实际上是$+2
。)相关:
$$
是当前 * 节的开始*,因此$ - $$
是您进入当前节的深度。但这只是在当前文件中,因此链接两个文件并将内容放入.rodata
与在同一个源文件中有两个section .rodata
块是不同的。请参见What's the real meaning of $$ in nasm。到目前为止,最常见的用法是
times 510-($-$$) db 0
/dw 0xAA55
将 Boot 扇区填充(使用db 0
)为510字节,然后添加引导扇区签名,使其为512字节。(NASM手册解释了这是如何工作的)koaltpgm2#
NASM文档
http://www.nasm.us/doc/nasmdoc3.html#section-3.5
NASM支持表达式中的两个特殊标记,允许计算涉及当前装配位置:$和$$标记。$的计算结果为包含表达式的行的开头的程序集位置;因此您可以使用JMP $编写无限循环。
http://www.nasm.us/doc/nasmdoc3.html#section-3.2.4
EQU定义了一个符号给定常数值:当使用EQU时,源代码行必须包含一个标签。2 EQU的作用是将给定的标签名定义为它的(唯一的)操作数的值。3这个定义是绝对的,以后不能改变。4因此,例如,
将msglen定义为常数12