我正在阅读 ELF 格式规范,其中告诉了所有这些内容,包括 elf-headers、程序头、节、段等。所有这些都被引用为具有各种字段和值的结构。
那么问题是,这一切都去哪里了?我的意思是,我可以将它们视为结构,而不是readelf
util 的输出吗?
是否有任何中间文件,其中所有这些精灵魔法存在,合并到源代码中吗?或者它只是编译器的内部结构,并且在规范中仅针对人类提到了结构?)
对我来说,这看起来像是“先有鸡还是先有蛋的问题”(用代码来谈论编译后的代码)。
答案1
这些结构存在于 ELF 文件中。
我们看一下ELF头:
#define EI_NIDENT (16)
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
ELF 标头位于每一个ELF 文件。
这实际上意味着 ELF 文件的前 16 个字节是e_ident
ELF 标头中的字段:
第一个字节是0x7f;
第二个是
'E'
;第三个是
'L'
;第四个是
'F'
;第五是班级;
第六是数据编码;
第七个是文件版本;
八是操作系统ABI;
ETC。
该字段之后e_ident
,接下来的 2 个字节是e_type
.
如果是你head /bin/bash
,你将能够看到ELF
接近开始的地方。
现在,如果您获取 ELF 文件开头的十六进制转储:
$ xxd /bin/bash | xxd头 00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............ 00000010: 0200 3e00 0100 0000 7005 4200 0000 0000 ..>.....pB.... 00000020: 4000 0000 0000 0000 c0cd 0f00 0000 0000 @.............. 00000030: 0000 0000 4000 3800 0900 4000 1d00 1c00 [电子邮件受保护]...@..... 00000040: 0600 0000 0500 0000 4000 0000 0000 0000 ........@....... 00000050: 4000 4000 0000 0000 4000 4000 0000 0000 @.@.....@.@..... 00000060: f801 0000 0000 0000 f801 0000 0000 0000 ........ 00000070: 0800 0000 0000 0000 0300 0000 0400 0000 ................ 00000080: 3802 0000 0000 0000 3802 4000 0000 0000 8.......8.@..... 00000090: 3802 4000 0000 0000 1c00 0000 0000 0000 8.@........................
此十六进制转储的第一行是前 16 个字节 ( e_ident
):
第一个字节确实是
0x7f
;然后来了
"ELF"
;之后是(ELF64)
0x02
类;ELFCLASS64
然后是编码,
0x01
对于ELFDATA2LSB
;ETC。
第二行的前两个字节是e_type
.它们以 LSB 编码(因为ELFDATA2LSB
),因此该值实际上0x0002
意味着ET_EXEC
(这是一个可执行文件)。
接下来的两个字节是体系结构 ( e_machine
):0x003e
因为EM_X86_64
这是一个x86_64
可执行文件。
您应该能够手动解码 ELF 标头中的所有字段,并且您应该找到与 给出的值相同的值readelf
。由此,您可以在文件中找到其他 ELF 结构,例如ElfXX_Shdr
或ElfXX_Phdr
,并根据它们的定义对其进行解码(您应该找到与 给出的信息相同的信息readelf
)。
答案2
使用过xxd
和awk
$ xxd hello_arm64 | awk '{for(i=2;i<NF;i++){a=a$i;c++;if(c>9){print a;exit;}}}'
7f454c460201010000000000000000000200b700
$ cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64-static
flags: F
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff