解决 ucore 实验 qemu 不断重启问题

解决 ucore 实验 qemu 不断重启问题

做清华大学操作系统 ucore 实验 (x86版本),实验一编译后运行 qemu 发现系统不断重启,无法正常运行 kernel。实验环境是 ubuntu 22.04gcc 11.4.0ld 2.38。最终查证是链接脚本 kernel.ld 导致代码运行错误。解决方法需要小小修改 kernel.ld

问题查证

使用 gdb 单部跟踪,发现运行到下面的 lgdt 函数后,系统就重启了。怀疑是否是传入的 gdt_pd 参数有问题,导致触发了 CPU 保护异常机制。打印该变量发现其数值不正常。
在这里插入图片描述
代码里是这样设置参数的,上面打印的操作有明显问题。

static struct segdesc gdt[] = {
    SEG_NULL,
    [SEG_KTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_KERNEL),
    [SEG_KDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_KERNEL),
    [SEG_UTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_USER),
    [SEG_UDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_USER),
    [SEG_TSS]    = SEG_NULL,
};

static struct pseudodesc gdt_pd = {
    sizeof(gdt) - 1, (uint32_t)gdt
};

于是怀疑是代码出现了内存覆写问题,把这个变量写坏了。重新调试 kernel,发现在刚进入 kern_init 时变量还是好的,结果紧接下面一句 memset(edata, 0, end - edata) 后,数值就被修改了。
在这里插入图片描述
于是查找 edataend 是什么。在 kernel.ld 中是这样写的,意思是希望用 edataend 来标记 bss 段的范围,然后在代码中将其清 0。

	/* The data segment */
	.data : {
		*(.data)
	}

	PROVIDE(edata = .);

	.bss : {
		*(.bss)
	}

	PROVIDE(end = .);

gdt_pd 变量是有初始化值的,不应该在 bss 范围内,使用 readelf -s 来查看符号地址就可以看到 gdt_pd 确实是被 edataend 包住了,所以是错误的。

在这里插入图片描述
使用 readelf -S 查看段信息
在这里插入图片描述

edata 标记的位置是 0x10f90,而 .got.plt 的起始地址也是 0x10f950。而在 0x10f950 后,bss 前还包含了 .got.plt, .data.rel.local, .data.rel.ro.local,这部分内容也会被错误清 0。由于 gdt_pd 是个 static 变量,他就位于 data.rel.local 里,所以就被修改了。

解决方法

需要 edataend 精确标记 .bss 的范围,不能包含其他的段,kernel.ld 修改如下
在这里插入图片描述

结果验证

修改完后再编译,就能看到正确结果了
在这里插入图片描述由于中断向量表尚未设置好,此时发生定时器中断还是错误重启。所以先注释掉启用中断的代码再运行,就不会再重启了。

int
kern_init(void) {
	// ....
    clock_init();               // init clock interrupt
    // intr_enable();              // enable irq interrupt
    while(1);
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值