手动设置函数地址 gcc
Posted
技术标签:
【中文标题】手动设置函数地址 gcc【英文标题】:manually setting function address gcc 【发布时间】:2013-03-31 17:29:24 【问题描述】:我有一个用于嵌入式系统的工作二进制文件。现在我想为它写一个补丁。补丁将被加载到主程序下方的 RAM 中,然后将从主程序中调用。问题是如何告诉 gcc 使用将从补丁中使用的某些函数的手动设置地址。换句话说:
旧代码具有sin()
功能,我可以使用 nm 找出旧代码中sin()
的地址。我的补丁代码将使用sin()
(或来自主程序的其他东西),我想告诉gcc(或者可能是ld或其他东西)在链接补丁代码时使用函数sin()
的静态地址.是否可以?
【问题讨论】:
binary
图像无法做到这一点。你如何在上面运行nm
?你确定你的意思是binary
?
如果确实是binary
,最好的方法是修补原始sin()
以跳转到您的变体。这稍微慢一些。如果您的 sin()
较小,您可以直接覆盖它。
对不起。你当然是对的。我有一个二进制文件,但可以从未剥离的精灵中找出函数地址。
【参考方案1】:
问题在于,您将替换所有对原始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 变量以及要分配给它的地址。
【讨论】:
感谢您的回答。您使用的是什么版本的 VxWorks?我想使用 GCC(或类似的东西)解决所有参考。因为我有原始的 partialimage.o 和真正的旧地址(对于整个系统来说都是实际的)和我想以某种方式链接的 patch.o(或者说“使用来自 partialimage.o 的函数地址”)与 partialimage .o.然后我想使用 objcopy 剥离它,然后将生成的二进制文件加载到系统中。 上次我使用 VxWorks(很久以前)我认为是 v5.4,并使用了 Windriver 定制版本的 GCC,它也很旧。在我使用它开发的系统中,除了内核本身之外,整个应用程序由许多在运行时从文件系统加载的目标文件组成。可能不是你要找的。但是,对于普通的静态链接,目标文件中的符号会覆盖库存档中的符号,因此如果原始sin()
在库中,并且在目标文件中进行替换,则将使用替换。
好的。您能简要描述一下您是如何编写系统的吗?有没有特殊的 vxworks 模块?
正如我所说,那是很久以前的事了,在另一份工作中,所以我无法访问代码。但是它可以通过 Tornado 环境配置工具进行配置,需要目标 shell 和加载器模块,并且系统模块是通过目标 shell 命令脚本加载的。以上是关于手动设置函数地址 gcc的主要内容,如果未能解决你的问题,请参考以下文章
从零开始学习音视频编程技术 开发环境搭建(Qt4.86手动设置环境,主要就是设置g++和qmake,比较透彻,附下载链接)