assembly $在NASM中是如何工作的?

jfgube3f  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(152)
message db "Enter a digit ", 0xA,0xD
Length equ $- message

它是否用于获取字符串的长度?
它在内部是如何工作的?

busg9geu

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。此人使用了

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

从而得到包括两个串的长度的hlen
EQU立即计算右边的值,得到一个常量值。(在一些汇编器中,比如FASM,equ是一个文本替换,你必须使用glen = $ - GOODBYE_MSG来计算这个位置上的$,而不是在后面的mov ecx, glen指令中计算$。但是NASM的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
顺便说一句,它通常是CR LF,而不是LF CR。

不太明显的例子:

times 4  dd $

汇编与此相同的内容(但不创建符号表条目或与现有名称冲突):

here:    times 4 dd here

times 4 dd $中,$并不会为每个双字更新到它自己的地址,它仍然是行的起始地址。(在一个文件中尝试它自己,并将平面二进制文件进行hexdump:都是零。)
但是%rep块在$之前扩展,因此

%rep 4
    dd $
%endrep

会产生0、4、8、12(在此范例中,从平面二进制中0的输出位置开始)。

$ nasm -o foo  rep.asm  && hd foo
00000000  00 00 00 00 04 00 00 00  08 00 00 00 0c 00 00 00

手动编码跳转位移:

一般直接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

反汇编输出(来自objdump -drwC -Mintel):

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.

例如,如果偏移量错误,objdump会将符号部分放置为func+8.前两个调用指令中的相对位移相差5,因为call rel32的长度为5个字节,并且它们具有相同的实际目的地,* 不 * 相同的相对位移。请注意,反汇编器负责将rel 32添加到调用指令的地址,以显示绝对目标地址。
您可以使用db target - ($+1)来编码较短的jmpjcc的偏移量。(但要注意: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手册解释了这是如何工作的)

koaltpgm

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因此,例如,

message         db      'hello, world' 
msglen          equ     $-message

将msglen定义为常数12

相关问题