自定义OS开发中,ISR0函数地址转int后值为0的问题求助
问题描述
我正在开发自定义操作系统,在设置IDT(中断描述符表)时,尝试通过&isr0获取ISR0函数的地址,核心代码如下:
// 示例函数 void isr0() { volatile uint8_t* ptr1 = (uint8_t*)(0xB8000); ptr1[0] = 'A'; } void main(){ int ptr = (int)&isr0; volatile uint8_t* ptr1 = (uint8_t*)0xB8000; int offset2 = 40; int value = (int)ptr; // 将地址以十进制形式输出到VGA缓冲区 ptr1[0 + offset2] = 48 + (value/100000) % 10; ptr1[2 + offset2] = 48 + (value/10000) % 10; ptr1[4 + offset2] = 48 + (value/1000) % 10; ptr1[6 + offset2] = 48 + (value/100) % 10; ptr1[8 + offset2] = 48 + (value/10) % 10; ptr1[10+ offset2] = 48 + (value/1) % 10; while(1); ... }
运行后Qemu窗口显示结果为000000,但在常规Linux机器上运行该代码能正常显示内存地址。此外发现调用该函数指针能正常工作,但将其转换为int类型时却得到0。
编译步骤:
i686-elf-gcc -nostdlib -O3 -ffreestanding -Wall -Wextra -m32 -c kernel.c -o bin/stage4.bin objcopy -O binary bin/stage4.bin bin/stage5.bin
引导加载相关文件为手写汇编的Stage1和Stage2,编译命令:
nasm stage1.asm -f bin -o bin/stage1.bin
镜像合并与运行命令:
cat bin/stage1.bin bin/stage2.bin bin/stage5.bin > bin/stage3.bin qemu-system-x86_64 -fda bin/stage3.bin -vga vmware -d guest_errors -m 64M >> bin/a 2>&1
原因分析与解决方案
核心原因
- 链接地址不匹配:引导加载程序(Stage2)会将内核加载到物理地址
0x100000处执行,但编译时使用了i686-elf-gcc的默认链接脚本,默认链接地址为0x0。编译器生成的函数地址是基于链接地址的偏移量,而非实际运行时的物理地址,因此&isr0被解析为链接时的偏移(若isr0是代码段第一个函数,偏移即为0)。 - 类型转换不安全:用
int存储指针地址存在风险,虽然32位环境下int通常为32位,但标准并未保证指针类型与int的长度一致,可能导致地址截断或解析错误。 - 优化导致的异常:开启
-O3优化后,编译器可能认为ptr和value未参与关键逻辑(仅用于显示),进而将其优化为0,但函数指针能正常调用说明函数本身的相对跳转逻辑未被破坏。
解决办法
编写自定义链接脚本
创建一个linker.ld文件,指定代码段的运行地址为引导加载程序加载内核的地址(即0x100000),示例内容如下:ENTRY(main) SECTIONS { . = 0x100000; .text ALIGN(4) : { *(.text) } .rodata ALIGN(4) : { *(.rodata) } .data ALIGN(4) : { *(.data) } .bss ALIGN(4) : { *(COMMON) *(.bss) } }编译时指定链接脚本:
i686-elf-gcc -nostdlib -O3 -ffreestanding -Wall -Wextra -m32 -T linker.ld kernel.c -o bin/stage4.bin使用正确的指针存储类型
替换代码中的int为uintptr_t(需包含头文件<stdint.h>),确保指针地址被正确存储:#include <stdint.h> ... uintptr_t ptr = (uintptr_t)&isr0; uintptr_t value = ptr;验证链接地址与加载地址一致性
可以通过objdump查看ELF文件的代码段地址,确认链接地址是否正确:i686-elf-objdump -h bin/stage4.bin检查
.text段的Addr字段是否为0x100000。临时关闭优化排查问题
若怀疑是优化导致的异常,可暂时将-O3改为-O0重新编译,观察地址是否能正常显示,待问题解决后再开启优化。
内容的提问来源于stack exchange,提问作者Stigl
相关产品推荐
相关产品推荐

