【发布时间】:2013-09-10 07:36:10
【问题描述】:
我正在尝试编写自己的加载程序。在这个程序中,我将程序复制到RAM中的特定地址,并通过读取elf的入口点跳转到入口点地址。但是,我无法理解加载程序地址是什么?这是否意味着二进制文件只需要在编译时指定的加载器地址处复制。我不能将程序加载到其他位置而不是编译期间指定的加载地址吗?我的基本问题如下,“我不能将程序加载到其他位置而不是编译时指定的加载地址吗?”
【问题讨论】:
标签: c bootloader
我正在尝试编写自己的加载程序。在这个程序中,我将程序复制到RAM中的特定地址,并通过读取elf的入口点跳转到入口点地址。但是,我无法理解加载程序地址是什么?这是否意味着二进制文件只需要在编译时指定的加载器地址处复制。我不能将程序加载到其他位置而不是编译期间指定的加载地址吗?我的基本问题如下,“我不能将程序加载到其他位置而不是编译时指定的加载地址吗?”
【问题讨论】:
标签: c bootloader
没错。
完全链接的 ELF 程序不包含允许您在将程序加载到不同地址后修复引用的重定位信息。
使用链接器的-Ur 选项(或适当的链接器脚本),您可以生成带有重定位的ELF 文件——不过,为这些文件编写加载器更加困难。
【讨论】:
你有没有机会瞄准 ARM?
您的问题的解决方案是 PIC/PIE(位置无关代码/可执行文件)。这样,程序编译如下:
这样,程序在代码中的任何地方都不包含绝对地址。它在代码中也没有重定位。唯一需要的重新定位是 GOT 本身的放置。
GOT 是一个包含所有全局对象、函数和数据的地址的表。在非 PIC 代码中,数据的绝对地址直接嵌入在代码中。该函数需要知道特定对象对应的GOT表地址和GOT表中的条目号。对象编号是嵌入 PIC 代码中的唯一内容。 GOT 地址通过我遇到的两种方式之一提供给函数:附加在函数体末尾或预定义 CPU 寄存器中的重定位。我发现后一种选择更好。
如果您有最初加载程序的内存映射 ROM,并且您希望将其复制到 RAM 以加快速度并允许修改数据,则 PIC 非常有用。
请注意,您可以在没有 PIC 的情况下完成上述所有操作,只是更麻烦。您将在代码中进行大量重定位(如果 PIC 移动函数代码是一个简单的 memcpy 问题)并且您必须一次复制所有数据块(正确编写的 PIC 可执行文件允许在不同的内存区域)。
如果你好奇,那么我可以给你发一些我的 ARM 架构的链接器脚本。
【讨论】: