You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自制业余操作系统:保护模式下加载平二进制文件执行遇通用保护错误

问题排查与解决方案

核心原因分析

触发中断13(通用保护错误),大概率是以下几个问题导致:

1. 内存页可执行权限未配置

在保护模式(尤其是启用分页的场景下),如果0x600000所在的内存页未设置可执行权限,CPU尝试执行该地址代码时会直接触发GPF。你需要检查页表项的权限位,确保目标页的NX(禁止执行)位未被置位(x86-64架构),或者在32位x86模式下,页表项权限标记允许代码执行。

2. 函数包含位置相关代码

你的aa函数调用了printkc,编译生成的汇编指令大概率是相对跳转/调用(比如call printkc是基于当前指令指针的相对偏移)。当把函数复制到0x600000后,原本指向printkc的相对偏移会指向错误内存位置,执行非法操作触发GPF。

如果函数后续涉及全局变量访问,同样会因为相对寻址失效引发问题。

3. 函数长度估算错误

你手动指定了45字节的复制长度,但实际编译后的aa函数长度可能不等于45字节。若复制的指令不完整,执行到一半会遇到非法操作码,间接触发GPF。

具体修复步骤

  • 配置内存页权限:修改页表初始化代码,将0x600000所在页标记为可读、可写、可执行(内核态内存需符合内核段权限要求)。
  • 编译为位置无关代码(PIC):如果要动态加载执行代码,需将函数编译为位置无关代码。GCC中可添加-fPIC或-fpie编译选项,生成的指令会使用绝对寻址或基于寄存器的相对寻址,复制到任意地址都能正常执行。
  • 准确获取函数长度:通过objdump -d your_kernel.elf | grep -A 20 "aa:"查看汇编输出,统计aa函数的实际字节数;也可在链接脚本中定义函数起止符号,或用__attribute__((section("myfunc")))将函数放到单独段,通过段起止地址计算长度。
  • 检查段描述符:若未启用分页,需确认GDT中对应0x600000地址范围的段描述符,已设置代码可执行的类型属性。

举个编译位置无关代码的Makefile示例:

CFLAGS += -fPIC

内容的提问来源于stack exchange,提问作者Soubhik Biswas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 05:07:03