本文共 4331 字,大约阅读时间需要 14 分钟。
void parse_elf(void *output){ Elf32_Ehdr ehdr; Elf32_Phdr *phdrs, *phdr; memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum); for (i = 0; i < ehdr.e_phnum; i++) { phdr = &phdrs[i]; switch (phdr->p_type) { case PT_LOAD:#ifdef CONFIG_RELOCATABLE dest = output; /* 参考下面的vmlinux.lds脚本 dest = out + (phdr->p_paddr - LOAD_PHYSICAL_ADDR) = out + (ADDR(.text) - LOAD_OFFSET) - LOAD_PHYSICAL_ADDR = out + (LOAD_OFFSET + LOAD_PHYSICAL_ADDR - LOAD_OFFSET) - LOAD_PHYSICAL_ADDR = out */ dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR);#else dest = (void *)(phdr->p_paddr); // p_paddr 为加载地址#endif memcpy(dest, output + phdr->p_offset, phdr->p_filesz); break; default: /* Ignore other PT_* */ break; } }}
对应的lds脚本
SECTIONS{#ifdef CONFIG_X86_32 . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; phys_startup_32 = startup_32 - LOAD_OFFSET;#endif /* Text and read-only data */ .text : AT(ADDR(.text) - LOAD_OFFSET) { // AT 定义加载地址,属于 PT_LOAD 段 _text = .; /* bootstrapping code */ HEAD_TEXT#ifdef CONFIG_X86_32 . = ALIGN(PAGE_SIZE); *(.text.page_aligned)#endif . = ALIGN(8); _stext = .; TEXT_TEXT SCHED_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT *(.fixup) *(.gnu.warning) /* End of text section */ _etext = .; } :text = 0x9090 /* Data */ .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Start of data section */ _sdata = .; /* init_task */ INIT_TASK_DATA(THREAD_SIZE)#ifdef CONFIG_X86_32 /* 32 bit has nosave before _edata */ NOSAVE_DATA#endif PAGE_ALIGNED_DATA(PAGE_SIZE) CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES) DATA_DATA CONSTRUCTORS /* rarely changed data like cpu maps */ READ_MOSTLY_DATA(INTERNODE_CACHE_BYTES) /* End of data section */ _edata = .; } :data
linux设备查看
[root@cliffr linux-2.6.32]# readelf -h vmlinuxELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x400000 Start of program headers: 52 (bytes into file) Start of section headers: 90528352 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 3 Size of section headers: 40 (bytes) Number of section headers: 70 Section header string table index: 67[root@cliffr linux-2.6.32]# [root@cliffr linux-2.6.32]# readelf -l vmlinuxElf file type is EXEC (Executable file)Entry point 0x400000There are 3 program headers, starting at offset 52Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x001000 0xc0400000 0x00400000 0x58f000 0x58f000 R E 0x1000 LOAD 0x590000 0xc098f000 0x0098f000 0xfe000 0x34e000 RWE 0x1000 NOTE 0x3e396c 0xc07e296c 0x007e296c 0x00168 0x00168 0x4 Section to Segment mapping: Segment Sections... 00 .text .notes __ex_table .rodata __bug_table .pci_fixup __ksymtab __ksymtab_gpl __kcrctab __kcrctab_gpl __ksymtab_strings __init_rodata __param 01 .data .init.text .init.data .x86_cpu_dev.init .parainstructions .altinstructions .altinstr_replacement .exit.text .data.percpu .smp_locks .bss .brk 02 .notes 对于第二个LOAD来说, 也就是数据段, 从elf的角度来看, 两者存放的位置是紧挨着。我们看一下代码段内存加载的位置:dest = out + (phdr->p_paddr - LOAD_PHYSICAL_ADDR) = out + (AT(ADDR(.text)) + text_len - LOAD_OFFSET - LOAD_PHYSICAL_ADDR) = out + text_len[root@cliffr linux-2.6.32]# cat .config | grep CONFIG_PHYSICAL_STARTCONFIG_PHYSICAL_START=0x400000
简单介绍一下Linux中ELF格式文件
http://www.elecfans.com/emb/20190402898901.htmlELF结构
http://blog.chinaunix.net/uid-8473611-id-3184556.htmlvmlinux 和普通elf文件的差别 linux kernel加载简述
https://blog.csdn.net/wdjjwb/article/details/81145255ELF格式大致描述
https://blog.csdn.net/qq_36503007/article/details/82821922链接脚本使用AT加载地址的总结
https://blog.csdn.net/czg13548930186/article/details/78770601关于链接脚本.lds的小知识点
https://blog.csdn.net/yilongdashi/article/details/84873908