c - 如何通过将各自的部分放在不同的位置来链接两个目标文件?

标签 c assembly linker bootloader linker-scripts

我有一个引导加载程序“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 字节扇区中内核的长度。

关于c - 如何通过将各自的部分放在不同的位置来链接两个目标文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52457734/

相关文章:

c++ - 如何在不使用太多内存的情况下链接大量 C++ 目标文件?

c - 如何优雅地让一个阻塞的pthread从主线程退出?

assembly - 在 x86 程序集中添加 0xFFFFFFFF

c - 如何使用 gcc asm 关键字在寄存器中传递函数参数

linux - Linux 上的 CMake 和资源文件中的链接

opengl - GLEW 和 CodeBlcks 的链接器问题

c - 使用嵌套结构数组进行结构初始化

无法读取UART数据

c - GDI泄漏问题

assembly - 为什么 x86 和 ARM 之间的 GNU 语法不同?