-ffreestanding 和 -nostdlib 在使用 gcc 编译时的区别

huangapple go评论129阅读模式
英文:

Difference between -ffreestanding and -nostdlib when compiling with gcc

问题

我使用一个64位的Linux机器,使用x84-elf64-gcc编译器。我刚开始进行低级编程,想要理解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"选项进行交叉编译32位版本并使用objdump时,得到:

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

我之前读到过这与位置无关代码(position independent code)有关:https://stackoverflow.com/questions/59070109/undefined-reference-to-global-offset-table-in-gcc-32-bit-code-for-a-trivial

为什么使用"-m32"选项编译时会发生这样的变化?
此外,有人建议我在编译时使用"-ffreestanding"选项,但似乎没有产生效果。我了解"-ffreestanding"告诉编译器没有标准库,那么"-nostdlib"是什么意思?

注意:我对这种“硬核”C编程相对新手,我认为主要问题是我不太了解链接器/编译器的工作原理。 -ffreestanding 和 -nostdlib 在使用 gcc 编译时的区别

英文:

I am using a 64 bit linux machine with a x84-elf64-gcc compiler. I have just started low level programming and would like to understand how C code is actually translated into binary. This is mainly for Operating Systems developement, as I know that a processor doesn't understand ELF, or any other format, and only understands binary.

For example, the following c file:

//test.c
int func()
{
    return 0x12345678;
}

When I compile with gcc:

gcc test.c

I get the following error:

(.text+0x20): undefined reference to `main&#39;
collect2: error: ld returned 1 exit status

So I'm guessing that there is an issue with the linker.
I do:

gcc test.c -c 

I get an ELF object file, and I do an objdump and get the expected:

0000000000000000 &lt;func&gt;:
   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   

But when I "cross compile" a 32 bit version using the -m32 option and objdump, I get:

hello.o:     file format elf32-i386


Disassembly of section .text:

00000000 &lt;func&gt;:
   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	e8 fc ff ff ff       	call   4 &lt;func+0x4&gt;
   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 &lt;__x86.get_pc_thunk.ax&gt;:
   0:	8b 04 24             	mov    (%esp),%eax
   3:	c3                   	ret    

I've read in a previous answer that this has to do with position independent code: https://stackoverflow.com/questions/59070109/undefined-reference-to-global-offset-table-in-gcc-32-bit-code-for-a-trivial

Why is there such a change when you compile with the -m32 option?
Moreover, I was advised to use the -ffreestanding option when I compile, but it doesn't seem to have an effect here. I've read that -ffreestanding tells the compiler that there is no standard library, so what is -nostdlib then?

Note: I'm relatively new to this hardcore c programming, and I think that the main issue here is that I don't really understand how linkers/compilers work. -ffreestanding 和 -nostdlib 在使用 gcc 编译时的区别

答案1

得分: 4

以下是翻译好的内容:

  • -freestanding 指示编译器应该是一个独立运行的编译器,据我所知,其唯一作用是禁用一些内置函数,比如_memcpy_;

  • -nostdlib 表示默认情况下不应链接任何库和启动文件。

英文:

The options control two parts of the process:

  • -freestanding indicates to the compiler that it should be a freestanding one, AFAIK the only effect is disabling some built-in functions like memcpy;

  • -nostdlib indicates that no libraries and no start up files should be linked by default.

答案2

得分: 2

I don't know what -ffreestanding does exactly, that part is a good question.

但很不幸,你的问题牵涉到了32位PIE代码:

为什么在使用-m32选项进行编译时会发生这种变化?

因为你没有加入任何-O优化选项,而32位模式没有EIP相对寻址数据的方式(只有相对跳转/调用)。因此,显然调试模式总是会设置一个寄存器作为GOT指针,作为寻址静态数据的基地址,即使在不使用它的函数中也是如此。

除非你明确希望创建一个PIE可执行文件,否则请始终使用-fno-pie来关闭该默认选项。

你可能还想使用-mcmodel=kernel - 如果你正在编译一个64位高半部内核(静态地址可以用作32位符号扩展立即数,但不能用作32位零扩展)。但我不知道它是否对32位代码有任何影响。

英文:

I don't know what -ffreestanding does exactly, that part is a good question.

But unfortunately your question has a big side-track into 32-bit PIE code:

> Why is there such a change when you compile with the -m32 option?

Because you left out any -O optimization option, and 32-bit mode doesn't have an EIP-relative addressing mode for data (only relative jumps/calls). So apparently debug-mode always sets up a register as a GOT pointer as a base for addressing static data, even in functions that don't use it.

Always use -fno-pie to turn off that default unless you specifically want to make a PIE executable.

You might also want -mcmodel=kernel - that's a good idea if you're compiling a 64-bit high-half kernel (static addresses can be used a 32-bit sign-extended immediates, but not 32-bit zero extended). But IDK if it does anything for 32-bit code.

huangapple
  • 本文由 发表于 2020年1月6日 20:36:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/59612257.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定