ELF文件
上次说过了,其实目标文件和可执行文件都是ELF格式文件
ELF索引表
ELF 文件包括三个索引表
ELF内容区
- 字符串表:interp,.strtable ,.shstrtab,.dynstr节区
- 符号表:.symtab
- 代码段:.text节区
- 数据段:.data、.rodata 、.bss节区
- 全局偏移表:.got节区
- 过程链接表: .plt节区
- 哈希表:指.hash节区
- 编译器版信息:.comment
ELF字段类型
Elf32_Addr:4字节,无符号程序地址
Elf32_Half: 2字节,无符号中等整数
Elf32_Off:4 字节,无符号文件偏移
Elf32_SWord:4 字节,有符号大整数
Elf32_Word :4字节,无符号大整数
ELF Header格式
| 字段 |
类型 |
长度 |
说明 |
| ident |
char [16] |
16 |
魔数 |
| type |
Elf32_Half |
2 |
文件类型 |
| machine |
Elf32_Half |
2 |
硬件平台 |
| version |
Elf32_Word |
4 |
版本 |
| entry |
Elf32_Addr |
4 |
程序进入点 <24> |
| phoff |
Elf32_Off |
4 |
程序头表偏移量<28> |
| shoff |
Elf32_Off |
4 |
节头表偏移量 |
| flags |
Elf32_Word |
4 |
处理器特定标志 |
| ehsize |
Elf32_Half |
2 |
ELF头部大小 |
| phentsize |
Elf32_Half |
2 |
程序头大小<42> |
| phnum |
Elf32_Half |
2 |
程序头数量<44> |
| shentsize |
Elf32_Half |
2 |
节头大小 |
| shnum |
Elf32_Half |
2 |
节头数量 |
| shstrndx |
Elf32_Half |
2 |
字符串表索引节头 |
ELF文件分析
查看文件头
readelf -h loader1.bin

| 字段 |
类型 |
长度 |
说明 |
| type |
Elf32_Word |
4 |
段类型 |
| offset |
Elf32_Off |
4 |
偏移量 <4> |
| vaddr |
Elf32_Addr |
4 |
内存虚拟地址 <8> |
| paddr |
Elf32_Addr |
4 |
物理地址 |
| filesz |
Elf32_Word |
4 |
段大小(文件占用)<16> |
| memsz |
Elf32_Word |
4 |
段大小(内存占用) |
| flag |
Elf32_Word |
4 |
段标志 |
| align |
Elf32_Word |
4 |
段对齐 |
查看程序头:
$ readelf -l 文件名

节头格式
| 字段 |
类型 |
长度 |
说明 |
| name |
Elf32_Word |
4 |
节名称 |
| type |
Elf32_Word |
4 |
节类型 |
| flags |
Elf32_Word |
4 |
节属性 |
| addr |
Elf32_Addr |
4 |
节区地址 |
| offset |
Elf32_Off |
2 |
偏移量 |
| size |
Elf32_Word |
4 |
节大小(文件) |
| link |
Elf32_Word |
4 |
节区头部表索引链接 |
| info |
Elf32_Word |
4 |
附加信息 |
| addralign |
Elf32_Word |
4 |
地址对齐 |
| entsize |
Elf32_Word |
4 |
项目表长度 |
查看字段头:
$ readelf -S 文件名

