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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 16:57:33