我在项目中看过如下代码:
extern void my_main(void) __attribute__ ((__noreturn__, asection(".main","f=ax")));
这是做什么的?
项目中没有直接的main()
功能。以上代码是否向编译器表明my_main()
应被视为main()
?
此外,.main
内存部分指示了什么?
答案 0 :(得分:3)
上述声明基本上做的是声明一个名为extern
的{{1}}函数,不带参数。
my_main()
部分是GNU / LLVM attribute syntax。属性基本上是编译指示,用于描述相关函数的某些非标准或扩展特征 - 在本例中为__attribute__
。
my_main()
有两个属性。
__noreturn__
(搜索my_main()
)表示该功能永远不会返回。
这与返回noreturn
- void
- 类型函数不同,即使没有值,也会在某个时刻调用函数void
。这意味着执行将跳转/返回给调用者。
在return
(又名noreturn
或_noreturn
)函数中,这表明调用此函数不应该将返回地址添加到堆栈中,因为函数本身将在执行返回之前退出,或者将长期跳转到执行中的另一个点。
它还用于向堆栈添加返回地址会以干扰被调用函数的方式破坏堆栈的地方(尽管这种情况很少见,而且我只是因为这个原因而曾用过它)。
第二个属性__noreturn__
更加模糊。我似乎无法找到它的具体文档,但它似乎或多或少非常简单。
它似乎正在做的是指定linker section以及出现是unix filemode,指定生成的二进制文件是e x 虽然我可能是错的,但强大的>可执行的。
编写本机代码时,所有功能都放在目标二进制格式的相应部分(例如ELF,Mach-O,PE等)。最常见的部分是asection(".main","f=ax")
,.text
,和.rodata
。
但是,在调用GCC链接器.data
时,您可以指定linker script来指定完全您希望如何构建目标二进制文件。
这包括部分,大小,甚至是您要用来制作文件的目标文件,指定它们应该去的位置以及它们的大小限制。
一个常见的误解是你永远不会使用ld
。事实并非如此;如果您在没有ld
标记的情况下运行gcc
或g++
或clang
- 编译器系列,则会在使用default linker script时无意中调用-c
链接你的二进制文件。
链接器脚本对于必须根据内存规范构建ROM的嵌入式硬件非常重要。
回到您的代码行:它将ld
放入名为my_func()
的任意部分。这就是全部。最终,在项目的某个地方,有一个链接描述文件,用于指定.main
的使用方式和使用位置。
我想这个代码的目标是将.main
放在目标二进制文件/可执行文件中的完全地址,因此无论使用它还知道该函数的确切位置( my_main()
)并可以将其用作切入点(asection(".main")
)。