[英]Difference between -ffreestanding and -nostdlib when compiling with gcc
我正在使用帶有 x84-elf64-gcc 編譯器的 64 位 linux 機器。 我剛剛開始低級編程,想了解 C 代碼實際上是如何翻譯成二進制的。 這主要用於操作系統開發,因為我知道處理器不理解 ELF 或任何其他格式,只能理解二進制。
例如下面的c文件:
//test.c
int func()
{
return 0x12345678;
}
當我用 gcc 編譯時:
gcc test.c
我收到以下錯誤:
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
所以我猜鏈接器有問題。 我願意:
gcc test.c -c
我得到了一個 ELF 對象文件,然后我做了一個 objdump 並得到了預期的結果:
0000000000000000 <func>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 78 56 34 12 mov $0x12345678,%eax
9: 5d pop %rbp
a: c3 retq
但是當我使用-m32選項和 objdump “交叉編譯”一個 32 位版本時,我得到:
hello.o: file format elf32-i386
Disassembly of section .text:
00000000 <func>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: e8 fc ff ff ff call 4 <func+0x4>
8: 05 01 00 00 00 add $0x1,%eax
d: b8 78 56 34 12 mov $0x12345678,%eax
12: 5d pop %ebp
13: c3 ret
Disassembly of section .text.__x86.get_pc_thunk.ax:
00000000 <__x86.get_pc_thunk.ax>:
0: 8b 04 24 mov (%esp),%eax
3: c3 ret
我在之前的回答中讀到這與位置無關代碼有關: 未定義引用 gcc 32 位代碼中的“_GLOBAL_OFFSET_TABLE_”,用於一個微不足道的函數,獨立操作系統
為什么在使用 -m32 選項編譯時會有這樣的變化? 此外,我被建議在編譯時使用-ffreestanding選項,但它在這里似乎沒有效果。 我讀過-ffreestanding告訴編譯器沒有標准庫,那么 -nostdlib 是什么?
注意:我對這種硬核c 編程比較陌生,我認為這里的主要問題是我並不真正了解鏈接器/編譯器的工作原理。 :(
我不知道-ffreestanding
到底做了什么,那部分是個好問題。
但不幸的是,您的問題對 32 位 PIE 代碼有很大的影響:
為什么在使用 -m32 選項編譯時會有這樣的變化?
因為您遺漏了任何-O
優化選項,並且 32 位模式沒有數據的 EIP 相對尋址模式(只有相對跳轉/調用)。 因此,顯然調試模式總是將寄存器設置為 GOT 指針作為尋址靜態數據的基礎,即使在不使用它的函數中也是如此。
除非您特別想讓PIE 可執行,否則始終使用-fno-pie
關閉該默認值。
您可能還需要-mcmodel=kernel
- 如果您正在編譯 64 位高半內核,這是一個好主意(靜態地址可以用於 32 位符號擴展立即數,但不能用於 32 位零擴展)。 但是 IDK 如果它對 32 位代碼有任何作用的話。
這些選項控制流程的兩個部分:
-freestanding向編譯器表明它應該是一個獨立的,AFAIK 唯一的效果是禁用一些內置函數,如memcpy ;
-nostdlib表示默認情況下不應鏈接任何庫和啟動文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.