linux 运行elf64,Elf64 格式
ELF文件格式
ELF (Executable and Linkable Format)是一種為可執行文件,目標文件,共享鏈接庫和內核轉儲(core dumps)準備的標準文件格式。 Linux和很多類Unix操作系統都使用這個格式。 讓我們來看一下64位ELF文件格式的結構以及內核源碼中有關于它的一些定義。
一個ELF文件由以下三部分組成:
ELF頭(ELF header) - 描述文件的主要特性:類型,CPU架構,入口地址,現有部分的大小和偏移等等;
程序頭表(Program header table) - 列舉了所有有效的段(segments)和他們的屬性。 程序頭表需要加載器將文件中的節加載到虛擬內存段中;
節頭表(Section header table) - 包含對節(sections)的描述。
現在讓我們對這些部分有一些更深的了解。
ELF頭(ELF header)
ELF頭(ELF header)位于文件的開始位置。 它的主要目的是定位文件的其他部分。 文件頭主要包含以下字段:
ELF文件鑒定 - 一個字節數組用來確認文件是否是一個ELF文件,并且提供普通文件特征的信息;
文件類型 - 確定文件類型。 這個字段描述文件是一個重定位文件,或可執行文件,或...;
目標結構;
ELF文件格式的版本;
程序入口地址;
程序頭表的文件偏移;
節頭表的文件偏移;
ELF頭(ELF header)的大小;
程序頭表的表項大小;
其他字段...
你可以在內核源碼種找到表示ELF64 header的結構體 elf64_hdr:
typedef struct elf64_hdr {
unsigned chare_ident[EI_NIDENT];
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry;
Elf64_Off e_phoff;
Elf64_Off e_shoff;
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
這個結構體定義在 elf.h
節(sections)
所有的數據都存儲在ELF文件的節(sections)中。 我們通過節頭表中的索引(index)來確認節(sections)。 節頭表表項包含以下字段:
節的名字;
節的類型;
節的屬性;
內存地址;
文件中的偏移;
節的大小;
到其他節的鏈接;
各種各樣的信息;
地址對齊;
這個表項的大小,如果有的話;
而且,在linux內核中結構體 elf64_shdr 如下所示:
typedef struct elf64_shdr {
Elf64_Word sh_name;
Elf64_Word sh_type;
Elf64_Xword sh_flags;
Elf64_Addr sh_addr;
Elf64_Off sh_offset;
Elf64_Xword sh_size;
Elf64_Word sh_link;
Elf64_Word sh_info;
Elf64_Xword sh_addralign;
Elf64_Xword sh_entsize;
} Elf64_Shdr;
程序頭表(Program header table)
在可執行文件或者共享鏈接庫中所有的節(sections)都被分為多個段(segments)。 程序頭是一個結構的數組,每一個結構都表示一個段(segments)。 它的結構就像這樣:
typedef struct elf64_phdr {
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset;
Elf64_Addr p_vaddr;
Elf64_Addr p_paddr;
Elf64_Xword p_filesz;
Elf64_Xword p_memsz;
Elf64_Xword p_align;
} Elf64_Phdr;
在內核源碼中。
elf64_phdr 定義在相同的 elf.h 文件中.
EFL文件也包含其他的字段或結構。 你可以在 Documentation 中查看。 現在我們來查看一下 vmlinux 這個ELF文件。
vmlinux
vmlinux 也是一個可重定位的ELF文件。 我們可以使用 readelf 工具來查看它。 首先,讓我們看一下它的頭部:
$ readelf -h vmlinux
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1000000
Start of program headers: 64 (bytes into file)
Start of section headers: 381608416 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 5
Size of section headers: 64 (bytes)
Number of section headers: 73
Section header string table index: 70
我們可以看出 vmlinux 是一個64位可執行文件。 我們可以從 Documentation/x86/x86_64/mm.txt 讀到相關信息:
ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0
之后我們可以在 vmlinux ELF文件中查看這個地址:
$ readelf -s vmlinux | grep ffffffff81000000
1: ffffffff81000000 0 SECTION LOCAL DEFAULT 1
65099: ffffffff81000000 0 NOTYPE GLOBAL DEFAULT 1 _text
90766: ffffffff81000000 0 NOTYPE GLOBAL DEFAULT 1 startup_64
值得注意的是,startup_64 例程的地址不是 ffffffff80000000, 而是 ffffffff81000000。 現在我們來解釋一下。
. = __START_KERNEL;
...
...
..
/* Text and read-only data */
.text : AT(ADDR(.text) - LOAD_OFFSET) {
_text = .;
...
...
...
}
其中,__START_KERNEL 定義如下:
#define __START_KERNEL(__START_KERNEL_map + __PHYSICAL_START)
從這個文檔中看出,__START_KERNEL_map 的值是 ffffffff80000000 以及 __PHYSICAL_START 的值是 0x1000000。 這就是 startup_64的地址是 ffffffff81000000的原因了。
最后我們通過以下命令來得到程序頭表的內容:
readelf -l vmlinux
Elf file type is EXEC (Executable file)
Entry point 0x1000000
There are 5 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000200000 0xffffffff81000000 0x0000000001000000
0x0000000000cfd000 0x0000000000cfd000 R E 200000
LOAD 0x0000000001000000 0xffffffff81e00000 0x0000000001e00000
0x0000000000100000 0x0000000000100000 RW 200000
LOAD 0x0000000001200000 0x0000000000000000 0x0000000001f00000
0x0000000000014d98 0x0000000000014d98 RW 200000
LOAD 0x0000000001315000 0xffffffff81f15000 0x0000000001f15000
0x000000000011d000 0x0000000000279000 RWE 200000
NOTE 0x0000000000b17284 0xffffffff81917284 0x0000000001917284
0x0000000000000024 0x0000000000000024 4
Section to Segment mapping:
Segment Sections...
00 .text .notes __ex_table .rodata __bug_table .pci_fixup .builtin_fw
.tracedata __ksymtab __ksymtab_gpl __kcrctab __kcrctab_gpl
__ksymtab_strings __param __modver
01 .data .vvar
02 .data..percpu
03 .init.text .init.data .x86_cpu_dev.init .altinstructions
.altinstr_replacement .iommu_table .apicdrivers .exit.text
.smp_locks .data_nosave .bss .brk
這里我們可以看出五個包含節(sections)列表的段(segments)。 你可以在生成的鏈接器腳本 - arch/x86/kernel/vmlinux.lds 中找到所有的節(sections)。
就這樣吧。 當然,它不是ELF(Executable and Linkable Format)的完整描述,但是如果你想要知道更多,可以參考這個文檔 - 這里
總結
以上是生活随笔為你收集整理的linux 运行elf64,Elf64 格式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: English trip EM3 LP
- 下一篇: 阿龙的学习笔记---Linux GDB