符号表 Symbol table
其他
readelf -a loaderELF.o
size loaderELF.o
objdump -s loaderELF.o
objdump -t loaderELF.o
objdump -S loaderELF.o
内存复制
数据传送指令
movsb指令
movsb : 即字符串传送指令,这条指令按字节送数据。默认复制一个字节/
参数:
rep movsb指令
rep movsb : 即字符串传送指令,复制多个字节
参数:
- esi:数据源地址
- edi:数据目标地址
- ecx:复制字节数、
汇编代码
1 2 3 4 5 6 7 8 9 10
| ;------------------ ;内存复制 : 源地址,目标地址,字节数 ;入参: ; esi = 源地址 ; edi = 目标地址 ; ecx = 字节数 MemCopy: rep movsb; ret
|
解析执行ELF文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| ;----------------------------------- ; 解析执行ELF文件: AnalyzeELF ; 入参: ; eax=文件内存位置 ; 出参: ; ebx=入口地址 AnalyzeELF:
mov edx, 0 mov ecx, 0 mov ebx, [eax + 28] ;program header偏移量 add ebx, eax ;program header位置 mov dx, [eax + 42] ;program header大小 mov cx, [eax + 44] ;program header数量
.loopSegment: cmp byte [ebx + 0],0 ;ptype为0,程序段未使用 je .nextSegment
push ecx; mov ecx, 0; ;--------------- ;复制segment mov esi, [ebx + 4] ;segment偏移量 add esi, eax ;src mov edi, [ebx + 8] ;dist mov cx, [ebx + 16] ;len call MemCopy pop ecx; .nextSegment: add ebx, edx loop .loopSegment ;继续读取下一个segment mov ebx, [eax + 24] ;返回入口地址 ret
|
调用处的代码
1 2 3 4 5 6 7
| ;---------------------- ;解析并执行ELF文件 AnalyzeKernel: mov eax, KERNEL_BASE_ADDR call AnalyzeELF jmp ebx
|
执行的c语言程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| int is_prime(unsigned short n) { int i = 0; for (i = 2; i < n; i++) { if (n % i == 0) { return 0; } } return 1; }
int _start(){ unsigned short* pvga = (unsigned short*)0xb8000; for(int i = 0;i <= 0x7fff;i++){ if(is_prime(i) == 1) { *(pvga + i) = (unsigned short)0x1704; } else { *(pvga + i) = (unsigned short)0x1700; } } fin: goto fin; }
|
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| # tools PLATFORM=Linux NASM=nasm BOCHS=bochs BXIMAGE=bximage
# args boot=boot build=build ENTRY_POINT=0x10000 CFLAGS=-m32 -c -nostdinc -nostdlib -fno-builtin -Wall -W -Wstrict-prototypes -Wmissing-prototypes LDFLAGS=-m elf_i386 -s -e _start -Ttext $(ENTRY_POINT)
target: $(build)/rastos.img @echo "build img completed"
$(build)/rastos.img:$(build)/boot.bin $(build)/loader.bin $(build)/loaderELF.bin $(BXIMAGE) -func=create -imgmode=flat -hd=16M -q $(build)/rastos.img sleep 2 dd if=$(build)/boot.bin of=$(build)/rastos.img bs=512 count=1 conv=notrunc dd if=$(build)/loader.bin of=$(build)/rastos.img bs=512 count=1 seek=1 conv=notrunc dd if=$(build)/loaderELF.bin of=$(build)/rastos.img bs=512 count=30 seek=2 conv=notrunc
$(build)/loaderELF.bin: $(build)/loaderELF.o $(LD) $(build)/loaderELF.o -o $(build)/loaderELF.bin $(LDFLAGS)
$(build)/loaderELF.o: $(boot)/loaderELF.c $(CC) $(boot)/loaderELF.c -o $(build)/loaderELF.o $(CFLAGS)
$(build)/%.bin: $(boot)/%.asm $(NASM) -f bin -o $(build)/$*.bin $(boot)/$*.asm
prepare: $(build) @echo "prepare dir $(build)" ifeq ($(build), $(wildcard $(build))) @echo "build directory exist..." else mkdir -p $(build) endif
clean: @echo "clean dir $(build)" rm -rf $(build)/*
platform: @echo $(PLATFORM)
|
加载执行c语言程序的代码并执行

天空任鸟飞,海阔凭鱼跃。我们已经成功的从启动,到进入c语言的世界,接下来就是无限的可能性。