我一直在阅读ELF规范,无法弄清楚程序入口点和_start地址的来源。
似乎他们应该在一个非常一致的地方,但我做了一些简单的程序,而_start总是在不同的地方。
任何人都可以澄清吗?
答案 0 :(得分:3)
_start
符号可以在任何目标文件中定义。通常它是自动生成的(它对应于C中的main
)。您可以自己生成它,例如在汇编源文件中生成:
.globl _start
_start:
// assembly here
当链接器处理完所有目标文件后,它会查找_start
符号并将其值放在elf header的e_entry
字段中。加载器从该字段获取地址,并在完成加载内存中的所有部分并准备执行该文件后调用它。
答案 1 :(得分:1)
查看链接器脚本ld
正在使用:
ld -verbose
格式记录在:https://sourceware.org/binutils/docs-2.25/ld/Scripts.html
它基本上确定了有关如何生成可执行文件的所有内容。
On Binutils 2.24 Ubuntu 14.04 64位,它包含以下行:
ENTRY(_start)
设置_start
符号的入口点(转到ctn提到的ELF头)
然后:
. = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
将第一个标头的地址设置为0x400000
+ SIZEOF_HEADERS
。
我已将该地址修改为0x800000
,并使用ld -T
传递了我的自定义脚本并且有效:readelf -s
表示_start
位于该地址。
另一种更改方法是使用-Ttext-segment=0x800000
选项。
使用0x400000
= 4Mb = getconf PAGE_SIZE
的原因是从第二页的开头开始,如下所示:Why is the ELF execution entry point virtual address of the form 0x80xxxxx and not zero 0x0?
问题描述了如何从命令行设置_start
:Why is the ELF entry point 0x8048000 not changeable with the "ld -e" option?
SIZEOF_HEADERS
是ELF +程序头的大小,它位于ELF文件的开头。这个数据被Linux加载到虚拟内存空间的最开头(TODO为什么?)在一个带有2个程序头的最小Linux x86-64 hello世界中它值0xb0
,所以_start
符号出现在0x4000b0。
答案 2 :(得分:0)
我不确定但请尝试此链接http://www.docstoc.com/docs/23942105/UNIX-ELF-File-Format 在第8页,它显示了入口点是否可执行的位置。基本上你需要计算偏移量,你就得到了它。 确保记住x86的小字节序(我猜你使用它)并重新排序,如果你阅读字节编辑:或者可能不是我不确定这是诚实的。