我尝试使用 gcc -S -fasm foo.c
将 C 代码编译为汇编代码。
c代码在主函数中声明全局变量和变量,如下所示:
int y=6;
int main()
{
int x=4;
x=x+y;
return 0;
}
现在我查看了从此 C 代码生成的汇编代码,发现全局变量 y 是使用 rip 指令指针的值存储的。
我以为只有 const 全局变量存储在文本段中,但是看这个例子,似乎常规全局变量也存储在文本段中,这很奇怪。
我想我做的一些假设是错误的,所以有人可以给我解释一下吗?
c编译器生成的汇编代码:
.file "foo.c"
.text
.globl y
.data
.align 4
.type y, @object
.size y, 4
y:
.long 6
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $4, -4(%rbp)
movl y(%rip), %eax
addl %eax, -4(%rbp)
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
最佳答案
可执行文件不同部分之间的偏移量是链接时间常量,因此 RIP 相对寻址可用于任何部分(包括 .data
,您的非 <const
全局变量)。请注意您的 asm 输出中的 .data
。
这甚至适用于 PIE 可执行文件或共享库,其中绝对地址未知直到运行时 (ASLR)。
位置无关可执行文件 (PIE) 的运行时 ASLR 随机化整个程序的一个基地址,而不是相对于彼此的各个段起始地址。
所有对静态变量的访问都使用 RIP 相对寻址,因为这是最有效的,即使在绝对寻址是一个选项的位置相关可执行文件中也是如此(因为静态代码/数据的绝对地址是链接-时间常数,在这种情况下不会通过动态链接重新定位。)
相关并且可能重复:
- Why is the address of static variables relative to the Instruction Pointer?
- Why does this MOVSS instruction use RIP-relative addressing?
在 32 位 x86 中,有 2 种冗余方式来编码无寄存器寻址模式和 disp32
绝对地址。
(有和没有 SIB 字节)。 x86-64 将较短的一个重新用作 RIP+rel32
,因此 mov foo, %eax
比 mov foo(%rip), %eax< 长 1 个字节
.
64 位绝对寻址将占用更多空间,并且仅适用于 mov
到/从 RAX/EAX/AX/AL 除非您使用单独的指令将地址放入寄存器首先。
(在 x86-64 Linux PIE/PIC 中,允许 64 位绝对寻址,并通过加载时修正处理,将正确的地址放入代码或跳转表或静态初始化的函数指针中。所以代码不会技术上必须与位置无关,但通常情况下这样做效率更高。并且不允许使用 32 位绝对寻址,因为 ASLR 不限于虚拟地址空间的低 31 位.)
请注意,在非 PIE Linux 可执行文件中,gcc 将使用 32 位绝对寻址 将静态数据的地址放入寄存器中。例如puts("hello");
通常编译为
mov $.LC0, %edi # mov r32, imm32
call puts
在默认的非 PIE 内存模型中,静态代码和数据链接到虚拟地址空间的低 32 位,因此 32 位绝对地址可以工作,无论它们是零扩展还是符号扩展到 64 位。这对于索引静态数组也很方便,比如mov array(%rax), %edx
; 例如添加 $4, %eax
。
参见 32-bit absolute addresses no longer allowed in x86-64 Linux?有关 PIE 可执行文件的更多信息,它对所有内容都使用与位置无关的代码,包括 RIP 相关的 LEA,如 7 字节 lea .LC0(%rip), %rdi
而不是 5 字节 mov $.LC0, %edi
.参见 How to load address of function or label into register
我提到 Linux 是因为它从 .cfi
指令看起来就像是为非 Windows 平台编译。
关于c - 为什么 x86-64 中的全局变量是相对于指令指针访问的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56262889/