C 为什么编译器可以假设全局变量的地址适合32位?

C 为什么编译器可以假设全局变量的地址适合32位?,c,gcc,x86-64,C,Gcc,X86 64,当查看此简单函数的汇编程序(请参见上)时 extern int global; void doit(int *); void call_doit(){ doit(&global); } 32位值用于保存全局的地址: call_doit: movl $global, %edi jmp doit 我理解,在这里使用32位寄存器(即%edi)优于64位寄存器(即%rdi),因为可以保存2个字节(movl$global,%edi需要5个字

当查看此简单函数的汇编程序(请参见上)时

extern int global;
void doit(int *);
void call_doit(){
    doit(&global);
}
32位值用于保存
全局
的地址:

call_doit:
        movl    $global, %edi
        jmp     doit
我理解,在这里使用32位寄存器(即
%edi
)优于64位寄存器(即
%rdi
),因为可以保存2个字节(
movl$global,%edi
需要5个字节,而
movq$global,%rdi
需要7个字节+4个额外字节,如果不假设
$global
适合32位的话)

(编者按:编译器实际上使用7字节
leaglobal(%rip),%rdi
从rip+32位相对位移创建64位地址,编译器可以根据相关原因假设该地址在范围内。对于64位绝对地址,
movabs$global,%rdi
将是10字节,而不是11字节。)

但是为什么编译器可以假设全局变量的地址适合这32位呢?编译器有什么保证


对于局部变量,编译器使用64位寄存器保存堆栈地址,例如:

void doit(int *);
void call_doit(){
    int local=0;
    doit(&local);
}
结果(请参见上的):


有趣。C要求编译器能够在一个翻译单元中处理至少4095个不同的标识符,但没有提到链接整个程序。GNU链接器施加并依赖的全局标识符的数量是否有限制?@mhc这是因为尾部调用优化仅在第一种情况下可能(在第二种情况下,您必须调整%rsp)顺便说一句,如果您创建的程序具有超过4GB的全局变量,你做错事的概率不是零可能32位是.data和.bss段的限制。即使是Clang和ICC也会为全局情况生成32位移动。如果您更改为C++,您将有更多的编译器进行测试,而在这些ZAPCC和ELCC中,也会发出<代码> MOVL$Global,%EDI
call_doit:
        subq    $24, %rsp
        leaq    12(%rsp), %rdi
        movl    $0, 12(%rsp)
        call    doit
        addq    $24, %rsp
        ret