函数和变量是否先于" _"使用gcc编译时?

时间:2016-07-08 18:06:03

标签: c gcc operating-system kernel

我正在使用GCC在Linux环境中学习OS开发。我在Bran的Kernel Development中了解到,编译时C中的所有函数和变量名都在其对应的汇编源文件中以" _"(下划线)开头。 但是当我浏览已编译的C程序的汇编源代码时,我甚至无法找到" _main"功能。 我执行了以下操作。

cpp sample.c sample.i

gcc -S sample.I

2 个答案:

答案 0 :(得分:6)

早期的情况确实如此。给定的C函数foo将在汇编程序中显示为_foo。这样做是为了避免与手工生成的.s文件发生冲突。

它也将被限制为总共8个字符[链接器限制]。

几十年来,情况并非如此。现在,符号不再以_为前缀,并且可能长于8个字符。

<强>更新

  

那么,现在GCC不会在函数和变量前面生成_?

在大多数情况下,没有。 IMO,你引用的参考,在这一点上,确实有点过时了。

大多数POSIX系统(例如linux,* BSD)使用gcc [或clang],他们不使用_

当我第一次开始用C编程[大约1981年]时,_仍然被使用。这是在AT&amp; T Unix v7,System III和System V上。

IIRC,它在20世纪90年代初期用于更新的系统(如linux)。就个人而言,从那以后我没有遇到_前缀,但我[大多]使用了linux [有时候是cygwin]。

一些AT&amp; T Unix衍生系统可能会保留它以实现向后兼容,但最终,大多数人都标准化了“foo is foo”。我无法访问OSX,所以我不能排除Johnathan对此的评论。

自从Unix早期(大约1970年)以来,_一直存在。这是在我的时间之前,但是,IIRC,Unix最初是用汇编语言编写的。它被转换为C. _用于划分用C语言编写的函数,或用于从C函数调用的函数。

那些没有前缀的是“仅限asm”[因为他们可能使用了非标准的调用约定]。回到白天,一切都很珍贵:RAM,CPU周期等等。

因此,asm函数可以/将使用“技巧”来节省资源。几个asm函数可以作为一个组工作,因为他们彼此了解。

如果可以从C调用给定的asm函数,_前缀符号是C兼容的“包装器”[在prolog / epilog中进行了额外的保存/恢复]。

  

那么,我可以将C程序的主要功能称为“call main”而不是“call _main”?

这是一个相当安全的赌注。

如果您从C调用给定的函数,它将自动执行正确的操作(即添加前缀或不添加前缀)。

只有在尝试从手动生成的汇编程序调用C函数时,问题可能才会出现。

所以,对于asm,我只是做了一件简单的事情并做call main。它适用于大多数[如果不是全部]系统。

如果你想“防弹”你的代码,你可以通过C预处理器(通过.S文件)运行你的asm并做(例如):

#ifdef C_USES_UNDERSCORE
#define CF(_x)          _##_x
#else
#define CF(_x)          _x
#endif

    call    CF(main)

但是,我觉得这太过分了。

它还说明了_前缀的整个问题。在具有大量内存和CPU周期的现代系统中,为什么汇编程序函数必须知道它调用的ABI兼容函数是从C还是手写汇编程序生成的?

答案 1 :(得分:1)

正如Craig所详述的那样,COFF和ELF等现代格式/ ABI不再遵循惯例。

在一些使用不同ABI的目标上,它仍在使用中。 示例是NeXT / OS X的Mach-O或16位和32位Windows。 64位Windows不再使用下划线(虽然GCC一直这样做,直到4.5.1为止)。

此外,下划线可能会显示为更大前缀的一部分。例如,__imp_符号中的__declspec(dllimport)或安腾ABI中的_Z

如果由于某种原因,需要影响重整,GCC会提供-f[no]leading-underscore标志。这将打破ABI兼容性。

一些链接: