我正在Linux x86_64上使用ELF可执行文件和gnu工具链进行实验:
我已经链接并手动剥离了“ Hello World”测试。
.global _start .text _start: mov $1, %rax ...
转换为267字节的ELF64可执行文件…
0000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............ 0000010: 0200 3e00 0100 0000 d400 4000 0000 0000 ..>.......@..... 0000020: 4000 0000 0000 0000 0000 0000 0000 0000 @............... 0000030: 0000 0000 4000 3800 0100 4000 0000 0000 ....@.8...@..... 0000040: 0100 0000 0500 0000 0000 0000 0000 0000 ................ 0000050: 0000 4000 0000 0000 0000 4000 0000 0000 ..@.......@..... 0000060: 0b01 0000 0000 0000 0b01 0000 0000 0000 ................ 0000070: 0000 2000 0000 0000 0000 0000 0000 0000 .. ............. 0000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000b0: 0400 0000 1400 0000 0300 0000 474e 5500 ............GNU. 00000c0: c3b0 cbbd 0abf a73c 26ef e960 fc64 4026 .......<&..`.d@& 00000d0: e242 8bc7 48c7 c001 0000 0048 c7c7 0100 .B..H......H.... 00000e0: 0000 48c7 c6fe 0040 0048 c7c2 0d00 0000 ..H....@.H...... 00000f0: 0f05 48c7 c03c 0000 0048 31ff 0f05 4865 ..H..<...H1...He 0000100: 6c6c 6f2c 2057 6f72 6c64 0a llo, World.
它具有一个程序头(LOAD),并且没有节:
There are 1 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x000000000000010b 0x000000000000010b R E 200000
这似乎会在地址0x400000处加载整个文件(文件偏移量0到0x10b-elf报头)。
入口点是:
Entry point address: 0x4000d4
对应于文件中的0xd4偏移量,我们可以看到该地址是机器代码(mov $1, %rax1)的开头
mov $1, %rax1
我的问题是为什么gnu链接器选择地址(如何)0x400000将文件映射到?
0x400000
起始地址通常由链接描述文件设置。
例如,在GNU / Linux上,/usr/lib/ldscripts/elf_x86_64.x我们看到:
/usr/lib/ldscripts/elf_x86_64.x
... PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); \ . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
该值0x400000是SEGMENT_START()该平台上该功能的默认值。
SEGMENT_START()
您可以通过浏览链接器手册找到有关链接器脚本的更多信息:
% info ld Scripts