【问题标题】:Weird linker error gcc when following simple kernel tutorial遵循简单的内核教程时出现奇怪的链接器错误 gcc
【发布时间】:2012-03-21 19:16:05
【问题描述】:

我正在关注如何制作一个简单的可启动内核的教程:http://www.osdever.net/tutorials/view/writing-a-simple-c-kernel

教程中有以下必备文件:

内核.c 源代码:

#define WHITE_TXT 0x07 // white on black text

void k_clear_screen();
unsigned int k_printf(char *message, unsigned int line);


k_main() // like main in a normal C program
{
    k_clear_screen();
    k_printf("Hi!\nHow's this for a starter OS?", 0);
};

void k_clear_screen() // clear the entire text screen
{
    char *vidmem = (char *) 0xb8000;
    unsigned int i=0;
    while(i < (80*25*2))
    {
        vidmem[i]=' ';
        i++;
        vidmem[i]=WHITE_TXT;
        i++;
    };
};

unsigned int k_printf(char *message, unsigned int line) // the message and then the line #
{
    char *vidmem = (char *) 0xb8000;
    unsigned int i=0;

    i=(line*80*2);

    while(*message!=0)
    {
        if(*message=='\n') // check for a new line
        {
            line++;
            i=(line*80*2);
            *message++;
        } else {
            vidmem[i]=*message;
            *message++;
            i++;
            vidmem[i]=WHITE_TXT;
            i++;
        };
    };

    return(1);
};

kernel_start.asm 源代码:

[BITS 32]

[global start]
[extern _k_main] ; this is in the c file

start:
  call _k_main

  cli  ; stop interrupts
  hlt ; halt the CPU

链接.ld 源代码:

OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
  .text  0x100000 : {
    code = .; _code = .; __code = .;
    *(.text)
    . = ALIGN(4096);
  }
  .data  : {
    data = .; _data = .; __data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss  :
  {
    bss = .; _bss = .; __bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .; _end = .; __end = .;
}

编译说明如下:

nasm -f aout kernel_start.asm -o ks.o
gcc -c kernel.c -o kernel.o
ld -T link.ld -o kernel.bin ks.o kernel.o

我能够成功执行前两行:

nasm -f aout kernel_start.asm -o ks.o
gcc -c kernel.c -o kernel.o

然后当我尝试运行这一行时:

ld -T link.ld -o kernel.bin ks.o kernel.o

我得到错误:

C:\basic_kernel>ld -T link.ld -o kernel.bin ks.o kernel.o
ks.o: file not recognized: File format not recognized

有谁知道这是为什么以及如何解决这个问题? 我正在使用 Windows 7 64 位

【问题讨论】:

    标签: c gcc assembly kernel bootloader


    【解决方案1】:

    您需要将-f aout 更改为-f elf 才能链接生成的目标文件。

    现代链接器将期待 ELF 和/或 Windows PECOFF;您的显然无法识别过时的 a.out 对象文件格式。

    当没有使用 -f 选项给出格式时,NASM 默认为平面二进制模式,因此完全删除它不是您想要的。

    【讨论】:

      【解决方案2】:

      您的gccld 可能需要PECOFF 或ELF 目标文件,而不是a.out,它是旧的和过时的。尝试将 nasm 调用中的 -f aout 替换为 -f elf 用于 ELF32 .o-f win32 用于 PECOFF .obj

      (完全删除 -f 会为您提供默认的 -f bin 平面二进制文件,例如 .com 可执行文件或 MBR 引导扇区,而不是链接器输入。)


      如果这不起作用,请尝试将此文件命名为 ks.s,将其与 gcc ks.s -c -o ks.o 组合在一起,然后使用它而不是 ks.o / kernel_start.asm 你有:

          .text
          .code32
          .globl start
      start:
          call _k_main
          cli
          hlt
      

      警告:它没有出现在这个例子中,但是当你以这种方式编写程序集时使用的指令语法与你所期望的非常不同。 This SO question 指向指南的链接。使用 GAS 的 .intel_syntax noprefix 指令将提供与 NASM 不同的语法;它更像是 MASM。


      需要注意的其他问题:您很有可能在程序集中的符号_k_main 的开头有一个下划线。 C 中定义的所有符号开头的下划线是它在 a.out 中的工作方式,但在 ELF 中没有。我不知道PECOFF。

      【讨论】:

      • 如果我删除“-f aout”,我会得到错误:“kernel_start.asm:21: error: binary output format does not support external references”
      • 别介意第一条评论。当我尝试链接器行时,我得到这个:ld:无法对非 PE 输出文件“kernel.bin”执行 PE 操作。有什么想法吗?
      • 我的想法已经不多了,我自己从未尝试过这样做。如果您运行命令 gcc --versionas --versionld --version 并将输出添加到您的问题中,它可能会有所帮助。
      • @P'sao:默认输出格式为-f bin(平面二进制)。您可能需要 -f elf 用于 ELF 或 -f win32 用于 PECOFF。完全无法删除 -f
      • @PeterCordes 感谢您的更新。我自己从未使用过 NASM。我记得当我写这个问题时,我试图在其手册中查找其默认输出格式,但没有任何运气。
      【解决方案3】:

      我不使用 Windows,所以我不知道这将如何适用于您的问题,但我曾经在编译内核时遇到过同样的问题(ld 给了我相同的错误代码)。问题是我的代码是由 clang 编译的,而不是由我的工具链的 GCC 编译的,因此当我的工具链的 ld 试图链接它时,它无法读取目标文件,因为它们不是它所期望的格式.如果您没有使用 x86 工具链(交叉编译器),请使用其中一个并确保使用该工具链中包含的 GCC 来编译您的文件。

      【讨论】:

        【解决方案4】:

        将 kernel.asm 中的 _k_main 替换为 k_main,如下所示:

        [BITS 32] 
        
        [global start]
        [extern k_main] ; include the c kernel
        
        start:
            call k_main ; call the c kernel
        
            cli  ; stop interrupts
            hlt ; halt the CPU
        

        【讨论】:

        • BITS 32 不会通知 CPU,它会通知 汇编器 CPU 将处于哪种模式。将BITS 64 放在文件顶部不会在运行文件时使 CPU 切换到 64 位模式,它只会生成在 32 位模式下解码错误的 64 位机器代码(例如,如果您将其组装成 32 位可执行文件。)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-10
        • 2014-12-17
        • 1970-01-01
        • 2011-09-03
        • 1970-01-01
        • 2023-03-17
        • 1970-01-01
        相关资源
        最近更新 更多