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

链接i686-elf目标文件时ld报R_386_16截断错误求助

问题

我使用nasm编译以下汇编代码,并将其与其他i686-elf输出文件进行链接:

global x86_Video_GetVbeInfo
x86_Video_GetVbeInfo:

    ; make new call frame
    push ebp             ; save old call frame
    mov ebp, esp          ; initialize new call frame

    x86_EnterRealMode

    ; save modified regs
    push edi
    push es
    push ebp                ; bochs vbe changes ebp

    ; call interrupt
    mov ax, 0x4f00
    LinearToSegOffset [bp + 8], es, edi, di
    int 10h

    ; check return
    cmp al, 4fh
    jne .error
    
    ; put status in eax
    mov al, ah
    and eax, 0xFF
    jmp .cont

.error:
    mov eax, -1

.cont:
    ; restore regs
    pop ebp                ; bochs vbe changes ebp
    pop es
    pop ebx

    push eax

    x86_EnterProtectedMode

    pop eax

    ; restore old call frame
    mov esp, ebp
    pop ebp
    ret

链接命令:

i686-elf-ld -T ../src/linker.ld -o ../binary/isolation/rcmiracle.bin -ffreestanding -O2 -nostdlib ../binary/compiler_out/x86.o ../binary/compiler_out/boot.o ../binary/compiler_out/kernel.o -lgcc

nasm编译无错误,但ld出现如下错误:

../binary/compiler_out/x86.o: in function `x86_Video_GetVbeInfo':
../src/x86.asm:(.text+0x44): relocation truncated to fit: R_386_16 against `.text'
../binary/compiler_out/x86.o: in function `x86_Video_GetVbeInfo.pmode16':
../src/x86.asm:(.text+0x51): relocation truncated to fit: R_386_16 against `.text'

修改链接脚本后问题仍未解决,求解决思路。

解决思路

这个错误的核心原因是:16位重定位无法适配32位段地址。你的代码位于32位保护模式段中,但x86_EnterRealMode、x86_EnterProtectedMode这类模式切换宏的实现里,大概率使用了16位的跳转或地址引用操作,而链接器检测到.text段的地址超出了16位能容纳的范围(即高于0xFFFF),因此触发截断错误。

具体修复步骤:

  • 排查模式切换宏的实现:打开定义x86_EnterRealMode和x86_EnterProtectedMode的文件,检查是否存在jmp .pmode16这类16位段内跳转,或是直接引用了32位地址的低16位部分。这类操作在段地址高于0xFFFF时必然失效。
  • 将模式切换代码隔离到16位兼容段:在汇编代码中单独声明一个16位代码段,比如用nasm的section .text16 align=16指令,然后把模式切换的核心逻辑移到这个段中。同时在链接脚本里将该段映射到0~0xFFFF范围内的地址空间。
  • 调整链接脚本的段布局:确保包含模式切换代码的段被放置在低16位地址空间(虚拟地址小于0x10000)。如果你的链接脚本中.text段的起始地址过高(比如0xC0000000这类内核高地址),16位重定位肯定无法正常工作。
  • 使用正确的指令集前缀与跳转方式:如果必须在32位段内执行16位代码,需要用bits 16前缀临时切换指令集,跳转时使用远跳转(far jump)明确指定16位段选择子,避免链接器生成错误的16位重定位项。
  • 修正寄存器栈平衡错误:注意到代码中pop ebx对应的是之前的push edi,这会导致寄存器栈不平衡,引发后续未知问题,需先将其修正为pop edi。

内容的提问来源于stack exchange,提问作者Lâm Bảo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 07:47:27