如何 link 将两个目标文件的各个部分放在不同的位置?

How to link two object files by placing their respective sections at different locations?

我有一个引导加载程序 "boot.asm",它必须包含一个特殊字,位于距开头 510 字节的偏移量处。我有一个用 C "kernel.c".

编写的内核源代码

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

现在我将两个源文件编译成 ELF 目标文件(分别)到 "boot.o" 和 "kernel.o",然后通过链接器链接它们并输出原始二进制文件 "kernel.bin" .

我想将我的引导加载程序代码从 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)
  }

}

我的理解是,一个可执行文件不能有多个部分。

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

我该如何解决这个问题。 谢谢。

您需要修复两件事,不要拆分 .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 字节长度扇区。