X86_64汇编内核开发:R_X86_64_16重定位截断错误的解决求助
解决X86_64内核汇编中的R_X86_64_16重定位截断错误
这个错误的核心原因很明确:你在64位内核代码里使用了16位的寻址操作,导致链接器无法将64位的string地址塞进16位的寄存器/偏移量里。下面是具体的修复步骤和解释:
1. 替换16位寄存器为64位寄存器
你的print_string函数里用了mov si, string,si是16位寄存器,而在x86_64长模式下,.rodata段的string是一个64位地址(通常会被链接到高内存区域,远大于16位能表示的范围),所以链接器会报错"relocation truncated to fit"。
把这一行改成64位寄存器rsi即可:
mov rsi, string ; 用64位寄存器存储64位地址
lodsb指令在64位模式下默认会使用rsi作为源地址寄存器(配合cld的方向标志),所以不需要额外修改这条指令,它会正常从rsi指向的地址加载字节到al中。
2. 优化汇编命令参数(可选但推荐)
你的YASM命令里--arch=x86可以明确改为--arch=x86_64,虽然--machine=amd64已经指定了64位模式,但这样更清晰,避免歧义:
yasm --arch=x86_64 --oformat=elf64 --machine=amd64 boot.S -o boot.o
3. 链接脚本的注意事项(如果问题仍存在)
虽然上述修改应该能解决你的问题,但如果链接脚本把.rodata或其他段放在了超出16位地址范围的区域(不过x86_64内核本来就会用高地址),也可能触发类似错误。如果修改寄存器后还是报错,可以提供你的链接脚本,我可以帮你进一步排查。
修改后的完整代码
section .text global _start _start: call print_string .inf_loop: hlt jmp .inf_loop print_string: cld mov rsi, string .loop: lodsb cmp al, BYTE 0 je .done out 0xe9, al jmp .loop .done: ret ; The stivale header our kernel needs to be booted via limine section .stivale2hdr ; This is set to zero, so the bootloader will use the elf entry point entry_point: dq 0 ; This tells the bootloader where our stack is ; Remember the stack grows downwards :) stack: dq this_is_the_stack+8192 flags: dq 011b tags: dq 0 section .bss align 16 this_is_the_stack: resb 8192 section .rodata string: db "Hello, world!", 0
简单总结:x86_64长模式下必须使用64位寄存器来处理内存地址,16位寄存器只适用于实模式或保护模式下的低内存操作,完全不适合现代64位内核的内存布局。
内容的提问来源于stack exchange,提问作者f566f6d
相关产品推荐
相关产品推荐

