北航linux内核编译及烧录实验报告,北航操作系统实验Lab1笔
记
<
# 北航操作系统实验Lab1
## Exerci 1.1
- **修改交叉编译路径为 `/OSLAB/compiler/usr/bin/mips_4KC-`**
- **`gxemul/` ⽬录下⽣成`vmlinux` 内核⽂件**
## Exerci 1.2动态摄影
ELF(Executable and Linkable Format) 是⼀种⽂件格式,从名字上看它是可执⾏⽂件和可链接⽂件的格式。通常多个.c⽂件经过编译以后,⽣成多个.o⽂件(也即是⽬标⽂件), 这些.o⽂件就是ELF格式,然后链接器将多个.o链接到⼀起就得到了⼀个可执⾏⽂件。可执⾏⽂件也是ELF格式。
那么,ELF ⽂件中都包含有什么东西呢?简⽽⾔之,就是和程序相关的所有必要信息。具体来说包含5
个部分。
1. ELF Header,包括程序的基本信息,⽐如体系结构和操作系统,同时也包含了 Section Header Table 和 Program Header Table 相对⽂件的偏移量 (offt)。
2. Program Header Table,也可以称为 Segment Table,它是⼀个数组,数组中的每⼀项描述了程序中每⼀个Segment的信
息,Segment 的信息需要在运⾏时刻使⽤。
3. Section Header Table,它也是个数组,数组的每⼀项描述了每⼀个Section的信息,Section 的信息需要在程序编译和链接的时候使⽤。
4. Segments,就是各个 Segment。Segment 则记录了每⼀段数据(包括代码等内容)需要被载⼊到哪⾥,记录了⽤于指导应⽤程序加载的各类信息。
5. Sections,就是各个 Section。Section 记录了程序的代码段、数据段等各个段的内容,主要是链接器在链接的过程中需要使⽤。
### 补全 `readelf.c` ⽂件
- **⽅法1**
```c
// get ction table addr, ction header number and ction header size.
shdr = (Elf32_Shdr *)(binary + ehdr -> e_shoff); //ction table addr
sh_entry_count = ehdr -> e_shnum; //ction header number
sh_entry_size = ehdr -> e_shentsize; //ction header size
// for each ction header, output ction number and ction addr.
for(Nr = 0; Nr < sh_entry_count; ++ Nr)
{
printf("%d:0x%x\n" , Nr , shdr->sh_addr);
shdr ++ ;
}
```c
// get ction table addr, ction header number and ction header size.
ptr_sh_table = binary + ehdr -> e_shoff;
sh_entry_count = ehdr -> e_shnum; //ction header number
sh_entry_size = ehdr -> e_shentsize; //ction header size
// for each ction header, output ction number and ction addr.
for(Nr = 0; Nr < sh_entry_count; ++ Nr)
{
shdr = (Elf32_Shdr *)(ptr_sh_table);
printf("%d:0x%x\n" , Nr , shdr->sh_addr);
ptr_sh_table += sh_entry_size;
}
```
### 解析 testELF ⽂件
## Exerci 1.3
实验使⽤的操作系统内核就是我们上⾯⽣成的vmlinux⽂件,这个⽂件是个可执⾏⽂件,ELF格式。它是经过多个.c⽂件编译成.o⽂件后,然后链接器将多个.o⽂件链接成⼀个最终的可执⾏⽂件vmlinux。我们的模拟器gxemul会把vmlinux⽂件加载到内存,然后跳转到内核⼊⼝(其实是个地址),CPU会从这个⼊⼝地⽅开始取址执⾏,这样操作系统就启动完毕了。内核⽂件⾥⾯有代码,数据等,内核⽂件应该被加载到哪个地⽅呢?换⽽⾔之这些代码和数据应该存储在内存中哪个地⽅?通过内存布局图可以发现我们需要把内核⽂件加载到`Kernel Text`处,也即是地址`0x80010000`处。如何设置内核加载的位置?
⾸先我们需要知道,⼀个可执⾏⽂件是根据什么加载到内存。是根据ELF⽂件⾥的内容,ELF⽂件记录了这个⽂件的各个段应该被加载到哪个地址,然后程序把这个⽂件加载到这个地址(这个在后⾯Lab
3⾥⾯会让你来实现这个过程)。我们可以看到vmlinux⽂件是由多个.o⽂件链接⽽成的,然后得到ELF⽂件vmlinux。ELF⽂件记录了这个⽂件应该被加载到哪个地⽅,因此我们可以在链接⽣成ELF⽂件的时候,指定这个加载位置为`0x80010000`!将内核⽂件加载到指定位置上,CPU不⼀定从这个位置开始执⾏。指导书上也说了程序⼊⼝的⼏种设置⽅法,本实验显然是使⽤ ENTRY() 指令指定了程序⼊⼝为 _start 函数。
### 补全 tools/sc_03.lds
- **将起始地址设为 `0x80010000`**
```asm
SECTIONS
{
. = 0x80010000;
.text : { *(.text) }
.data : { *(.data) }沈阳游玩
.bss : { *(.bss) }
end = . ;
### 查看地址
- **重新`make`,⽣成`vmlinux`内核⽂件**
- **查看各个`ction`的地址**
## Exerci 1.4
### 补全 `boot/start.S`
- **栈指针地址应设为 `0x80400000`**
```asm
/*To do:
t up stack
you can reference the memory layout in the include/mmu.h */
li sp, 0x80400000 // 设置栈指针举世闻名的反义词
jal main // 跳转到main函数
nop
```
### 运⾏ `vmlinux` ⽂件
- **重新`make`**
- **执⾏命令 `gxemul -E testmips -C R3000 -M 64 elf-file`** `elf-file`为编译⽣成的`vmlinux`⽂件的路径
## Exerci 1.5
### 补全 `lp_Print()` 函数
- **找到 `%`**
```c
外国电影推荐/* scan for the next '%' */
while((*fmt) != '\0' && (*fmt) != '%') {
含手的成语
OUTPUT(arg, fmt, 1);//其他字符,直接输出
fmt ++ ;
}
/* flush the string found so far */
/* are we hitting the end? */
if((*fmt) == '\0' ) break; //结束了
```
/*init the variable */冰箱怎么调
描写父亲的句子
longFlag = 0;
negFlag = 0;
width = 0;
ladjust = 0;//默认右对齐
prec = 0;
padc = ' ';
/* we found a '%' */
fmt ++ ;
/* check for other prefixes */
/*check for flag */
if(*fmt == '-') ladjust = 1, fmt ++;
el if(*fmt == '0') padc = '0' , fmt ++;
/*check for width */
for(; IsDigit(*fmt); fmt ++ ) width = width * 10 + Ctod(*fmt) ;
/*check for precision */
if(*fmt == '.')
{
fmt ++ ;
for(; IsDigit(*fmt); fmt ++ )
prec = prec * 10 + Ctod(*fmt) ;
}
/* check for long */
if( *fmt == 'l' ) {
longFlag = 1;
fmt ++ ;
}
玄武兽```
### 输出结果
- **重新`make`**
- 执⾏命令 `gxemul -E testmips -C R3000 -M 64 elf-file` , 查看输出结果### push到远程进⾏测试
最后修改:2020 年 07 ⽉ 26 ⽇ 10 : 46 AM © 允许规范转载
赞赏
如果觉得我的⽂章对你有⽤,请随意赞赏
×Clo
赞赏作者
扫⼀扫⽀付
⽀付宝⽀付
微信⽀付