慢慢欣赏linux elf文件

10 篇文章 0 订阅
2 篇文章 0 订阅
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 vmlinux
ELF 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 vmlinux

Elf file type is EXEC (Executable file)
Entry point 0x400000
There are 3 program headers, starting at offset 52

Program 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_START
CONFIG_PHYSICAL_START=0x400000

简单介绍一下Linux中ELF格式文件
http://www.elecfans.com/emb/20190402898901.html

ELF结构
http://blog.chinaunix.net/uid-8473611-id-3184556.html

vmlinux 和普通elf文件的差别 linux kernel加载简述
https://blog.csdn.net/wdjjwb/article/details/81145255

ELF格式大致描述
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值