这是 rCore Tutorial Book 第一章「应用程序与基本执行环境」的练习。
本文首发于 blog.skywt.cn,建议查看原文以获得更好的阅读体验。
课后练习
编程题
Program 1
1. 实现一个 linux 应用程序 A,显示当前目录下的文件名。
#include <dirent.h>
#include <stdio.h>
int main() {
DIR *dir = opendir(".");
struct dirent *entry;
while ((entry = readdir(dir))) {
printf("%s\n", entry->d_name);
}
return 0;
}
相关库的用法:
- dirent.h 这个库中,定义了
DIR数据类型,表示一个目录流。同时还定义了一个叫做dirent的数据类型,是一个结构体,其中一个成员是char d_name[],即目录的名称。 - opendir 函数打开一个目录流,返回的正是
DIR对象。 - readdir 函数以一个
DIR对象为参数,返回一个dirent类型结构体,它表示传入的DIR指针指向的条目;同时,会将指针指向下一个条目。
Program 2
2. 实现一个 Linux 应用程序 B,能打印出调用栈链信息。
(前置知识:C 语言中内联汇编语句 asm 的用法)
这里在 x86_64 环境下运行。我们直接内联汇编命令,将栈底指针寄存器 rbp 取出来,并不断根据寄存器的内容追溯上一个栈帧的 rbp。(注意我们是 64 位环境,所以最好使用 64 位的 rbp 而不是 ebp)
需要注意的是,根据实践,第一个栈帧的 rbp 指向的是 0x1 而不是 0x0。while 循环何时停止需要根据此判断。
编写输出栈信息的函数如下:
void print_call_stack_info() {
unsigned long long stack_ptr;
asm ("mov %%rbp, %0" : "=r" (stack_ptr));
printf("== BEGIN CALL STACK INFO\n");
while (stack_ptr != 0x1) {
printf(" == %p\n", (void*)stack_ptr);
stack_ptr = *((unsigned long long*)stack_ptr);
}
printf("== END CALL STACK INFO\n");
}
递归调用的函数能让我们最直观地体会到栈的变化。编写好如上函数之后,我们来编写一个递归计算阶乘的函数,并让程序计算 5 的阶乘:
int fact(int x){
printf("Calling fact(%d)\n", x);
print_call_stack_info();
if (x == 0) return 1;
return fact(x-1) * x;
}
int main() {
print_call_stack_info();
printf("5! = %d\n", fact(5));
return 0;
}
编译运行,程序会在每次调用 fact 时输出栈信息。可以看到在 fact(0) 中调用 print_call_stack_info() 有 8 行输出(也就是有 8

本文介绍了Linux下显示当前目录文件的C程序,展示了通过内联汇编获取调用栈信息的技巧,以及在RISC-V环境中使用QEMU模拟系统调用的示例。文章还探讨了应用程序占用的资源、内存空间分配、栈帧恢复方法,并讲解了如何通过GDB调试QEMU启动过程。
最低0.47元/天 解锁文章
342

被折叠的 条评论
为什么被折叠?



