遵循简单的内核教程时奇怪的链接器错误gcc

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了遵循简单的内核教程时奇怪的链接器错误gcc相关的知识,希望对你有一定的参考价值。

我按照本教程介绍如何制作一个简单的可启动内核:http://www.osdever.net/tutorials/view/writing-a-simple-c-kernel

本教程中有以下必需文件:

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!
How'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=='
') // 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

link.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:asic_kernel>ld -T link.ld -o kernel.bin ks.o kernel.o
ks.o: file not recognized: File format not recognized

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

答案

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

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

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

另一答案

您的gccld可能期望PECOFF或ELF目标文件,而不是a.out,这是旧的和过时的。尝试用-f aout替换你的nasm调用中的-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。

另一答案

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

另一答案

在kernel.asm中用k_main替​​换_k_main,如下所示:

[BITS 32] ; inform the processor of 32 bits mode program

[global start]
[extern k_main] ; include the c kernel

start:
    call k_main ; call the c kernel

    cli  ; stop interrupts
    hlt ; halt the CPU

以上是关于遵循简单的内核教程时奇怪的链接器错误gcc的主要内容,如果未能解决你的问题,请参考以下文章

链接时gcc可以使用多个内核吗?

奇怪的链接器错误

构建时的链接器符号算术计算错误的结果

非常奇怪的链接器行为

Linux 运行时链接器错误

将弱符号和局部符号链接在一起时,可能的 GCC 链接器错误会导致错误