[英]How to make gcc or clang use 64-bit/32-bit division instead of 128-bit/64-bit division when the dividend is 64-bit and the quotient is 32-bit?
[英]How can gcc/clang assume a string constant's address is 32-bit?
如果我編譯這個程序:
#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輸出/編譯選項 。)
我的問題是:GCC如何知道字符串的地址可以適合32位立即數操作數? 為什么不需要使用movabs $.LC0, %rdi
(即mov r64, imm64
,不是零或符號擴展的imm32
)。
AFAIK,沒有任何跡象表明加載器必須決定在任何特定地址加載數據部分。 如果字符串存儲在1ULL << 32
以上的某個地址,那么movl將忽略更高的位。 我對clang有類似的行為,所以我不認為這是GCC獨有的。
我關心的原因是我想創建自己的數據段,它存在於我選擇的任意地址(可能超過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 =大
為大型模型生成代碼:此模型不會對部分的地址和大小做出任何假設。
https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
3.18.1 AArch64選項
-mcmodel =微小
生成微小代碼模型的代碼。 程序及其靜態定義的符號必須在1GB之內。 指針是64位。 程序可以靜態或動態鏈接。 這個模型沒有完全實現,大多被視為“小”。
-mcmodel =小
為小代碼模型生成代碼。 程序及其靜態定義的符號必須在4GB之內。 指針是64位。 程序可以靜態或動態鏈接。 這是 默認代碼模型 。
-mcmodel =大
為大型代碼模型生成代碼。 這不會對部分的地址和大小做出任何假設。 指針是64位。 程序只能靜態鏈接。
我可以確認這是在64位編譯時發生的:
gcc -O1 foo.c
然后objdump -d a.out
(另請注意printf("%s\\n")
可以優化為puts
! ):
0000000000400536 <main>:
400536: 48 83 ec 08 sub $0x8,%rsp
40053a: bf d4 05 40 00 mov $0x4005d4,%edi
40053f: e8 cc fe ff ff callq 400410 <puts@plt>
400544: b8 00 00 00 00 mov $0x0,%eax
400549: 48 83 c4 08 add $0x8,%rsp
40054d: c3 retq
40054e: 66 90 xchg %ax,%ax
原因是GCC默認為-mcmodel=small
,其中靜態數據鏈接在地址空間的底部2G中。
請注意,字符串常量不會轉到數據段,但它們會在代碼段內,除非-fwritable-strings
。 此外,如果您想在內存中自由重定位目標代碼,您可能希望使用-fpic
進行編譯以使代碼RIP相對而不是在任何地方放置64位地址。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.