首页 > 解决方案 > 链接器找不到外部引用

问题描述

我正在尝试遵循OS Dev Wiki 的 Bare Bones 教程。但是,当我尝试将所有内容链接在一起时,我的链接器(Cygwin Binutils)给了我以下错误:

boot.o: In function `start':
boot.asm:(.text+0x6): undefined reference to `kernmain'

当我运行命令时

i686-pc-cygwin-gcc -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib kernel.o boot.o -lgcc

以前,我认为kernel_main()入口点的标识符()kernel.c与其他一些重要的命名空间具有相同的标识符(根据我已经尝试过但没有工作的其他有点相似的答案)。

---编辑---这是源代码,尽管您可以使用 wiki 页面上的内容复制所有内容。

引导程序

MBALIGN equ 1 << 0
MEMINFO equ 1 << 0
FLAGS equ MBALIGN | MEMINFO
MAGIC equ 0x1BADB002                ;magic number tells cpu where to find the bootloader
CHECKSUM equ -(MAGIC + FLAGS)       ;checksum of above

section .multiboot
    dd MAGIC
    dd FLAGS
    dd CHECKSUM

section .bss
align 16
stack_bottom:
resb 16384 ;16 kilobytes
stack_top:

section .text
global _start:function (_start.end - _start)
_start:
    mov esp, stack_top

    [extern kernmain]
    call kernmain

    cli

.hang: hlt
    jmp .hang

.end:

内核.c

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

enum vga_color
{
    BLACK = 0,
    BLUE = 1,
    GREEN = 2,
    CYAN = 3,
    RED = 4,
    MAGENTA = 5,
    BROWN = 6,
    LIGHT_GREY = 7,
    DARK_GREY = 8,
    LIGHT_BLUE = 9,
    LIGHT_GREEN = 10,
    LIGHT_CYAN = 11,
    LIGHT_RED = 12,
    LIGHT_MAGENTA = 13,
    LIGHT_BROWN = 14,
    WHITE = 15
};

static inline uint8_t vga_entry_color(enum vga_color foreground, enum vga_color background)
{
    return foreground | background << 4;
}

static inline uint16_t vga_entry(unsigned char c, uint8_t color)
{
    return (uint16_t)c | (uint16_t)color << 8;
}

size_t strlen(const char* str)
{
    size_t len = 0;
    while (str[len])
    {
        len++;
    }
    return len;
}

static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;

size_t terminal_row;
size_t terminal_column;
uint8_t terminal_color;
uint16_t* terminal_buffer;

void terminal_initialize()
{
    terminal_row = 0;
    terminal_column = 0;
    terminal_color = vga_entry_color(WHITE, BLACK);
    terminal_buffer = (uint16_t*)0xB8000;
    for (size_t y = 0; y < VGA_HEIGHT; y++) {
        for (size_t x = 0; x < VGA_WIDTH; x++) {
            const size_t index = y * VGA_WIDTH + x;
            terminal_buffer[index] = vga_entry(' ', terminal_color);
        }
    }
}

void terminal_setcolor(uint8_t color)
{
    terminal_color = color;
}

void terminal_putentryat(char c, uint8_t color, size_t x, size_t y)
{
    const size_t index = y * VGA_WIDTH + x;
    terminal_buffer[index] = vga_entry(c, color);
}

void terminal_putchar(char c)
{
    terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
    if (++terminal_column == VGA_WIDTH) {
        terminal_column = 0;
        if (++terminal_row == VGA_HEIGHT)
            terminal_row = 0;
    }
}

void terminal_write(const char* data, size_t size)
{
    for (size_t i = 0; i < size; i++)
        if (data[i] == '\n')
        {
            terminal_row++;
        }
        else if (data[i] == '\r')
        {
            terminal_column = 0;
        }
        else 
        {
            terminal_putchar(data[i]);
        }
}

void terminal_writestring(const char* data)
{
    terminal_write(data, strlen(data));
}

void kernmain(void)
{
    terminal_initialize();

    terminal_writestring("Hello, kernel World!\nHere again");
}

链接器.ld

ENTRY(_start)

SECTIONS
{
    . = 1M;

    .text BLOCK(4K) : ALIGN(4K)
    {
        *(.multiboot)
        *(.text)
    }

    .rodata BLOCK(4K) : ALIGN(4K)
    {
        *(.rodata)
    }

    .data BLOCK(4K) : ALIGN(4K)
    {
        *(.data)
    }

    .bss BLOCK(4K) : ALIGN(4K)
    {
        *(COMMON)
        *(.bss)
    }
}

这是我运行来构建它的命令

nasm -f elf32 boot.asm -o boot.o
i686-pc-cygwin-gcc -c kernel.c -o kernel.o -std=gnu99 -ffreestanding -O2 -Wall -Wextra
i686-pc-cygwin-gcc -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib kernel.o boot.o -lgcc

标签: cassemblylinkercygwin

解决方案


推荐阅读