Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 为什么在NASM中使用RIP相对寻址?_Assembly_X86 64_Nasm_Memory Address_Cpu Registers - Fatal编程技术网

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

Assembly 为什么在NASM中使用RIP相对寻址?,assembly,x86-64,nasm,memory-address,cpu-registers,Assembly,X86 64,Nasm,Memory Address,Cpu Registers,我有一个适用于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 "

我有一个适用于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
我想知道行
learsi[rel msg]
。为什么NASM强迫我这么做?据我所知,
msg
只是指向可执行文件中某些数据的指针,执行
mov rsi,msg
会将该地址放入
rsi
。但是如果我将行
learsi[rel msg]
替换为,NASM将抛出此错误(注意:我正在使用命令
NASM-f macho64 hello.asm
):

为什么会发生这种情况?
lea
有什么特别之处,
mov
做不到的?我如何知道何时使用每一个

lea有什么特别之处是mov做不到的

lear,[rel symbol]
可以在运行时访问RIP<代码>移动r,imm不能。立即数常量被编码到指令的二进制表示形式中,这意味着如果代码+数据映射到链接时未知的地址,它将不起作用。(即其位置相关代码。)

这就是为什么RIP相对寻址对PIC(位置无关代码)如此好的原因:您不需要通过全局偏移量表进行一定程度的间接寻址来访问同一对象文件中定义的静态数据,只需使用RIP相对地址即可

它还可以有效地为您提供64位地址,而不需要在指令中嵌入完整的64位绝对值。MacOS X需要64位地址,因为它将“映像基”映射到低4GiB虚拟地址空间之外

如果可执行文件(不仅仅是共享库)是PIC,这是一件好事,因此MacOS可以随机化它们的基址以获得更高的安全性。(无需在出现的任何位置重写绝对地址。)


在位置相关的Linux可执行文件(不是MacOS)中,您可以作为优化使用
movesi,msg
。注意ESI,而不是RSI。
mov-rsi,msg
如果使用10字节
mov-rsi,imm64
而不是7字节
lea-rsi,[RIP+rel32]
,效率会更低。()

在x86-64中,访问静态数据的“正常”方式是使用RIP相对寻址,例如
mov-eax、[rel-my\u-global\u-var]
。只有将地址放入寄存器时,如果目标允许32位绝对值,您有时可能会利用32位绝对值

其他相关问答:

  • )
lea
有什么特别之处,
mov
做不到的

mov reg,imm
将立即数常量加载到其目标操作数中。立即常数直接编码在操作码中,例如
mov eax,如果
someVar
的地址为
0x00ABCDEF
,则someVar
将编码为
B8 EF CD AB 00
。也就是说,要用
imm
作为
msg
的地址对这样的指令进行编码,您需要知道
msg
的确切地址。在位置无关的代码中,您不知道它是先验的

mov reg,[expression]
加载位于
expression
描述的地址处的值。x86指令的复杂编码方案允许具有相当复杂的
表达式
:通常是
reg1+reg2*s+displa
,其中
s
可以是0,1,2,4,
reg1
reg2
可以是通用寄存器或零,
displa
是立即移位。在64位模式下,表达式可以有另一种形式:
RIP+DISF
,即相对于下一条指令计算地址

lea reg,[expression]
使用所有这些复杂的地址计算方法将地址本身加载到
reg
中(不同于
mov
,它取消对计算出的地址的引用)。因此,在编译时不可用的信息,即
RIP
中的绝对地址,可以在不知道其值的情况下在指令中编码。nasm表达式
learsi,[rel msg]
被翻译成

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

它使用相对地址
msg nextInsn
而不是绝对地址
msg
,因此允许汇编程序不知道实际地址,但仍然对指令进行编码。

我认为Jester已经回答了这个问题。Mach-O对象文件格式要求所有内容都与位置无关。这意味着您的代码需要能够在任何地址加载并仍能工作。
mov rsi,msg
使用的绝对地址必须根据程序加载的位置而改变,Mach-O不支持这种情况。@RossRidge,但“绝对地址”实际上不是相对于可执行文件的开头吗?CPU不知道可执行文件从何处开始。当它执行
mov rsi,msg
指令时,它用编码为立即操作数的值加载寄存器。该立即值必须是
msg
的实际地址。Mach-O不支持这一点。@RossRidge可执行文件知道它将被加载到哪里吗?如果没有,它如何知道
msg
的地址将在哪里?对于Mach-O,可执行文件不知道将加载到哪里。它不知道
msg
将位于何处。通过使用RIP相对寻址,它不需要。更新:OS X支持64位绝对地址的文本重定位,但它在低位32位之外加载可执行文件,因此32位绝对寻址不可用。因此,RIP相对寻址不是必需的,但它几乎总是OSX上的最佳选项。
    lea rsi,[rip+(msg-nextInsn)]
nextInsn: