ELF 可执行文件:许多零字节
ELF executable file: many zero bytes
简介
我正在编译一个简单的汇编代码(Intel 语法,x86,Linux)打印“Hello World!”。这是:
SECTION .rodata
msg: db 'Hello world!', 0xA
msg_len: equ $ - msg
SECTION .text
global _start
_start:
mov eax, 4 ; `write` system call
mov ebx, 1 ; to stdout
mov ecx, msg
mov edx, msg_len
int 0x80
mov eax, 1 ; `exit` system call
xor ebx, ebx ; exit code 0
int 0x80
我用以下命令编译它:
nasm -f elf32 -o hello_world.o hello_world.s
ld -m elf_i386 -o hello_world hello_world.o
代码运行良好,但我担心的是文件大小:
-rwxrwxr-x 1 nikolay nikolay 8704 Apr 27 15:20 hello_world
-rw-rw-r-- 1 nikolay nikolay 243 Apr 26 22:16 hello_world.s
-rw-rw-r-- 1 nikolay nikolay 640 Apr 27 15:20 hello_world.o
问题
object文件比源代码稍微大一点,不过似乎也合理,因为ELF文件中应该有一些源代码没有的元数据什么的,对吧?但是可执行文件甚至比 object 文件大 10 倍以上!
此外,object 文件中有一些零字节,但我不会说它们太多了。但是,可执行文件中有很多零(请参阅 Additional info
部分中的两个屏幕截图)。
调查
我尝试阅读了一些关于 ELF 的文章,包括维基百科和手册页。我没有仔细阅读它们,所以我可能漏掉了一些东西,但我发现有用的是 dumpelf
实用程序(来自 pax-utils
包,可通过 apt
安装),使用它我转储了我的 elf 文件并发现了可能是这些零流的原因的东西:
在可执行文件的所有三个 headers 中,有 p_align
字段集:
.p_align = 4096 , /* (min mem alignment in bytes) */
这应该意味着每个部分都应该用零字节填充,以便其长度是 4096 的倍数。并且由于以下每个部分的大小都相对较小,因此有很多零字节被添加,这就是那些零的来源。
问题
所以,我想知道:
我说的对吗?添加这些零字节是否使这些部分足够长?
我还注意到前三个部分(''
、'.rodata'
、'.text'
)开始于 0
、4096
和 8192
,但下面的('.symtab'
、'.strtab'
、'.shstrtab'
)似乎不再对齐:它们从 8208
、8368
和 8422
... 为什么?这里发生了什么?
我们需要这个对齐有什么用?在编程headers中,有p_vaddr
和p_paddr
两个字段,设置为前三段开始的地址,那么如果我们已经知道 headers 部分的地址?它与内存页面(在我的机器上大小为 4KiB)有关吗?
我什么时候 want/need 以及如何更改对齐值?看起来应该有一个链接器参数来更改此值。我在 ld
的手册中找到了 --nmagic
参数,它完全禁用了对齐(万岁!可执行文件没有与 object 文件大小相同),但我猜对齐是故意存在的,所以也许我只需要降低值以使其更适合我的情况?
如果您知道我遗漏了什么,我将非常感谢您对这些问题中的任何一个或任何其他细节的回答。也请告诉我,如果我在任何地方都错了。提前致谢!
附加信息
我的 object 文件的转储(带有 xxd hello_world.o | grep -E '0000|$' --color=always | less -R
):
我的可执行文件转储的一部分(使用与上面类似的命令):
一个新的部分从地址 0x1000
开始
dumpelf hello_world.o
的输出:
#include <elf.h>
/*
* ELF dump of 'hello_world.o'
* 640 (0x280) bytes
*/
Elf32_Dyn dumpedelf_dyn_0[];
struct {
Elf32_Ehdr ehdr;
Elf32_Phdr phdrs[0];
Elf32_Shdr shdrs[7];
Elf32_Dyn *dyns;
} dumpedelf_0 = {
.ehdr = {
.e_ident = { /* (EI_NIDENT bytes) */
/* [0] EI_MAG: */ 0x7F,'E','L','F',
/* [4] EI_CLASS: */ 1 , /* (ELFCLASS32) */
/* [5] EI_DATA: */ 1 , /* (ELFDATA2LSB) */
/* [6] EI_VERSION: */ 1 , /* (EV_CURRENT) */
/* [7] EI_OSABI: */ 0 , /* (ELFOSABI_NONE) */
/* [8] EI_ABIVERSION: */ 0 ,
/* [9-15] EI_PAD: */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
},
.e_type = 1 , /* (ET_REL) */
.e_machine = 3 , /* (EM_386) */
.e_version = 1 , /* (EV_CURRENT) */
.e_entry = 0x0 , /* (start address at runtime) */
.e_phoff = 0 , /* (bytes into file) */
.e_shoff = 64 , /* (bytes into file) */
.e_flags = 0x0 ,
.e_ehsize = 52 , /* (bytes) */
.e_phentsize = 0 , /* (bytes) */
.e_phnum = 0 , /* (program headers) */
.e_shentsize = 40 , /* (bytes) */
.e_shnum = 7 , /* (section headers) */
.e_shstrndx = 3
},
.phdrs = {
/* no program headers ! */ },
.shdrs = {
/* Section Header #0 '' 0x40 */
{
.sh_name = 0 ,
.sh_type = 0 , /* [SHT_NULL] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 0 , /* (bytes) */
.sh_size = 0 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 0 ,
.sh_entsize = 0
},
/* Section Header #1 '.rodata' 0x68 */
{
.sh_name = 1 ,
.sh_type = 1 , /* [SHT_PROGBITS] */
.sh_flags = 2 ,
.sh_addr = 0x0 ,
.sh_offset = 352 , /* (bytes) */
.sh_size = 13 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 4 ,
.sh_entsize = 0
},
/* Section Header #2 '.text' 0x90 */
{
.sh_name = 9 ,
.sh_type = 1 , /* [SHT_PROGBITS] */
.sh_flags = 6 ,
.sh_addr = 0x0 ,
.sh_offset = 368 , /* (bytes) */
.sh_size = 31 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 16 ,
.sh_entsize = 0
},
/* Section Header #3 '.shstrtab' 0xB8 */
{
.sh_name = 15 ,
.sh_type = 3 , /* [SHT_STRTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 400 , /* (bytes) */
.sh_size = 51 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 1 ,
.sh_entsize = 0
},
/* Section Header #4 '.symtab' 0xE0 */
{
.sh_name = 25 ,
.sh_type = 2 , /* [SHT_SYMTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 464 , /* (bytes) */
.sh_size = 112 , /* (bytes) */
.sh_link = 5 ,
.sh_info = 6 ,
.sh_addralign = 4 ,
.sh_entsize = 16
},
/* Section Header #5 '.strtab' 0x108 */
{
.sh_name = 33 ,
.sh_type = 3 , /* [SHT_STRTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 576 , /* (bytes) */
.sh_size = 37 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 1 ,
.sh_entsize = 0
},
/* Section Header #6 '.rel.text' 0x130 */
{
.sh_name = 41 ,
.sh_type = 9 , /* [SHT_REL] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 624 , /* (bytes) */
.sh_size = 8 , /* (bytes) */
.sh_link = 4 ,
.sh_info = 2 ,
.sh_addralign = 4 ,
.sh_entsize = 8
},
},
.dyns = dumpedelf_dyn_0,
};
Elf32_Dyn dumpedelf_dyn_0[] = {
/* no dynamic tags ! */ };
dumpelf hello_world
的输出:
#include <elf.h>
/*
* ELF dump of 'hello_world'
* 8704 (0x2200) bytes
*/
Elf32_Dyn dumpedelf_dyn_0[];
struct {
Elf32_Ehdr ehdr;
Elf32_Phdr phdrs[3];
Elf32_Shdr shdrs[6];
Elf32_Dyn *dyns;
} dumpedelf_0 = {
.ehdr = {
.e_ident = { /* (EI_NIDENT bytes) */
/* [0] EI_MAG: */ 0x7F,'E','L','F',
/* [4] EI_CLASS: */ 1 , /* (ELFCLASS32) */
/* [5] EI_DATA: */ 1 , /* (ELFDATA2LSB) */
/* [6] EI_VERSION: */ 1 , /* (EV_CURRENT) */
/* [7] EI_OSABI: */ 0 , /* (ELFOSABI_NONE) */
/* [8] EI_ABIVERSION: */ 0 ,
/* [9-15] EI_PAD: */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
},
.e_type = 2 , /* (ET_EXEC) */
.e_machine = 3 , /* (EM_386) */
.e_version = 1 , /* (EV_CURRENT) */
.e_entry = 0x8049000 , /* (start address at runtime) */
.e_phoff = 52 , /* (bytes into file) */
.e_shoff = 8464 , /* (bytes into file) */
.e_flags = 0x0 ,
.e_ehsize = 52 , /* (bytes) */
.e_phentsize = 32 , /* (bytes) */
.e_phnum = 3 , /* (program headers) */
.e_shentsize = 40 , /* (bytes) */
.e_shnum = 6 , /* (section headers) */
.e_shstrndx = 5
},
.phdrs = {
/* Program Header #0 0x34 */
{
.p_type = 1 , /* [PT_LOAD] */
.p_offset = 0 , /* (bytes into file) */
.p_vaddr = 0x8048000 , /* (virtual addr at runtime) */
.p_paddr = 0x8048000 , /* (physical addr at runtime) */
.p_filesz = 148 , /* (bytes in file) */
.p_memsz = 148 , /* (bytes in mem at runtime) */
.p_flags = 0x4 , /* PF_R */
.p_align = 4096 , /* (min mem alignment in bytes) */
},
/* Program Header #1 0x54 */
{
.p_type = 1 , /* [PT_LOAD] */
.p_offset = 4096 , /* (bytes into file) */
.p_vaddr = 0x8049000 , /* (virtual addr at runtime) */
.p_paddr = 0x8049000 , /* (physical addr at runtime) */
.p_filesz = 31 , /* (bytes in file) */
.p_memsz = 31 , /* (bytes in mem at runtime) */
.p_flags = 0x5 , /* PF_R | PF_X */
.p_align = 4096 , /* (min mem alignment in bytes) */
},
/* Program Header #2 0x74 */
{
.p_type = 1 , /* [PT_LOAD] */
.p_offset = 8192 , /* (bytes into file) */
.p_vaddr = 0x804A000 , /* (virtual addr at runtime) */
.p_paddr = 0x804A000 , /* (physical addr at runtime) */
.p_filesz = 13 , /* (bytes in file) */
.p_memsz = 13 , /* (bytes in mem at runtime) */
.p_flags = 0x4 , /* PF_R */
.p_align = 4096 , /* (min mem alignment in bytes) */
},
},
.shdrs = {
/* Section Header #0 '' 0x2110 */
{
.sh_name = 0 ,
.sh_type = 0 , /* [SHT_NULL] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 0 , /* (bytes) */
.sh_size = 0 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 0 ,
.sh_entsize = 0
},
/* Section Header #1 '.text' 0x2138 */
{
.sh_name = 27 ,
.sh_type = 1 , /* [SHT_PROGBITS] */
.sh_flags = 6 ,
.sh_addr = 0x8049000 ,
.sh_offset = 4096 , /* (bytes) */
.sh_size = 31 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 16 ,
.sh_entsize = 0
},
/* Section Header #2 '.rodata' 0x2160 */
{
.sh_name = 33 ,
.sh_type = 1 , /* [SHT_PROGBITS] */
.sh_flags = 2 ,
.sh_addr = 0x804A000 ,
.sh_offset = 8192 , /* (bytes) */
.sh_size = 13 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 4 ,
.sh_entsize = 0
},
/* Section Header #3 '.symtab' 0x2188 */
{
.sh_name = 1 ,
.sh_type = 2 , /* [SHT_SYMTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 8208 , /* (bytes) */
.sh_size = 160 , /* (bytes) */
.sh_link = 4 ,
.sh_info = 6 ,
.sh_addralign = 4 ,
.sh_entsize = 16
},
/* Section Header #4 '.strtab' 0x21B0 */
{
.sh_name = 9 ,
.sh_type = 3 , /* [SHT_STRTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 8368 , /* (bytes) */
.sh_size = 54 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 1 ,
.sh_entsize = 0
},
/* Section Header #5 '.shstrtab' 0x21D8 */
{
.sh_name = 17 ,
.sh_type = 3 , /* [SHT_STRTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 8422 , /* (bytes) */
.sh_size = 41 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 1 ,
.sh_entsize = 0
},
},
.dyns = dumpedelf_dyn_0,
};
Elf32_Dyn dumpedelf_dyn_0[] = {
/* no dynamic tags ! */ };
对齐为 4096 字节,这是此体系结构上的页面大小。这不是巧合,正如 man page 关于 nmagic 所说:“关闭部分的页面对齐”。
通过正常(非 nmagic)二进制文件的大小,您可以猜测链接器布局了三个页面,大概具有不同的访问权限(代码 = 不可写,数据 = 不可执行,rodata = 只读),这些权限只能每页设置。 运行ning 时磁盘布局与 RAM 中的布局匹配。
这对于按需分页很重要。当程序启动时,整个可执行文件基本上是映射的,页面根据需要通过页面错误从磁盘加载。页面也可以在其其他 运行ning 实例之间共享(这对动态库来说更重要),并且可以在需要时由于内存压力而从 RAM 中逐出。
当 运行 时,nmagic 可执行文件仍被加载到三个页面中,但由于它们不再与磁盘上的内容匹配,因此不会按需分页。我不建议在任何更大的东西上使用该选项。
注意:如果您创建一个更长的 运行ning 可执行文件(可能添加输入读取),您可以通过查看 /proc/ 检查 运行ning 进程的内存布局细节[pid]/地图和地图。
简介
我正在编译一个简单的汇编代码(Intel 语法,x86,Linux)打印“Hello World!”。这是:
SECTION .rodata
msg: db 'Hello world!', 0xA
msg_len: equ $ - msg
SECTION .text
global _start
_start:
mov eax, 4 ; `write` system call
mov ebx, 1 ; to stdout
mov ecx, msg
mov edx, msg_len
int 0x80
mov eax, 1 ; `exit` system call
xor ebx, ebx ; exit code 0
int 0x80
我用以下命令编译它:
nasm -f elf32 -o hello_world.o hello_world.s
ld -m elf_i386 -o hello_world hello_world.o
代码运行良好,但我担心的是文件大小:
-rwxrwxr-x 1 nikolay nikolay 8704 Apr 27 15:20 hello_world
-rw-rw-r-- 1 nikolay nikolay 243 Apr 26 22:16 hello_world.s
-rw-rw-r-- 1 nikolay nikolay 640 Apr 27 15:20 hello_world.o
问题
object文件比源代码稍微大一点,不过似乎也合理,因为ELF文件中应该有一些源代码没有的元数据什么的,对吧?但是可执行文件甚至比 object 文件大 10 倍以上!
此外,object 文件中有一些零字节,但我不会说它们太多了。但是,可执行文件中有很多零(请参阅 Additional info
部分中的两个屏幕截图)。
调查
我尝试阅读了一些关于 ELF 的文章,包括维基百科和手册页。我没有仔细阅读它们,所以我可能漏掉了一些东西,但我发现有用的是 dumpelf
实用程序(来自 pax-utils
包,可通过 apt
安装),使用它我转储了我的 elf 文件并发现了可能是这些零流的原因的东西:
在可执行文件的所有三个 headers 中,有 p_align
字段集:
.p_align = 4096 , /* (min mem alignment in bytes) */
这应该意味着每个部分都应该用零字节填充,以便其长度是 4096 的倍数。并且由于以下每个部分的大小都相对较小,因此有很多零字节被添加,这就是那些零的来源。
问题
所以,我想知道:
我说的对吗?添加这些零字节是否使这些部分足够长?
我还注意到前三个部分(
''
、'.rodata'
、'.text'
)开始于0
、4096
和8192
,但下面的('.symtab'
、'.strtab'
、'.shstrtab'
)似乎不再对齐:它们从8208
、8368
和8422
... 为什么?这里发生了什么?我们需要这个对齐有什么用?在编程headers中,有
p_vaddr
和p_paddr
两个字段,设置为前三段开始的地址,那么如果我们已经知道 headers 部分的地址?它与内存页面(在我的机器上大小为 4KiB)有关吗?我什么时候 want/need 以及如何更改对齐值?看起来应该有一个链接器参数来更改此值。我在
ld
的手册中找到了--nmagic
参数,它完全禁用了对齐(万岁!可执行文件没有与 object 文件大小相同),但我猜对齐是故意存在的,所以也许我只需要降低值以使其更适合我的情况?
如果您知道我遗漏了什么,我将非常感谢您对这些问题中的任何一个或任何其他细节的回答。也请告诉我,如果我在任何地方都错了。提前致谢!
附加信息
我的 object 文件的转储(带有 xxd hello_world.o | grep -E '0000|$' --color=always | less -R
):
我的可执行文件转储的一部分(使用与上面类似的命令): 一个新的部分从地址 0x1000
开始dumpelf hello_world.o
的输出:
#include <elf.h>
/*
* ELF dump of 'hello_world.o'
* 640 (0x280) bytes
*/
Elf32_Dyn dumpedelf_dyn_0[];
struct {
Elf32_Ehdr ehdr;
Elf32_Phdr phdrs[0];
Elf32_Shdr shdrs[7];
Elf32_Dyn *dyns;
} dumpedelf_0 = {
.ehdr = {
.e_ident = { /* (EI_NIDENT bytes) */
/* [0] EI_MAG: */ 0x7F,'E','L','F',
/* [4] EI_CLASS: */ 1 , /* (ELFCLASS32) */
/* [5] EI_DATA: */ 1 , /* (ELFDATA2LSB) */
/* [6] EI_VERSION: */ 1 , /* (EV_CURRENT) */
/* [7] EI_OSABI: */ 0 , /* (ELFOSABI_NONE) */
/* [8] EI_ABIVERSION: */ 0 ,
/* [9-15] EI_PAD: */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
},
.e_type = 1 , /* (ET_REL) */
.e_machine = 3 , /* (EM_386) */
.e_version = 1 , /* (EV_CURRENT) */
.e_entry = 0x0 , /* (start address at runtime) */
.e_phoff = 0 , /* (bytes into file) */
.e_shoff = 64 , /* (bytes into file) */
.e_flags = 0x0 ,
.e_ehsize = 52 , /* (bytes) */
.e_phentsize = 0 , /* (bytes) */
.e_phnum = 0 , /* (program headers) */
.e_shentsize = 40 , /* (bytes) */
.e_shnum = 7 , /* (section headers) */
.e_shstrndx = 3
},
.phdrs = {
/* no program headers ! */ },
.shdrs = {
/* Section Header #0 '' 0x40 */
{
.sh_name = 0 ,
.sh_type = 0 , /* [SHT_NULL] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 0 , /* (bytes) */
.sh_size = 0 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 0 ,
.sh_entsize = 0
},
/* Section Header #1 '.rodata' 0x68 */
{
.sh_name = 1 ,
.sh_type = 1 , /* [SHT_PROGBITS] */
.sh_flags = 2 ,
.sh_addr = 0x0 ,
.sh_offset = 352 , /* (bytes) */
.sh_size = 13 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 4 ,
.sh_entsize = 0
},
/* Section Header #2 '.text' 0x90 */
{
.sh_name = 9 ,
.sh_type = 1 , /* [SHT_PROGBITS] */
.sh_flags = 6 ,
.sh_addr = 0x0 ,
.sh_offset = 368 , /* (bytes) */
.sh_size = 31 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 16 ,
.sh_entsize = 0
},
/* Section Header #3 '.shstrtab' 0xB8 */
{
.sh_name = 15 ,
.sh_type = 3 , /* [SHT_STRTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 400 , /* (bytes) */
.sh_size = 51 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 1 ,
.sh_entsize = 0
},
/* Section Header #4 '.symtab' 0xE0 */
{
.sh_name = 25 ,
.sh_type = 2 , /* [SHT_SYMTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 464 , /* (bytes) */
.sh_size = 112 , /* (bytes) */
.sh_link = 5 ,
.sh_info = 6 ,
.sh_addralign = 4 ,
.sh_entsize = 16
},
/* Section Header #5 '.strtab' 0x108 */
{
.sh_name = 33 ,
.sh_type = 3 , /* [SHT_STRTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 576 , /* (bytes) */
.sh_size = 37 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 1 ,
.sh_entsize = 0
},
/* Section Header #6 '.rel.text' 0x130 */
{
.sh_name = 41 ,
.sh_type = 9 , /* [SHT_REL] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 624 , /* (bytes) */
.sh_size = 8 , /* (bytes) */
.sh_link = 4 ,
.sh_info = 2 ,
.sh_addralign = 4 ,
.sh_entsize = 8
},
},
.dyns = dumpedelf_dyn_0,
};
Elf32_Dyn dumpedelf_dyn_0[] = {
/* no dynamic tags ! */ };
dumpelf hello_world
的输出:
#include <elf.h>
/*
* ELF dump of 'hello_world'
* 8704 (0x2200) bytes
*/
Elf32_Dyn dumpedelf_dyn_0[];
struct {
Elf32_Ehdr ehdr;
Elf32_Phdr phdrs[3];
Elf32_Shdr shdrs[6];
Elf32_Dyn *dyns;
} dumpedelf_0 = {
.ehdr = {
.e_ident = { /* (EI_NIDENT bytes) */
/* [0] EI_MAG: */ 0x7F,'E','L','F',
/* [4] EI_CLASS: */ 1 , /* (ELFCLASS32) */
/* [5] EI_DATA: */ 1 , /* (ELFDATA2LSB) */
/* [6] EI_VERSION: */ 1 , /* (EV_CURRENT) */
/* [7] EI_OSABI: */ 0 , /* (ELFOSABI_NONE) */
/* [8] EI_ABIVERSION: */ 0 ,
/* [9-15] EI_PAD: */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
},
.e_type = 2 , /* (ET_EXEC) */
.e_machine = 3 , /* (EM_386) */
.e_version = 1 , /* (EV_CURRENT) */
.e_entry = 0x8049000 , /* (start address at runtime) */
.e_phoff = 52 , /* (bytes into file) */
.e_shoff = 8464 , /* (bytes into file) */
.e_flags = 0x0 ,
.e_ehsize = 52 , /* (bytes) */
.e_phentsize = 32 , /* (bytes) */
.e_phnum = 3 , /* (program headers) */
.e_shentsize = 40 , /* (bytes) */
.e_shnum = 6 , /* (section headers) */
.e_shstrndx = 5
},
.phdrs = {
/* Program Header #0 0x34 */
{
.p_type = 1 , /* [PT_LOAD] */
.p_offset = 0 , /* (bytes into file) */
.p_vaddr = 0x8048000 , /* (virtual addr at runtime) */
.p_paddr = 0x8048000 , /* (physical addr at runtime) */
.p_filesz = 148 , /* (bytes in file) */
.p_memsz = 148 , /* (bytes in mem at runtime) */
.p_flags = 0x4 , /* PF_R */
.p_align = 4096 , /* (min mem alignment in bytes) */
},
/* Program Header #1 0x54 */
{
.p_type = 1 , /* [PT_LOAD] */
.p_offset = 4096 , /* (bytes into file) */
.p_vaddr = 0x8049000 , /* (virtual addr at runtime) */
.p_paddr = 0x8049000 , /* (physical addr at runtime) */
.p_filesz = 31 , /* (bytes in file) */
.p_memsz = 31 , /* (bytes in mem at runtime) */
.p_flags = 0x5 , /* PF_R | PF_X */
.p_align = 4096 , /* (min mem alignment in bytes) */
},
/* Program Header #2 0x74 */
{
.p_type = 1 , /* [PT_LOAD] */
.p_offset = 8192 , /* (bytes into file) */
.p_vaddr = 0x804A000 , /* (virtual addr at runtime) */
.p_paddr = 0x804A000 , /* (physical addr at runtime) */
.p_filesz = 13 , /* (bytes in file) */
.p_memsz = 13 , /* (bytes in mem at runtime) */
.p_flags = 0x4 , /* PF_R */
.p_align = 4096 , /* (min mem alignment in bytes) */
},
},
.shdrs = {
/* Section Header #0 '' 0x2110 */
{
.sh_name = 0 ,
.sh_type = 0 , /* [SHT_NULL] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 0 , /* (bytes) */
.sh_size = 0 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 0 ,
.sh_entsize = 0
},
/* Section Header #1 '.text' 0x2138 */
{
.sh_name = 27 ,
.sh_type = 1 , /* [SHT_PROGBITS] */
.sh_flags = 6 ,
.sh_addr = 0x8049000 ,
.sh_offset = 4096 , /* (bytes) */
.sh_size = 31 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 16 ,
.sh_entsize = 0
},
/* Section Header #2 '.rodata' 0x2160 */
{
.sh_name = 33 ,
.sh_type = 1 , /* [SHT_PROGBITS] */
.sh_flags = 2 ,
.sh_addr = 0x804A000 ,
.sh_offset = 8192 , /* (bytes) */
.sh_size = 13 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 4 ,
.sh_entsize = 0
},
/* Section Header #3 '.symtab' 0x2188 */
{
.sh_name = 1 ,
.sh_type = 2 , /* [SHT_SYMTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 8208 , /* (bytes) */
.sh_size = 160 , /* (bytes) */
.sh_link = 4 ,
.sh_info = 6 ,
.sh_addralign = 4 ,
.sh_entsize = 16
},
/* Section Header #4 '.strtab' 0x21B0 */
{
.sh_name = 9 ,
.sh_type = 3 , /* [SHT_STRTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 8368 , /* (bytes) */
.sh_size = 54 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 1 ,
.sh_entsize = 0
},
/* Section Header #5 '.shstrtab' 0x21D8 */
{
.sh_name = 17 ,
.sh_type = 3 , /* [SHT_STRTAB] */
.sh_flags = 0 ,
.sh_addr = 0x0 ,
.sh_offset = 8422 , /* (bytes) */
.sh_size = 41 , /* (bytes) */
.sh_link = 0 ,
.sh_info = 0 ,
.sh_addralign = 1 ,
.sh_entsize = 0
},
},
.dyns = dumpedelf_dyn_0,
};
Elf32_Dyn dumpedelf_dyn_0[] = {
/* no dynamic tags ! */ };
对齐为 4096 字节,这是此体系结构上的页面大小。这不是巧合,正如 man page 关于 nmagic 所说:“关闭部分的页面对齐”。
通过正常(非 nmagic)二进制文件的大小,您可以猜测链接器布局了三个页面,大概具有不同的访问权限(代码 = 不可写,数据 = 不可执行,rodata = 只读),这些权限只能每页设置。 运行ning 时磁盘布局与 RAM 中的布局匹配。
这对于按需分页很重要。当程序启动时,整个可执行文件基本上是映射的,页面根据需要通过页面错误从磁盘加载。页面也可以在其其他 运行ning 实例之间共享(这对动态库来说更重要),并且可以在需要时由于内存压力而从 RAM 中逐出。
当 运行 时,nmagic 可执行文件仍被加载到三个页面中,但由于它们不再与磁盘上的内容匹配,因此不会按需分页。我不建议在任何更大的东西上使用该选项。
注意:如果您创建一个更长的 运行ning 可执行文件(可能添加输入读取),您可以通过查看 /proc/ 检查 运行ning 进程的内存布局细节[pid]/地图和地图。