【问题标题】:Place a function at very start of binary将函数放在二进制文件的开头
【发布时间】:2013-06-29 17:32:49
【问题描述】:

我正在开发一个玩具操作系统和引导加载程序。我正在尝试用 C 编写内核,然后将其转换为二进制文件以便从引导加载程序直接跳转(即,我没有加载 ELF 或类似的东西)。

我已经设置了正确来源的链接器文件(我正在将内核加载到地址 0xC0000000)并通过objdump 确认它正在正确使用它。但是,它并没有像我想要的那样将我的入口点放在开头(0xC0000000)。我猜这不是 ENTRY 指令的用途。

我的问题只是我想在地址 0xC0000000 处放置一个特定的函数 kernel_main。有没有办法使用 gcc 进行编译和链接来完成此操作?

我的链接器文件的相关部分如下所示:

ENTRY(kernel_main)

SECTIONS
{
   /* Origin */
   . = 0xC0000000;

   .text BLOCK(4K) : ALIGN(4K)
   {
       *(.text)
   }
   /* etc. */
}

【问题讨论】:

    标签: c gcc linker


    【解决方案1】:

    ENTRY 链接器命令告诉链接器加载程序在加载程序时应该跳转到哪个符号。如果您正在制作自己的操作系统,因为没有加载器,所以它真的没有被使用。

    相反,如您所知,程序只是从第一个代码地址开始。

    要先放置一段特殊的代码,你可以把它放在一个特殊的代码段中,然后放在列表的最前面:

    .text BLOCK(4K) : ALIGN(4K)
    {
        *(.text.boot) *(.text)
    }
    

    列表中的段按给定的顺序放置。

    【讨论】:

    • 谢谢,这是一个很好的解决方案。我测试了它,它工作正常。我选择 Drew 的答案的唯一原因是因为这依赖于编译器特定的语法来将函数分配给段。在我看来,Drew 的回答更加通用和简洁,但两者似乎都可以正常工作。
    【解决方案2】:

    ENTRY 指令仅对支持入口点的输出格式有用。由于您使用的是二进制输出,因此这是行不通的。您可以做的是在单独的源文件中编写一个小存根(即entry.centry.asm 或其他)。然后,在ld 脚本中,在*(.text) 行之前,您可以放置​​entry.o(.text)。这指示ld 从特定目标文件加载符号(而* 表示所有目标文件)。所以新的ld 脚本看起来像这样: ENTRY(kernel_main)

    SECTIONS
    {
       /* Origin */
      . = 0xC0000000;
    
       .text BLOCK(4K) : ALIGN(4K)
       {
           entry.o(.text)
           *(.text)
       }
       /* etc. */
    }
    

    只要entry.o 只包含一个函数(简单地调用您的内核主函数),这应该可以工作。

    【讨论】:

    • 非常好,谢谢。我对此进行了测试,它似乎工作正常。
    猜你喜欢
    • 2010-09-29
    • 2017-05-08
    • 1970-01-01
    • 2017-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多