基于x86架构的简单内核实现-2
5.库函数 和 调试打印函数
基础部分在前四章已经介绍完了。
5.1 c语言字符串处理函数
在内核中无法使用 处于用户态的c语言库函数 所以需要自己实现相关函数
include/string.h
1 |
|
函数实现
libs/string.c
memcpy()
1 | inline void memcpy(uint8_t *dest, const uint8_t *src, uint32_t len){ |
使用内联函数 减少函数调用的开销
++ 优先级高于 * 先右边结合 d++ 然后再 *d 最后在++进行自增 指向下一个内存地址
- 解引用
dest
当前指向的内存位置,用于读取或写入值。 - 将
dest
指针移动到下一个uint8_t
类型的内存地址。
memset()
1 | inline void memset(void *dest, uint8_t val, uint32_t len) { |
uint8_t *dst = (uint8_t *) dest;
1
2
3
4
5
6
7
8
9
10
11
12
- 这行代码中的类型转换是必要的,因为 `void*` 类型的指针是一个通用指针,无法直接进行算术运算。将 `void*` 转换为 `uint8_t*` 使得可以按字节操作内存(即每次操作一个字节)。
- `uint8_t` 是一个确保只操作一个字节大小的类型,适用于按字节设置内存值。
> bzero() 将 dest 指向的内存区域的前 len 个字节清零(等同于调用 memset(dest, 0, len))
```c
inline void bzero(void *dest, uint32_t len){
memset(dest, 0, len);
}
strcmp()
1 | static inline int strcmp(const char *str1, const char *str2) |
*str1 && *str2
确保当前指针指向的字符串不是终止字符 \0
*str1 == *str2
确保相等
返回值:return *str1 - *str2;
返回ASCII之差
- 如果
*str1 - *str2
为零(即*str1 == *str2
),这意味着两个字符串相等或在某一点同步到了字符串的终止字符。 - 如果
*str1 - *str2
为正值,则str1
在首个不同点处的字符在字典顺序中位于str2
的对应字符之后。 - 如果
*str1 - *str2
为负值,则str1
在首个不同点处的字符在字典顺序中位于str2
的对应字符之前。
strcpy()
1 | static inline char *strcpy(char *dest, const char *src) |
strcat()
1 | static inline char *strcat(char *dest, const char *src) |
cp++;
找到字符串末尾
*cp++ = *src++
进行赋值
strlen()
1 | static inline int strlen(const char *src) |
(eos - src - 1)
因为地址是连续的,所以直接进行地址相减
5.2 内核级打印函数 printk
参照printf 函数:首先是一个待显示的字符 串,里面分别用%加相关字母的方式一一指明了后面的参数数量和类型。只要我们传递正确 的带有格式描述的字符串和相关参数,printf函数就能正确的打印出来结果。
5.3 利用qemu 联合 gdb 进行c语言 源代码级别调试
通讯机制:
qemu -S -s -fda floppy.img -boot a
- 注意这里的qemu 要替换成 qemu-system-i386
- 因为qemu和gdb运行的时候毕竟是两个进程,数据交换必然涉及到进 程间通信机制。
- -fda floppy.img 和 -boot a 是指定启动的镜像,-s 这个参数指的 是启动时开启1234端口等待gdb连接(这个参数从字面上看比较隐晦),-S 是指是启动时 不自动开始运行,等待调试器的执行命令。
启动gdb后执行下面命令: — 后续直接封装在gdbinit这个文件中
1 | file hx_kernel |
执行命令
1 | make |
5.4 打印函数调用的栈信息 — multiboot
在示意图中我们假设从start函数->kern_entry函数->console_clear函数的调用过 程,最终暂停在console_clear函数里面。我们可以清楚的看到,只要拿到此时的ebp寄存 器的值,就可以沿着这个调用链找到每一个调用的函数的返回地址,之前的问题就这样解 决了。需要注意的是C语言里对指针做算数运算时,改变的地址长度是和当前指针变量的类 型相关的。
5.4 修改entry.c函数
entry.c
1 |
|
运行结果:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Sifanのblog!