You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
8.4 KiB
Markdown
219 lines
8.4 KiB
Markdown
10 years ago
|
Executable and Linkable Format
|
||
|
================================================================================
|
||
|
|
||
9 years ago
|
ELF (Executable and Linkable Format) is a standard file format for executable files, object code, shared libraries and core dumps. Linux and many UNIX-like operating systems use this format. Let's look at the structure of the ELF-64 Object File Format and some definitions in the linux kernel source code which related with it.
|
||
10 years ago
|
|
||
9 years ago
|
An ELF object file consists of the following parts:
|
||
10 years ago
|
|
||
9 years ago
|
* ELF header - describes the main characteristics of the object file: type, CPU architecture, the virtual address of the entry point, the size and offset of the remaining parts, etc...;
|
||
9 years ago
|
* Program header table - lists the available segments and their attributes. Program header table need loaders for placing sections of the file as virtual memory segments;
|
||
9 years ago
|
* Section header table - contains the description of the sections.
|
||
10 years ago
|
|
||
9 years ago
|
Now let's have a closer look on these components.
|
||
10 years ago
|
|
||
|
**ELF header**
|
||
|
|
||
9 years ago
|
The ELF header is located at the beginning of the object file. Its main purpose is to locate all other parts of the object file. The File header contains the following fields:
|
||
10 years ago
|
|
||
9 years ago
|
* ELF identification - array of bytes which helps identify the file as an ELF object file and also provides information about general object file characteristic;
|
||
|
* Object file type - identifies the object file type. This field can describe that ELF file is a relocatable object file, an executable file, etc...;
|
||
10 years ago
|
* Target architecture;
|
||
|
* Version of the object file format;
|
||
|
* Virtual address of the program entry point;
|
||
|
* File offset of the program header table;
|
||
|
* File offset of the section header table;
|
||
9 years ago
|
* Size of an ELF header;
|
||
|
* Size of a program header table entry;
|
||
10 years ago
|
* and other fields...
|
||
|
|
||
9 years ago
|
You can find the `elf64_hdr` structure which presents ELF64 header in the linux kernel source code:
|
||
10 years ago
|
|
||
|
```C
|
||
|
typedef struct elf64_hdr {
|
||
|
unsigned char e_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;
|
||
|
```
|
||
|
|
||
7 years ago
|
This structure defined in the [elf.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/uapi/linux/elf.h#L220)
|
||
10 years ago
|
|
||
|
**Sections**
|
||
|
|
||
9 years ago
|
All data stores in a sections in an Elf object file. Sections identified by index in the section header table. Section header contains following fields:
|
||
10 years ago
|
|
||
|
* Section name;
|
||
|
* Section type;
|
||
|
* Section attributes;
|
||
|
* Virtual address in memory;
|
||
|
* Offset in file;
|
||
|
* Size of section;
|
||
|
* Link to other section;
|
||
|
* Miscellaneous information;
|
||
|
* Address alignment boundary;
|
||
|
* Size of entries, if section has table;
|
||
|
|
||
9 years ago
|
And presented with the following `elf64_shdr` structure in the linux kernel:
|
||
10 years ago
|
|
||
|
```C
|
||
|
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;
|
||
|
```
|
||
|
|
||
7 years ago
|
[elf.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/uapi/linux/elf.h#L312)
|
||
9 years ago
|
|
||
10 years ago
|
**Program header table**
|
||
|
|
||
9 years ago
|
All sections are grouped into segments in an executable or shared object file. Program header is an array of structures which describe every segment. It looks like:
|
||
10 years ago
|
|
||
|
```C
|
||
|
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;
|
||
|
```
|
||
|
|
||
9 years ago
|
in the linux kernel source code.
|
||
|
|
||
7 years ago
|
`elf64_phdr` defined in the same [elf.h](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/include/uapi/linux/elf.h#L254).
|
||
10 years ago
|
|
||
9 years ago
|
The ELF object file also contains other fields/structures which you can find in the [Documentation](http://www.uclibc.org/docs/elf-64-gen.pdf). Now let's a look at the `vmlinux` ELF object.
|
||
10 years ago
|
|
||
|
vmlinux
|
||
|
--------------------------------------------------------------------------------
|
||
|
|
||
9 years ago
|
`vmlinux` is also a relocatable ELF object file . We can take a look at it with the `readelf` util. First of all let's look at the header:
|
||
10 years ago
|
|
||
|
```
|
||
|
$ 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
|
||
|
```
|
||
|
|
||
9 years ago
|
Here we can see that `vmlinux` is a 64-bit executable file.
|
||
10 years ago
|
|
||
7 years ago
|
We can read from the [Documentation/x86/x86_64/mm.txt](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/Documentation/x86/x86_64/mm.txt#L21):
|
||
10 years ago
|
|
||
|
```
|
||
|
ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0
|
||
|
```
|
||
|
|
||
9 years ago
|
We can then look this address up in the `vmlinux` ELF object with:
|
||
10 years ago
|
|
||
|
```
|
||
9 years ago
|
$ readelf -s vmlinux | grep ffffffff81000000
|
||
10 years ago
|
1: ffffffff81000000 0 SECTION LOCAL DEFAULT 1
|
||
|
65099: ffffffff81000000 0 NOTYPE GLOBAL DEFAULT 1 _text
|
||
|
90766: ffffffff81000000 0 NOTYPE GLOBAL DEFAULT 1 startup_64
|
||
|
```
|
||
|
|
||
9 years ago
|
Note that the address of the `startup_64` routine is not `ffffffff80000000`, but `ffffffff81000000` and now I'll explain why.
|
||
10 years ago
|
|
||
7 years ago
|
We can see following definition in the [arch/x86/kernel/vmlinux.lds.S](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/arch/x86/kernel/vmlinux.lds.S):
|
||
10 years ago
|
|
||
|
```
|
||
|
. = __START_KERNEL;
|
||
|
...
|
||
|
...
|
||
|
..
|
||
|
/* Text and read-only data */
|
||
|
.text : AT(ADDR(.text) - LOAD_OFFSET) {
|
||
|
_text = .;
|
||
|
...
|
||
|
...
|
||
|
...
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Where `__START_KERNEL` is:
|
||
|
|
||
|
```
|
||
|
#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)
|
||
|
```
|
||
|
|
||
9 years ago
|
`__START_KERNEL_map` is the value from the documentation - `ffffffff80000000` and `__PHYSICAL_START` is `0x1000000`. That's why address of the `startup_64` is `ffffffff81000000`.
|
||
10 years ago
|
|
||
9 years ago
|
And at last we can get program headers from `vmlinux` with the following command:
|
||
10 years ago
|
|
||
|
```
|
||
9 years ago
|
readelf -l vmlinux
|
||
10 years ago
|
|
||
|
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
|
||
|
```
|
||
|
|
||
9 years ago
|
Here we can see five segments with sections list. You can find all of these sections in the generated linker script at - `arch/x86/kernel/vmlinux.lds`.
|
||
10 years ago
|
|
||
9 years ago
|
That's all. Of course it's not a full description of ELF (Executable and Linkable Format), but if you want to know more, you can find the documentation - [here](http://www.uclibc.org/docs/elf-64-gen.pdf)
|