如何通过将两个文件分别放在不同的位置来链接两个文件?

时间:2018-09-22 14:41:12

标签: c assembly linker bootloader linker-scripts

我有一个引导加载程序“ boot.asm”,该程序必须包含一个特殊字,该字距开头的位置为510个字节。而且我有一个用C“ kernel.c”编写的内核源代码。

我的计划是通过从引导加载程序加载硬盘的第二个扇区并将其放在内存中的0x8000位置来调用内核(将在hd的第二个扇区中)。

现在,我将两个源文件都分别编译成ELF目标文件,分别编译成“ boot.o”和“ kernel.o”,然后通过链接器链接它们,并输出原始二进制文件“ kernel.bin”。 / p>

我想将我的引导程序代码从0x7c00开始,然后在0x7dfe位置,我必须输入特殊的词。然后在0x8000,我必须放置我的内核代码。即我想将两个目标文件的各个部分放在不同的位置。

这是我失败的尝试。

ENTRY(boot)
OUTPUT_FORMAT("binary")

SECTIONS{
  . = 0x7c00;
  .text :
  {
    *(.boot)
  }

  .sig : AT(0x7dfe){
     SHORT(0xaa55);
  }

  . = 0x8000;

  .text :
  {
    kernel.o(.text)
  }

  .rodata :
  {
    kernel.o(.rodata)
  }

  .data :
  {
    kernel.o(.data)
  }

  .bss :
  {
    kernel.o(.bss)
  }

}

我了解的是,一个可执行文件最多只能有一个部分。

我对底层编程的了解有限。

我该如何解决此问题。 谢谢。

1 个答案:

答案 0 :(得分:3)

您需要修复两件事,不要拆分.text输出部分,并使用AT()将内核立即放在输出二进制文件中的引导扇区之后,同时将其地址保持在0x8000。例如,类似这样的链接描述文件应该起作用:

ENTRY(boot)
OUTPUT_FORMAT("binary")

SECTIONS {
  . = 0x7c00;
  .boot :
  {
    *(.boot)
  }

  . = 0x7dfe;
  .sig : {
     SHORT(0xaa55);
  }

  . = 0x8000;
  .kernel : AT(0x7e00)  /* place immediately after the boot sector */
  {
    *(.text)
    *(.rodata)
    *(.data)
    _bss_start = .;
    *(.bss)
    *(COMMON)
    _bss_end = .;
  }
  kernel_sectors = (SIZEOF(.kernel) + 511) / 512;

  /DISCARD/ : {
        *(.eh_frame)
  }
}

我添加了一些东西来处理您将在GCC编译的目标文件中看到的部分。 _bss_start_bss_end符号可用于将.bss部分归零,并且根据Michael Petch的建议,kernel_sector符号设置为512字节的内核长度部门。