linker - 为什么clang从声明为'extern“C”'的函数中删除下划线?
问题描述
我正在观看一段视频,试图更好地理解目标文件。演示者使用以下作为生成非常简单的目标文件的程序示例:
extern "C" void _start() {
asm("mov $60, %eax\n"
"mov $24567837, %edi\n"
"syscall\n");
}
该程序是通过编译
clang++ -c step0.cpp -O1 -o step0.o
并通过链接
ld -static step0.o -o step0
尝试链接时收到此错误消息:
Undefined symbols for architecture x86_64:
"start", referenced from:
-u command line option
(maybe you meant: __start)
ld: symbol(s) not found for inferred architecture x86_64
我没有通过 -u 命令行选项,所以我不确定为什么会收到该错误消息。
解决方案
clang 不是删除下划线,而是添加下划线。您的程序实际上是在导出一个__start
符号,但 ld 期望您有一个start
符号作为您的入口点,即 ld 在-u start
您的体系结构中默认运行。
您可以在 ld with -U start
(抑制未定义符号的错误)start
或 via -undefined suppress
(抑制所有未定义的符号错误)中禁用此检查。但是,您最终会得到一个没有架构入口点的可执行文件,因此该程序实际上无法工作。
我建议不要抑制错误,而是直接控制 clang 选择的符号。您可以使用独立asm
声明告诉 clang 要生成什么符号:
void _start() asm ("start");
确保此独立声明与函数定义分开。
您可以在此处阅读有关控制 gcc 生成的符号的更多信息:https ://stackoverflow.com/a/1035937/12928775
此外,正如在对类似答案的评论中指出的那样,您很可能希望__attribute__((naked))
在函数定义上使用以防止 clang 在入口时生成堆栈帧。请参阅:https ://stackoverflow.com/a/60311490/12928775