Jer*_*ov2 2 assembly nasm cpu-registers memory-address mov
我有一个适用于Mac OS X的程序集hello world程序,如下所示:
global _main
section .text
_main:
mov rax, 0x2000004
mov rdi, 1
lea rsi, [rel msg]
mov rdx, msg.len
syscall
mov rax, 0x2000001
mov rdi, 0
syscall
section .data
msg: db "Hello, World!", 10
.len: equ $ - msg
Run Code Online (Sandbox Code Playgroud)
我想知道这条线lea rsi, [rel msg]。为什么NASM强迫我这样做?据我了解,它msg只是指向可执行文件中某些数据的指针,这样做mov rsi, msg会将地址放入rsi。但是,如果我将替换为lea rsi, [rel msg],则NASM会引发此错误(注意:我使用的是命令nasm -f macho64 hello.asm):
hello.asm:9: fatal: No section for index 2 offset 0 found
Run Code Online (Sandbox Code Playgroud)
为什么会这样?有什么特别之处lea是mov不能做?我怎么知道什么时候使用每个?
lea 有什么特别而 mov 做不到的?
LEA r, [rel symbol]可以在运行时访问 RIP。 mov r, imm不能。立即数被编码到指令的二进制表示中,这意味着如果代码+数据被映射到链接时未知的地址,它将不起作用。(即它是位置相关的代码。)
这就是为什么 RIP 相对寻址对 PIC(位置无关代码)如此有用的原因:不需要通过全局偏移表的间接级别来访问甚至在同一目标文件中定义的静态数据,您只需使用 RIP 相对地址。
它还可以有效地为您提供 64 位地址,而无需在指令中嵌入完整的 64 位绝对地址。MacOS X 需要 64 位地址,因为它将“图像库”映射到虚拟地址空间的低 4GiB 之外。
如果可执行文件(不仅仅是共享库)是 PIC,这是一件好事,因此 MacOS 可以随机化它们的基地址以提高安全性。(无需在绝对地址出现的任何地方重写它们。)
在位置相关的 Linux 可执行文件(不是 MacOS)中,您可以作为优化使用
mov esi, msg. 注意 ESI,而不是RSI。使用 10 字节而不是 7 字节
mov rsi, msg会降低效率。(如何将函数或标签的地址加载到寄存器中)mov rsi, imm64lea rsi, [RIP + rel32]
在 x86-64 中访问静态数据的“正常”方式是使用 RIP 相对寻址,例如mov eax, [rel my_global_var]. 如果目标允许 32 位绝对值,则仅用于将地址放入寄存器中,您有时可能会利用 32 位绝对值。
其他相关问答:
有什么特别之处
lea是mov不能做?
mov reg,imm将立即数加载到其目标操作数中。立即数直接在操作码mov eax,someVar中编码,例如,将被编码为B8 EF CD AB 00好像someVaris的地址0x00ABCDEF。即用您的imm地址编码这样的指令msg需要知道的确切地址msg。在与位置无关的代码中,您不会先验地知道它。
mov reg,[expression]加载位于所描述的地址处的值expression。x86指令的复杂编码方案允许非常复杂expression:通常为reg1+reg2*s+displ,其中s可以为0、1、2、4,可以为通用寄存器,reg1也reg2可以为零,并且displ是立即移位。在64位模式下,expression可以采用以下一种形式:RIP+displ即,相对于下一条指令计算地址。
lea reg,[expression]使用所有复杂的地址计算方法将地址本身加载到其中reg(与mov取消引用所计算的地址不同)。因此,在编译时不可用的信息,即绝对地址RIP,可以在指令中进行编码,而无需知道其值。nasm表达式lea rsi,[rel msg]被翻译成类似
lea rsi,[rip+(msg-nextInsn)]
nextInsn:
Run Code Online (Sandbox Code Playgroud)
使用相对地址msg-nextInsn而不是的绝对地址msg,从而使汇编器不知道实际地址,但仍对指令进行编码。
| 归档时间: |
|
| 查看次数: |
3874 次 |
| 最近记录: |