Gcc 如何正确使用简单的链接器脚本?可执行文件在运行时得到SIGKILL

Gcc 如何正确使用简单的链接器脚本?可执行文件在运行时得到SIGKILL,gcc,linker,linker-scripts,Gcc,Linker,Linker Scripts,我试图了解更深入的链接过程和链接器脚本…查看binutils文档,我发现了一个简单的链接器脚本实现,我通过添加一些命令对其进行了改进: OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(mymain) SECTIONS { . = 0x10000; .text : { *(.text) } . = 0x8000000; .data : {

我试图了解更深入的链接过程和链接器脚本…查看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
,但我的情况如何?使用此链接器脚本的正确方法是什么?

我怀疑您的代码运行得很好,最后遇到了麻烦:在
a++
之后,您希望发生什么

mymain()
只是一个普通的C函数,它将尝试返回给它的调用者

但是您已经将它设置为ELF入口点,它告诉ELF加载程序在正确的位置加载程序段后跳转到它,并且它不希望您返回

那些“其他对象文件,如
crt1.o
crti.o
crtn.o
”通常为C程序处理这些内容。C程序的ELF入口点不是
main()
——相反,它是一个为
main()
设置适当环境的包装器(例如,在堆栈或寄存器上设置
argc
argv
参数,具体取决于平台),调用
main()
(期望它会返回),然后调用
exit
系统调用(使用
main()
中的返回代码)


[更新以下评论:]

当我使用
gdb
尝试您的示例时,我看到它确实在从
mymain()
返回时失败:在
mymain
上设置一个断点,然后逐步执行指令后,我看到它执行增量,然后在函数结尾处遇到问题:

$ gcc -g -c main.c
$ ld -o prog -T my_script.lds main.o
$ gdb ./prog
...
(gdb) b mymain
Breakpoint 1 at 0x10006: file main.c, line 4.
(gdb) r
Starting program: /tmp/prog 

Breakpoint 1, mymain () at main.c:4
4         a++;
(gdb) display/i $pc
1: x/i $pc
0x10006 <mymain+6>:     addl   $0x1,-0x4(%ebp)
(gdb) si
5       }
1: x/i $pc
0x1000a <mymain+10>:    leave  
(gdb) si
Cannot access memory at address 0x4
(gdb) si
0x00000001 in ?? ()
1: x/i $pc
Disabling display 1 to avoid infinite recursion.
0x1:    Cannot access memory at address 0x1
(gdb) q

是的,要在linux上运行,我们需要更改.lds文件

SECTIONS
{
   . = 0x8048000;
   .text : { *(.text) 
}

谢谢你,马修。我说程序在启动时崩溃是因为gdb这样说……我知道在调用
main
其他函数之前,我想是调用了CTOR。但是如果我想为
main
指定另一个名称,我应该在哪里指定?而且,如果我将我的程序显式地链接到
ld
,我还必须传递c运行时对象文件吗?你想实现什么?您想使用普通的C运行时和库吗?如果是这样,则必须调用main函数
main
:这就是C运行时调用的。(这与ELF入口点不同,它通常是
crt1.o
中的
\u start
)如果您直接调用
ld
,那么是的,您必须自己链接各种C运行时文件。如果您使用的是
gcc
,它会帮您完成这项工作。您可以看到它对
gcc-v
的作用,但您需要知道它通过包装器
collect2
(请参阅)调用
ld
。我知道是否有可能构建一个可执行文件(ELF格式),该文件在不链接到c运行时对象文件的情况下正确运行。是的,只要你能在没有C运行时代码为你做的事情的情况下生活。我已经用一个例子更新了我的答案。是的,我正在使用Linux…我不知道为什么,但如果我重现你的步骤(编译、链接和用gdb调试),gdb会说另一件事:
在启动过程中,程序以信号SIGKILL终止,终止。
所以我甚至不能开始调试。我使用的是
gcc4.4.5
SECTIONS
{
   . = 0x8048000;
   .text : { *(.text) 
}