其他部分:
这一部分应该算是最简单的一部分了,几乎就是按照文档的做就可以了,但是有几个问题值的关注
一个系统调用的生命周期是什么
使用navy-apps/tests/hello作为例子分析
从printf会调用klib中间的printf 函数,至于为什么不是调用Nemu中间实现的或者系统的printf以后会讲到。
printf("Hello World from Navy-apps for the %dth time!\n", i ++);
klib中间经过反复调用各种函数,最终会到达nano.c中间。这里大家就把klib当做一个黑盒子,我看一下其中的代码,说实话,有一种读天书的感觉。
nano.c 中间定义了大量的系统调用其中就包括需要使用_write
int _write(int fd, void *buf, size_t count){
return _syscall_(SYS_write, fd, (intptr_t)buf, count);
}
nano.c 中间封装了syscall的调用原理,也就是使用0x80号中断
intptr_t _syscall_(int type, intptr_t a0, intptr_t a1, intptr_t a2) {
int ret = -1;
asm volatile("int $0x80" : "=a"(ret) : "a"(type), "b"(a0), "c"(a1), "d"(a2));
return ret;
}
system.c 定义在Nemu模块中间,包含有int的处理函数
make_EHelper(int) {
uint8_t int_NO = id_dest->val;
raise_intr(int_NO, *eip);
print_asm("int %s", id_dest->str);
}
intr.c 中间定义raise_intr函数读取CPU的中断向量表的入口地址,并且开始执行函数,目前raise_intr函数只会被int调用,在PA4中间还可以被时钟中断调用的。
void raise_intr(uint8_t NO, vaddr_t ret_addr) {
rtl_push(&cpu.eflags);
cpu.IF = 0; // assume we forbit every all IF in the interrupt
rtl_push(&cpu.cs);
rtl_push(&ret_addr); // eip
uint32_t a = vaddr_read(idtr_addr + sizeof(GateDesc) * NO, 4);
uint32_t b = vaddr_read(idtr_addr + sizeof(GateDesc) * NO + 4, 4);
uint32_t entry_addr = (a & 0xffff) | (b & 0xffff0000);
rtl_j(entry_addr);
}
cte.c中间_cte_init函数实现创建了各种终端号的入口地址,都是使用函数的形式定义的。
trap.S中间定义了函数入口,并且在asm_trap函数中间写下一些列的汇编,其中有一个非常关键的操作。调用函数之前push,根据i386的函数调用规则,push的内容就是参数,也就是esp作为参数传入到一个irq_handle的函数中间了。
pushl %esp
call irq_handle
cte.c 中间定义了irq_handle函数,该函数的参数竟然是Context *, 上一步中间说明了esp是参数,也就是调用irq_handle之前的一系列的push的操作就是构成了Context的的内容了。irq_handle 函数会调用一个函数指针,该函数指针指向的内容随架构变化,在x86-neum的架构下会指向do_event函数
irq.c中间定义了do_event函数,进一步调用do_syscall函数
syscall.c 中间定义syscall.c函数
fs.c 中间定义了fs_write函数来处理所有的读写操作,由于虚拟文件的封装,wiret函数会调用实现注册好的serial_write函数。
13.device.c中间包含了seraial_write函数就很简单了,_put()的输出就可以了
清楚了上面过程,整个PA3大概就可以做完了,中间可能会遇到各种bug, 只是需要一层一层的函数调用检查就可以了。
brk 的含义是什么
Nemu和AM是如何协同合作的
printf到底是谁的
随着试验的进行,大家逐渐会模糊一件事情,当你想要调试的时候,printf到底glibc提供的(也就是物理机上安装的操作系统上的运行时库提供的),还是klib提供的(就是哪一个嵌入式库提供的),还是Nemu中间的printf(就是PA2在Nemu中间实现的一系列的io函数)。当然其中使用Log函数是如何实现的。