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

编译可执行文件遇链接错误:boot.asm中main未定义引用

链接错误:undefined reference to `main' 解决方法

问题背景

我有kernel.c和boot.asm两个文件,内容如下:

boot.asm

[bits 32]

section .text
    align 4
    dd 0x1BADB002
    dd 0x00
    dd - (0x1BADB002 + 0x00)

global start

extern main

start:
    cli
    mov esp, stack_space
    jmp main

    hlt

stack_space:

kernel.c

char *vidmem = (char*)0xb8000; //змінна для відео пам'яті

void printString(void){
    const char *nameOS = "Welcome to CyberDOS";
    unsigned int i = 0, j = 0;
    while (nameOS[j] != '\0'){
        vidmem[i] = nameOS[j];
        vidmem[i+1] = 0x07;
        ++j;
        i += 2;

    }
}
void clearScreen(){
    unsigned int i = 0, j = 0;

    while (j < 80 * 25 * 2){//резервуємо 25 рядків по 80 символів
        vidmem[j] = ' ';
        vidmem[j+1] = 0x07;
        j += 2;
    }
    j = 0;
}   
void main(void){
    clearScreen();
    printString();
}

我用以下命令编译链接:

cd C:\Users\Ukraine\AppData\Local\bin\NASM
nasm -f elf32 C:\Users\Ukraine\Documents\Test\boot.asm -o C:\Users\Ukraine\Documents\Test\output\boot.o
gcc -m32 -c C:\Users\Ukraine\Documents\Test\kernel\kernel.c -o C:\Users\Ukraine\Documents\Test\output\kernel.o
cd C:\Users\Ukraine\Documents\Test\output

gcc -m32 -o kernel.exe -Wl,-e,start boot.o kernel.o
objcopy -O elf32-i386 C:\Users\Ukraine\Documents\Test\output\kernel.exe C:\Users\Ukraine\Documents\Test\output\kernel.elf
cd C:/Program Files/qemu/qemu-system-i386 -output output
cd C:\Users\Ukraine\Documents\Test
pause

执行后出现链接错误:

C:\Users\Ukraine\Documents\Test\output>gcc -m32 -o kernel.exe -Wl,-e,start boot.o kernel.o
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: boot.o: in function `start':
C:\Users\Ukraine\Documents\Test\boot.asm:(.text+0x13): undefined reference to `main'
collect2.exe: error: ld returned 1 exit status

我知道问题和extern语句有关,但找不到具体问题,求解决这个链接错误。

解决方案

问题根源

GCC编译C代码时,会自动给C函数名添加下划线前缀(C语言的名称修饰规则)。你在boot.asm中声明extern main,但实际编译后main函数的符号名是_main,链接器找不到main符号所以报错。

修复方法

有两种可行的修复方式:

方式1:修改汇编文件的符号引用

将boot.asm中的extern main改为extern _main,同时把jmp main改成jmp _main,修改后的代码如下:

[bits 32]

section .text
    align 4
    dd 0x1BADB002
    dd 0x00
    dd - (0x1BADB002 + 0x00)

global start

extern _main

start:
    cli
    mov esp, stack_space
    jmp _main

    hlt

stack_space:

方式2:编译C代码时禁用下划线前缀

编译kernel.c时添加-fno-leading-underscore参数,让编译器不给C函数名加下划线:

gcc -m32 -c -fno-leading-underscore C:\Users\Ukraine\Documents\Test\kernel\kernel.c -o C:\Users\Ukraine\Documents\Test\output\kernel.o

额外优化提示

  1. 你的汇编代码中stack_space只是一个标签,没有分配实际栈空间,运行时可能出现栈溢出问题,建议添加栈空间分配:
stack_space:
    resb 8192  ; 分配8KB栈空间
  1. 当前命令先生成PE格式的kernel.exe再转成ELF,其实可以直接用ld生成ELF文件,避免格式转换问题:
ld -m elf_i386 -Ttext 0x100000 -o kernel.elf boot.o kernel.o

(-Ttext 0x100000指定代码段加载地址,符合Multiboot规范的常见地址)

内容的提问来源于stack exchange,提问作者Dmitriy Parkhomenko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 22:08:30