geekos project 1 (ELF文件相关)
一、目的 熟悉ELF文件格式,了解GeekOS系统如何将ELF格式的可执行程序装入到内存,建立内核进程并运行的实现技术。 二、流程 1、修改/geekos/elf.c文件:在函数Parse_ELF_Executable( )中添加代码,分析ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值。 2、在Linux环境下编译系统得到GeekOS镜像文件。 3、编写一个相应的bochs配置文件。 4、在bochs中运行GeekOS系统显示结果。
编译以及启动bochs同project0… project0遇到的那些错误还是都会遇到一遍233.
然后在project1/src/geekos/ 目录下的elf.c中添加函数:int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat)
原理部分不过多阐释,具体可见我参考的博客。
最后实现为:
1int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength,
2 struct Exe_Format *exeFormat)
3 {
4 elfHeader* header = exeFileData;
5 programHeader* pHeader = (exeFileData+header->phoff);
6 exeFormat->numSegments = header->phnum;
7 exeFormat->entryAddr = header->entry;
8 int i = 0;
9 for (; i< header->phnum; i++) {
10 exeFormat->segmentList[i].offsetInFile = pHeader->offset;
11 exeFormat->segmentList[i].lengthInFile = pHeader->fileSize;
12 exeFormat->segmentList[i].startAddress = pHeader->vaddr;
13 exeFormat->segmentList[i].sizeInMemory = pHeader->memSize;
14 exeFormat->segmentList[i].protFlags = pHeader->flags;
15 pHeader++;
16 }
17
18 return 0; //!!
19
20 //TODO("Parse an ELF executable image");
21 }
然后由于编译之后比project0多生成了一个diskc.img文件
所以还需要相应得修改配置文件.bochsrc
最后内容如下:
1config_interface: textconfig
2romimage: file=/usr/share/bochs/BIOS-bochs-latest
3megs: 8
4vgaromimage: file=/usr/share/vgabios/vgabios.bin
5floppya: 1_44=./fd.img, status=inserted
6ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
7ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15
8#ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
9#ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
10ata0-master: type=disk, path=./diskc.img, mode=flat, cylinders=40, heads=8, spt=64
11#ata0-slave: type=cdrom, path="/dev/cdrom", status=inserted
12boot: a
13#ips: 1000000
14log:./bochs.out
15vga_update_interval: 300000
16keyboard_serial_delay: 250
17keyboard_paste_delay: 100000
18private_colormap: enabled=0
display_library: sdl
project0遇到的启动bochs的那些问题project1也会遇到一遍233
然后。。。启动。。。
报错如下:
查了好多。。。一无所获。。。
最后看到一遍博客: 参考博客1
那篇博客里虽然和我遇到的问题不一致。。。
但是死马当做活马医。。。
objdump -d a.exe 查看了反汇编代码。。。。a.exe的路径是project1/build/user/
100001000 <_Entry>:
2 1000: 83 ec 1c sub $0x1c,%esp
3 1003: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp)
4 100a: 00
5 100b: c7 04 24 00 00 00 00 movl $0x0,(%esp)
6 1012: e8 06 00 00 00 call 101d <main>
7 1017: c9 leave
8 1018: cb lret
9 1019: 83 c4 1c add $0x1c,%esp
10 101c: c3 ret
10000101d <main>:
2 101d: 55 push p
3 101e: 89 e5 mov %esp,p
4 1020: 83 e4 f0 and $0xfffffff0,%esp
5 1023: 83 ec 40 sub $0x40,%esp
6 1026: c7 44 24 18 48 69 20 movl $0x21206948,0x18(%esp)
7 102d: 21
8 102e: c7 44 24 1c 20 54 68 movl $0x69685420,0x1c(%esp)
9 1035: 69
10 1036: c7 44 24 20 73 20 69 movl $0x73692073,0x20(%esp)
11 103d: 73
12 103e: c7 44 24 24 20 74 68 movl $0x65687420,0x24(%esp)
13 1045: 65
14 1046: c7 44 24 28 20 73 65 movl $0x63657320,0x28(%esp)
15 104d: 63
16 104e: c7 44 24 2c 6f 6e 64 movl $0x20646e6f,0x2c(%esp)
17 1055: 20
18 1056: c7 44 24 30 73 74 72 movl $0x69727473,0x30(%esp)
19 105d: 69
20 105e: c7 44 24 34 6e 67 0a movl $0xa676e,0x34(%esp)
21 1065: 00
22 1066: c7 44 24 38 00 00 00 movl $0x0,0x38(%esp)
23 106d: 00
24 106e: c7 44 24 3c 00 00 00 movl $0x0,0x3c(%esp)
25 1075: 00
26 1076: c7 04 24 00 21 00 00 movl $0x2100,(%esp)
27 107d: e8 13 00 00 00 call 1095 <ELF_Print>
28 1082: 8d 44 24 18 lea 0x18(%esp),x
29 1086: 89 04 24 mov x,(%esp)
30 1089: e8 07 00 00 00 call 1095 <ELF_Print>
31 108e: b8 00 00 00 00 mov $0x0,x
32 1093: c9 leave
33 1094: c3 ret
100001095 <ELF_Print>:
2 1095: 8b 44 24 04 mov 0x4(%esp),x
3 1099: cd 90 int $0x90
4 109b: c3 ret
可以看到在_Entry入口处的汇编,首先
sub $0x1c,%esp
然而程序却抢先在
add $0x1c,%esp
之前使用leave和lret长跳转返回了,这样程序当然出错了。
我这里是将
asm volatile (“leave”); asm volatile (“lret”);
改成了
** asm volatile (“add $0x1c, %esp”); (注意,原文作者这里把%esp写成$esp,坑死小白啊。。还写错两次)**
asm volatile (“lret”);
就能正常工作了。

