我在嵌入式系统中使用了一个有效的二进制文件。现在我想为它写一些补丁。补丁将被加载到主程序下面的RAM中,然后从主程序调用。问题是如何告诉gcc使用将从补丁中使用的某些函数的手动设置地址。换一种说法:
旧代码具有函数sin()
,我可以使用nm来查找旧代码中sin()
的地址。我的修补代码将使用sin()
(或主程序中的其他内容),我想告诉gcc(或者ld或者其他东西),它可以使用函数sin()
的静态地址。链接修补的代码。可能吗?
答案 0 :(得分:0)
问题在于,您可以替换修补代码的原始sin()
函数的所有引用。这将要求运行时系统包含所有用于解析引用的目标代码数据,以及原始代码可以修改(例如,不在ROM中)。
Windriver的RTOS VxWorks可以做一些接近你的建议; it 的方式是你使用“部分链接”(GNU链接器选项-r
)生成一个目标文件,其中包含将在运行时解析的链接 - 这允许一个目标文件使用未解析的链接创建 - 即不完整的可执行文件。 VxWorks本身包含一个加载器和运行时“链接器”,可以动态加载部分链接的目标文件并解析引用。但是,加载的目标文件必须完全可以使用已加载的对象代码进行解析 - 因此没有循环依赖关系,并且在您的示例中,您必须重新加载/重新启动系统,以便加载包含sin()
的目标文件之前引用它的那些,否则只有那些之后加载的才会使用新的实现。
因此,如果你要使用VxWorks(或具有类似功能的操作系统),解决方案可能很简单,如果不是,你必须实现自己的加载器/链接器,这当然是可能的,但不是微不足道的。
另一种可能更简单的可能性是通过变量中的指针调用所有代码调用函数,以便在运行时解析所有调用(或至少所有可能要替换的调用)。您必须加载补丁然后修改sin()
函数的指针,以便之后的所有调用都对新函数进行。这种方法的问题在于你要么必须知道先验你可能以后想要替换哪些函数,要么让所有函数都以这种方式调用(在内存方面这可能过于昂贵。也许对于这个解决方案有用,可以使用某种预处理器或代码生成器来标记以这种方式“动态”的函数,并自动生成指针和调用代码。例如,您可以编写代码:
__dynamic void myFunction( void ) ;
...
myFunction() ;
并且您的自定义预处理器将生成:
void myFunction( void ) ;
void (*__dynamic_myFunction)(void) = myFunction() ;
...
__dynamic_myFunction() ;
然后你的补丁/加载程序代码会将myFunctionDyn重新分配给替换函数的地址。
您可以生成一个“动态符号表”,其中只包含__dynamic_xxxxx符号的名称和地址,并在您的应用程序中包含该符号,以便加载程序可以通过将xxxxx名称与加载的目标文件中的符号相匹配来更改__dynamic_xxxxx变量 - 如果加载普通二进制文件,则必须向加载程序提供链接信息 - 即要重新分配的__dynamic_xxxxx变量和分配给它的地址。