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

OS开发中链接器报“file format not recognized”错误求助

问题排查与修复

问题背景

开发简易操作系统内核时,链接器先后出现两个错误:

  • 初始使用-f obj编译汇编文件时,报错file format not recognized
  • 改为-f elf后,报错undefined reference to main

代码文件

Makefile

BUILD?=build/
ASM?=nasm
ASMFLAGS?=-f obj
CC=i386-elf-gcc
LD=i386-elf-ld
CCFLAGS=-m32 -std=c11 -O2 -g -Wall -Wextra -Wpedantic -Wstrict-aliasing
CCFLAGS+=-Wno-pointer-arith -Wno-unused-parameter
CCFLAGS+=-nostdlib -nostdinc -ffreestanding -fno-pie -fno-stack-protector
CCFLAGS+=-fno-builtin-function -fno-builtin
LDFLAGS=

SOURCES_C=$(wildcard *.c)
SOURCES_ASM=$(wildcard *.asm)
OBJECTS_C=$(patsubst %.c,$(BUILD)/kernel/c/%.obj,$(SOURCES_C))
OBJECTS_ASM=$(patsubst %.asm,$(BUILD)/kernel/asm/%.obj,$(SOURCES_ASM))

all: kernel.bin

kernel.bin: $(OBJECTS_ASM) $(OBJECTS_C)
    $(LD) -o $(BUILD)/kernel.bin $< $(LDFLAGS) -Tlink.ld    

$(BUILD)/kernel/c/%.obj: %.c always
    $(CC) $(CCFLAGS) -o $@ $<

$(BUILD)/kernel/asm/%.obj: %.asm always
    $(ASM) $(ASMFLAGS) -o $@ $<

always:
    mkdir -p $(BUILD)/kernel/c
    mkdir -p $(BUILD)/kernel/asm

汇编代码

[bits    32]
[extern main]

section .text
global _start
_start:
    call main

C代码

void main(){
    volatile char* video_memory = (volatile char*)0xb800;
    *video_memory = 'X';
}

错误原因与修复方案

1. 目标文件格式不匹配

  • 原因:-f obj生成的是DOS/16位格式目标文件,与i386-elf工具链要求的ELF格式不兼容,导致链接器无法识别。
  • 修复:将ASMFLAGS改为-f elf32(明确指定32位ELF格式,匹配32位内核):
    ASMFLAGS?=-f elf32
    

2. 链接时遗漏C目标文件

  • 原因:链接命令中使用$<仅传入了第一个依赖文件(汇编目标),未包含C目标文件,导致链接器找不到main的实现。
  • 修复:将链接命令中的$<替换为$^(代表所有依赖文件):
    kernel.bin: $(OBJECTS_ASM) $(OBJECTS_C)
        $(LD) -o $(BUILD)/kernel.bin $^ $(LDFLAGS) -Tlink.ld    
    

3. C编译未生成目标文件

  • 原因:当前C编译命令缺少-c参数,gcc会直接尝试生成可执行文件而非纯目标文件,导致生成的.obj文件格式错误。
  • 修复:在C编译规则中添加-c参数:
    $(BUILD)/kernel/c/%.obj: %.c always
        $(CC) $(CCFLAGS) -c -o $@ $<
    

4. C函数名的下划线前缀问题

  • 原因:i386-elf-gcc默认会给C函数名添加下划线前缀(如main会被编译为_main),但汇编代码中引用的是main,导致符号不匹配。
  • 修复(二选一):
    • 修改汇编代码,引用带下划线的符号:
      [extern _main]
      ...
      call _main
      
    • 或在C编译参数中添加-fno-leading-underscore,关闭下划线前缀行为:
      CCFLAGS+=-fno-leading-underscore
      

内容的提问来源于stack exchange,提问作者neta cohen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 18:13:25