为什么在NASM中使用RIP相对寻址?

时间:2015-07-05 19:56:08

标签: assembly nasm memory-address cpu-registers 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

我想知道线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

为什么会这样? lea mov无法做到的{{1}}有什么特别之处?我怎么知道何时使用每一个?

2 个答案:

答案 0 :(得分:5)

  

lea mov无法做到的mov reg,imm有什么特别之处?

mov eax,someVar立即常量加载到其目标操作数中。立即常数直接编码在操作码中,例如,如果B8 EF CD AB 00的地址为someVar0x00ABCDEF将被编码为imm。即要编写msg地址为msg的此类指令,您需要知道mov reg,[expression]的确切地址。在与位置无关的代码中,您不是先验的。

expression加载位于expression描述的地址的值。 x86指令的复杂编码方案允许具有相当复杂的reg1+reg2*s+displ:通常它是s,其中reg1可以是0,1,2,4,reg2和{ {1}}可以是通用寄存器或零,displ是立即置换。在64位模式下,expression可以有另外一种形式:RIP+displ,即地址是相对于下一条指令计算的。

lea reg,[expression]使用所有这种复杂的计算地址的方式将地址本身加载到reg(与mov不同,后者取消引用计算的地址)。因此,在编译时不可用的信息,即将在RIP中的绝对地址,可以在指令中编码而不知道其值。 nasm表达式lea rsi,[rel msg]被翻译成类似

的内容
    lea rsi,[rip+(msg-nextInsn)]
nextInsn:

使用相对地址msg-nextInsn而不是msg的绝对地址,从而允许汇编器不知道实际地址但仍然编码指令。

答案 1 :(得分:2)

  

mov不能做什么特别的?

LEA r, [rel symbol]可以在运行时访问RIP。 mov r, imm无法做到。立即数被编码到指令的二进制表示中,这意味着如果代码+数据被映射到链接时不知道的地址,它就不会工作。 (即它的位置相关代码。)

这就是为什么RIP相对寻址对于PIC(与位置无关的代码)非常好的原因:不需要通过全局偏移表的间接级别来访问在同一目标文件中定义的静态数据,您可以使用RIP相对地址。

MacOS X甚至在可执行文件(不仅仅是共享库)中也需要PIC,因此在所有情况下都需要避免使用绝对寻址。