如何正确使用简单的链接描述文件?可执行文件在运行时收到 SIGKILL
我试图了解更深入的链接过程和链接器脚本...查看 binutils 文档,我发现了一个简单的链接器脚本实现,我通过添加一些命令对其进行了改进:
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(mymain)
SECTIONS
{
. = 0x10000;
.text : { *(.text) }
. = 0x8000000;
.data : { *(.data) }
.bss : { *(.bss) }
}
我的程序是一个非常简单的程序:
void mymain(void)
{
int a;
a++;
}
现在我尝试构建一个可执行文件:
gcc -c main.c
ld -o prog -T my_script.lds main.o
但是如果我尝试运行prog
,它会在启动期间收到SIGKILL
。我知道当一个程序被编译并与命令链接时:
gcc prog.c -o prog
最终的可执行文件也是其他目标文件的产物,例如 crt1.o
、crti.o
和 crtn.o
但我的情况呢?使用此链接描述文件的正确方法是什么?
I'm trying to understand deeper linking process and linker scripts...looking at binutils doc i found a simple linker script implementation that i've improved by adding some commands:
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(mymain)
SECTIONS
{
. = 0x10000;
.text : { *(.text) }
. = 0x8000000;
.data : { *(.data) }
.bss : { *(.bss) }
}
My program is a very simple program:
void mymain(void)
{
int a;
a++;
}
Now i tried to build an executable:
gcc -c main.c
ld -o prog -T my_script.lds main.o
But if i try to run prog
it receives a SIGKILL
during startup. I know that when a program is compiled and linked with the command:
gcc prog.c -o prog
the final executable is the product also of other object files like crt1.o
, crti.o
and crtn.o
but what about my case? Which is the correct way to use this linker scripts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我怀疑您的代码运行得很好,但最终遇到了麻烦:您希望在
a++
之后发生什么?mymain()
只是一个普通的 C 函数,它将尝试返回到其调用者。但是您已将其设置为 ELF 入口点,这会告诉 ELF 加载器在将程序段加载到正确位置后跳转到该入口点 - 并且它不期望您返回。
那些“其他目标文件,如
crt1.o
、crti.o
和crtn.o
”通常为 C 程序处理这些内容。 C 程序的 ELF 入口点不是main()
- 相反,它是一个包装器,为main()
设置适当的环境(例如设置 < code>argc 和argv
参数位于堆栈或寄存器中,具体取决于平台),调用main()
(期望它可能返回),然后调用exit
系统调用(带有main()
的返回码)。[更新以下评论:]
当我使用
gdb
尝试您的示例时,我发现它确实在从mymain()
返回时失败:在mymain
上设置断点,然后单步执行指令,我看到它执行了增量,然后在函数尾声中遇到了麻烦:至少对于 i386,ELF 加载器在之前设置了一个合理的堆栈输入加载的代码,这样你可以将 ELF 入口点设置为 C 函数并获得合理的行为;但是,正如我上面提到的,您必须自己处理干净的进程退出。如果您不使用 C 运行时,则最好也不要使用任何依赖于 C 运行时的库。
因此,这里是一个示例,使用原始链接描述文件 - 但修改了 C 代码以将
a
初始化为已知值,并调用exit
系统调用(使用内联汇编),最终值a
作为退出代码。 (注:我刚刚意识到您没有具体说明您正在使用什么平台;我在这里假设是 Linux。)I suspect that your code is running just fine, and getting into trouble at the end: what do you expect to happen after the
a++
?mymain()
is just an ordinary C function, which will try to return to its caller.But you've set it as the ELF entry point, which tells the ELF loader to jump to it once it has loaded the program segments in the right place - and it doesn't expect you to return.
Those "other object files like
crt1.o
,crti.o
andcrtn.o
" normally handle this stuff for C programs. The ELF entry point for a C program isn'tmain()
- instead, it's a wrapper which sets up an appropriate environment formain()
(e.g. setting up theargc
andargv
arguments on the stack or in registers, depending on platform), callsmain()
(with the expectation that it may return), and then invokes theexit
system call (with the return code frommain()
).[Update following comments:]
When I try your example with
gdb
, I see that it does indeed fail on returning frommymain()
: after setting a breakpoint onmymain
, and then stepping through instructions, I see that it performs the increment, then gets into trouble in the function epilogue:For i386 at least, the ELF loader sets up a sensible stack before entering the loaded code, so you can set the ELF entry point to a C function and get reasonable behaviour; however, as I mentioned above, you have to handle a clean process exit yourself. And if you're not using the C runtime, you'd better not be using any libraries that depend on the C runtime either.
So here is an example of that, using your original linker script - but with the C code modified to initialise
a
to a known value, and invoke anexit
system call (using inline assembly) with the final value ofa
as the exit code. (Note: I've just realised that you haven't said exactly what platform you're using; I'm assuming Linux here.)是的,要在 Linux 上运行,我们需要更改 .lds 文件
yes to run on linux, we need to change .lds file