AS汇编器undefined label错误:GDT初始化相关符号未定义
OS开发GDT初始化链接错误排查与解决
问题背景
在OS开发过程中,初始化GDT时遇到链接错误,相关代码、编译命令及错误信息如下:
相关代码
boot.s 代码
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */ .set MEMINFO, 1<<1 /* provide memory map */ .set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */ .set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */ .set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */ .section .multiboot .align 4 .long MAGIC .long FLAGS .long CHECKSUM .section .bss .align 16 stack_bottom: .skip 16384 # 16 KiB stack_top: .section .text .global _start .type _start, @function _start: mov $stack_top, %esp # setup GDT cli xor %ax, %ax mov %ds, %ax lgdt gdt_desc sti call kernel_main cli 1: hlt jmp 1b .size _start, . - _start
gdt.s 代码
.global gdt .global gdt_null .global gdt_code .global gdt_data .global gdt_end .global gtd_desc gdt: gdt_null: .8byte 0 gdt_code: .2byte 0xFFFF .2byte 0x0000 .byte 0 .byte 0b10011010 .byte 0b11001111 .byte 0 gdt_data: .2byte 0xFFFF .2byte 0 .byte 0 .byte 0b10010010 .byte 0b11001111 .byte 0 gtd_end: gtd_desc: .2byte gdt_end - gdt .2byte gdt
链接脚本 linker.ld
ENTRY(_start) SECTIONS { . = 1M; .text BLOCK(4K) : ALIGN(4K) { *(.multiboot) *(.text) } /* Read-only data. */ .rodata BLOCK(4K) : ALIGN(4K) { *(.rodata) } /* Read-write data (initialized) */ .data BLOCK(4K) : ALIGN(4K) { *(.data) } /* Read-write data (uninitialized) and stack */ .bss BLOCK(4K) : ALIGN(4K) { *(COMMON) *(.bss) } }
编译链接命令
as --32 boot.s -o boot.o as --32 gdt.s -o gdt.o g++ -m32 -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib boot.o kernel.o gdt.o -lgcc
链接错误信息
/usr/bin/ld: boot.o: in function `_start': (.text+0xf): undefined reference to `gdt_desc' /usr/bin/ld: gdt.o: in function `gtd_end': (.text+0x18): undefined reference to `gdt_end' (.text+0x18): relocation truncated to fit: R_386_PC8 against undefined symbol `gdt_end' (.text+0x19): relocation truncated to fit: R_386_16 against `.text'
错误原因与解决方法
1. 符号拼写错误
- boot.s中引用的是
gdt_desc,但gdt.s里定义的全局符号是gtd_desc(拼写少了一个t),导致未定义引用。 - gdt.s中计算GDT长度时用了
gdt_end,但实际定义的结束标签是gtd_end,同样拼写错误。
修正方案:
修改gdt.s中的符号名,保持一致:
.global gdt .global gdt_null .global gdt_code .global gdt_data .global gdt_end .global gdt_desc // 修正为gdt_desc gdt: // ... 中间GDT项代码不变 ... gdt_end: // 修正为gdt_end gdt_desc: // 修正为gdt_desc .2byte gdt_end - gdt .4byte gdt // 此处同时修正基地址长度
2. GDT描述符基地址长度错误
原gdt.s中用.2byte gdt存储GDT基地址,但32位模式下GDT描述符的基地址是32位,必须用4字节存储,否则会截断地址,引发 relocation 错误。
修正方案:
将.2byte gdt改为.4byte gdt,确保基地址完整。
3. (可选)将GDT放入只读数据段
当前GDT默认放在.text段,可将其移至.rodata段(只读数据段),更符合数据属性:
在gdt.s开头添加.section .rodata:
.section .rodata .global gdt .global gdt_null .global gdt_code .global gdt_data .global gdt_end .global gdt_desc gdt: // ... 后续代码不变 ...
修正后重新编译链接即可解决所有错误。
内容的提问来源于stack exchange,提问作者lowlevellarry
相关产品推荐
相关产品推荐

