如果我编译此程序:
#include <stdio.h> int main(int argc, char** argv) { printf("hello world!\n"); return 0; }
对于x86-64,asm输出使用movl $.LC0, %edi/ call puts。(请参阅Godbolt上的完整asm输出/编译选项。)
movl $.LC0, %edi
call puts
我的问题是:GCC如何知道字符串的地址可以放入32位立即数中?为什么不需要使用它movabs $.LC0, %rdi(即mov r64, imm64,而不是零或符号扩展的imm32)。
movabs $.LC0, %rdi
mov r64, imm64
imm32
AFAIK,没有什么说加载程序必须决定将数据段加载到任何特定地址的。如果该字符串存储在上方的某个地址,1ULL << 32那么movl将忽略较高的位。我在clang中得到类似的行为,所以我认为这并不是GCC独有的。
1ULL << 32
我关心的原因是我想创建自己的数据段,该段存储在内存中的任意位置(可能大于2 ^ 32)。
在GCC手册中:
https://gcc.gnu.org/onlinedocs/gcc-4.5.3/gcc/i386-and-x86_002d64-Options.html
3.17.15 Intel 386和AMD x86-64选项
-mcmodel =小 为小型代码模型生成代码:程序及其符号必须在地址空间的低2 GB中链接。指针是64位。程序可以静态或动态链接。 这是 默认的代码模型。 -mcmodel = kernel为内核代码模型生成代码。内核在负2 GB的地址空间中运行。该模型必须用于Linux内核代码。 -mcmodel =中 生成用于中型模型的代码:程序链接在地址空间的低2 GB中。小符号也放置在此处。大小大于-mlarge-data- threshold的符号将放入大数据或bss节中,并且可以位于2GB以上。程序可以静态或动态链接。 -mcmodel =大 生成大型模型的代码:该模型不对节的地址和大小做任何假设。
-mcmodel =小
为小型代码模型生成代码:程序及其符号必须在地址空间的低2 GB中链接。指针是64位。程序可以静态或动态链接。 这是 默认的代码模型。
-mcmodel = kernel为内核代码模型生成代码。内核在负2 GB的地址空间中运行。该模型必须用于Linux内核代码。
-mcmodel =中
生成用于中型模型的代码:程序链接在地址空间的低2 GB中。小符号也放置在此处。大小大于-mlarge-data- threshold的符号将放入大数据或bss节中,并且可以位于2GB以上。程序可以静态或动态链接。
-mcmodel =大
生成大型模型的代码:该模型不对节的地址和大小做任何假设。
https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
3.18.1 AArch64选项
-mcmodel =小 为小代码模型生成代码。该程序及其静态定义的符号之间的距离必须在1GB之内。指针是64位。程序可以静态或动态链接。该模型尚未完全实施,通常被视为“小型”模型。 -mcmodel =小 为小代码模型生成代码。该程序及其静态定义的符号之间的距离必须在4GB之内。指针是64位。程序可以静态或动态链接。 这是 默认的代码模型 。 -mcmodel =大 为大型代码模型生成代码。这不假定节的地址和大小。指针是64位。程序只能静态链接。
为小代码模型生成代码。该程序及其静态定义的符号之间的距离必须在1GB之内。指针是64位。程序可以静态或动态链接。该模型尚未完全实施,通常被视为“小型”模型。
为小代码模型生成代码。该程序及其静态定义的符号之间的距离必须在4GB之内。指针是64位。程序可以静态或动态链接。 这是 默认的代码模型 。
为大型代码模型生成代码。这不假定节的地址和大小。指针是64位。程序只能静态链接。