在linux remoteproc驱动中elf解析函数实现分析文章中介绍了在linux remoteproc驱动中对elf文件各个不同类型header parse的函数以及对应的定义。
在该文中则重点解释program segment的含义以及对应数据处理。
/* These constants define the permissions on sections in the program
header, p_flags. */
#define PF_R 0x4
#define PF_W 0x2
#define PF_X 0x1
typedef struct elf32_phdr{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
typedef struct elf64_phdr {
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment, file & memory */
} Elf64_Phdr;
以test.elf为例来分析
Offset
表示对应program segment数据在elf文件中的偏移地址PhysAddr
表示要将该program segment的数据拷贝到的物理地址FileSiz
表示当前program segment在elf文件中占的大小MemSiz
表示当前program segment在对应bin文件中占的大小Flg
表示当前program segment的属性Align
表示当前program segment的对齐大小$ readelf -lW test.elf
Elf file type is EXEC (Executable file)
Entry point 0x0
There are 6 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x09262c 0x1016262c 0x1016262c 0x00008 0x00008 R 0x4
LOAD 0x010000 0x00000000 0x00000000 0x00440 0x00440 RW 0x10000
LOAD 0x020000 0x10000000 0x10000000 0x00800 0x00800 R E 0x10000
LOAD 0x030000 0x10100000 0x10100000 0x62638 0x62638 R E 0x10000
LOAD 0x092740 0x10172740 0x10172740 0x0900c 0x5d158a0 RW 0x10000
LOAD 0x000000 0xa0000000 0xa0000000 0x00000 0x04100 RW 0x10000
Section to Segment mapping:
Segment Sections...
00 .ARM.exidx
01 .reset .rom
02 .cpu_vectors
03 .init .text .fini .rodata .ARM.exidx .eh_frame
04 shell_cmd .data .init_array .fini_array .init_array.00000 .datasafe .bss .stack .heap
05 .ram_mpu
$
以linux编译生成的vmlinux为例:其一共包含5个program segments;
Offset
表示对应program segment数据在elf文件中的偏移地址PhysAddr
表示要将该program segment的数据拷贝到的物理地址FileSiz
表示当前program segment在elf文件中占的大小MemSiz
表示当前program segment在对应bin文件中占的大小Flg
表示当前program segment的属性Align
表示当前program segment的对齐大小$ readelf -lW vmlinux
Elf file type is DYN (Shared object file)
Entry point 0xffff800008000000
There are 5 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0xffff800008000000 0xffff800008000000 0xd2c000 0xd2c000 RWE 0x10000
LOAD 0xd40000 0xffff800008d40000 0xffff800008d40000 0x0588dc 0x0588dc R E 0x10000
LOAD 0xda0000 0xffff800008da0000 0xffff800008da0000 0x397808 0x43ea24 RW 0x10000
NOTE 0xd3aa50 0xffff800008d2aa50 0xffff800008d2aa50 0x000054 0x000054 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
Section to Segment mapping:
Segment Sections...
00 .head.text .text .got.plt .rodata __ksymtab __ksymtab_gpl __ksymtab_strings __param __modver __ex_table .notes .hyp.rodata
01 .init.text .exit.text .altinstructions
02 .init.data .data..percpu .hyp.data..percpu .hyp.reloc .rela.dyn .data __bug_table .mmuoff.data.write .mmuoff.data.read .bss
03 .notes
04
$
typedef struct elf32_shdr {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
typedef struct elf64_shdr {
Elf64_Word sh_name; /* Section name, index in string tbl */
Elf64_Word sh_type; /* Type of section */
Elf64_Xword sh_flags; /* Miscellaneous section attributes */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Size of section in bytes */
Elf64_Word sh_link; /* Index of another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
以test.elf为例来分析
Off
表示对应section数据在elf文件中的偏移地址Addr
表示要将该section的数据拷贝到的物理地址Size
表示当前section的大小Flg
表示当前program segment的属性Type
表示当前section的类型Name
表示当前section的名字Flg
表示当前section的属性$ readelf -SW test.elf
There are 23 section headers, starting at offset 0x9b894:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .reset PROGBITS 00000000 010000 000040 00 A 0 0 1
[ 2] .rom PROGBITS 00000100 010100 000340 00 WA 0 0 1
[ 3] .ram_mpu NOBITS a0000000 0a0000 004100 00 WA 0 0 1
[ 4] .cpu_vectors PROGBITS 10000000 020000 000800 00 AX 0 0 4
[ 5] .init PROGBITS 10100000 030000 00000c 00 AX 0 0 4
[ 6] .text PROGBITS 10100010 030010 0555c0 00 AX 0 0 16
[ 7] .fini PROGBITS 101555d0 0855d0 00000c 00 AX 0 0 4
[ 8] .rodata PROGBITS 101555e0 0855e0 00d04c 00 A 0 0 8
[ 9] .ARM.exidx ARM_EXIDX 1016262c 09262c 000008 00 AL 6 0 4
[10] .eh_frame PROGBITS 10162634 092634 000004 00 A 0 0 4
[11] shell_cmd PROGBITS 10172740 092740 0000f0 00 WA 0 0 32
[12] .data PROGBITS 10172830 092830 004780 00 WA 0 0 16
[13] .init_array INIT_ARRAY 10176fb0 096fb0 000004 04 WA 0 0 4
[14] .fini_array FINI_ARRAY 10176fb4 096fb4 000004 04 WA 0 0 4
[15] .init_array.00000 INIT_ARRAY 10176fb8 096fb8 000004 04 WA 0 0 4
[16] .datasafe PROGBITS 10176fbc 096fbc 004790 00 WA 0 0 1
[17] .bss NOBITS 1017b750 09b74c 07c888 00 WA 0 0 16
[18] .stack NOBITS 101f7fe0 09b74c 090000 00 WA 0 0 1
[19] .heap NOBITS 10287fe0 09b74c 5c00000 00 WA 0 0 1
[20] .comment PROGBITS 00000000 09b74c 000045 01 MS 0 0 1
[21] .ARM.attributes ARM_ATTRIBUTES 00000000 09b791 000035 00 0 0 1
[22] .shstrtab STRTAB 00000000 09b7c6 0000cb 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
$
以linux的vmlinux为例来分析
Off
表示对应section数据在elf文件中的偏移地址Addr
表示要将该section的数据拷贝到的物理地址Size
表示当前section的大小Flg
表示当前program segment的属性Type
表示当前section的类型Name
表示当前section的名字Flg
表示当前section的属性$ readelf -SW vmlinux
There are 40 section headers, starting at offset 0xd59a938:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .head.text PROGBITS ffff800008000000 010000 000040 00 AX 0 0 4
[ 2] .text PROGBITS ffff800008010000 020000 a63d60 08 AX 0 0 65536
[ 3] .got.plt PROGBITS ffff800008a73d60 a83d60 000018 08 WA 0 0 8
[ 4] .rodata PROGBITS ffff800008a80000 a90000 25af18 00 WA 0 0 4096
[ 5] __ksymtab PROGBITS ffff800008cdaf18 ceaf18 00d374 00 A 0 0 4
[ 6] __ksymtab_gpl PROGBITS ffff800008ce828c cf828c 00fe10 00 A 0 0 4
[ 7] __ksymtab_strings PROGBITS ffff800008cf809c d0809c 02e361 01 AMS 0 0 1
[ 8] __param PROGBITS ffff800008d26400 d36400 0028a0 00 A 0 0 8
[ 9] __modver PROGBITS ffff800008d28ca0 d38ca0 000318 00 WA 0 0 8
[10] __ex_table PROGBITS ffff800008d28fb8 d38fb8 001a98 00 A 0 0 8
[11] .notes NOTE ffff800008d2aa50 d3aa50 000054 00 A 0 0 4
[12] .hyp.rodata PROGBITS ffff800008d2b000 d3b000 001000 00 WA 0 0 8
[13] .init.text PROGBITS ffff800008d40000 d40000 03fcf4 00 AX 0 0 4
[14] .exit.text PROGBITS ffff800008d7fcf4 d7fcf4 0031c8 00 AX 0 0 4
[15] .altinstructions PROGBITS ffff800008d82ebc d82ebc 015a20 00 A 0 0 1
[16] .init.data PROGBITS ffff800008da0000 da0000 013298 00 WA 0 0 256
[17] .data..percpu PROGBITS ffff800008db4000 db4000 009b58 00 WA 0 0 64
[18] .hyp.data..percpu PROGBITS ffff800008dbe000 dbe000 000ed0 00 WA 0 0 16
[19] .hyp.reloc PROGBITS ffff800008dbeed0 dbeed0 000060 00 A 0 0 4
[20] .rela.dyn RELA ffff800008dbef30 dbef30 1fa280 18 A 37 0 8
[21] .data PROGBITS ffff800008fc0000 fc0000 162b20 00 WA 0 0 4096
[22] __bug_table PROGBITS ffff800009122b20 1122b20 013e18 00 WA 0 0 4
[23] .mmuoff.data.write PROGBITS ffff800009137000 1137000 000018 00 WA 0 0 2048
[24] .mmuoff.data.read PROGBITS ffff800009137800 1137800 000008 00 WA 0 0 8
[25] .bss NOBITS ffff800009138000 1137808 0a6a24 00 WA 0 0 4096
[26] .debug_aranges PROGBITS 0000000000000000 1137810 01f600 00 0 0 16
[27] .debug_info PROGBITS 0000000000000000 1156e10 8f735c0 00 0 0 1
[28] .debug_abbrev PROGBITS 0000000000000000 a0ca3d0 449e7e 00 0 0 1
[29] .debug_line PROGBITS 0000000000000000 a51424e f522ac 00 0 0 1
[30] .debug_frame PROGBITS 0000000000000000 b466500 261300 00 0 0 8
[31] .debug_str PROGBITS 0000000000000000 b6c7800 29f3dc 01 MS 0 0 1
[32] .debug_ranges PROGBITS 0000000000000000 b966be0 000230 00 0 0 16
[33] .debug_line_str PROGBITS 0000000000000000 b966e10 010dda 01 MS 0 0 1
[34] .debug_loclists PROGBITS 0000000000000000 b977bea 152ec46 00 0 0 1
[35] .debug_rnglists PROGBITS 0000000000000000 cea6830 2e8174 00 0 0 1
[36] .comment PROGBITS 0000000000000000 d18e9a4 000045 01 MS 0 0 1
[37] .symtab SYMTAB 0000000000000000 d18e9f0 26caa8 18 38 85372 8
[38] .strtab STRTAB 0000000000000000 d3fb498 19f2f0 00 0 0 1
[39] .shstrtab STRTAB 0000000000000000 d59a788 0001ab 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
$
对于elf section的数据在boot阶段的流向是按照从elf文件的offset处,按照size大小去拷贝数据到addr的内存处,当各个section拷贝完成之后即可以触发复位操作,启动对应的core。