我有一种情况需要将第三方静态库的函数调用插入iOS系统框架(共享库)。静态库供应商提供的具有成本效益或及时维护支持的可能性很小甚至不存在。
实际上改变了来自:
的呼叫序列+-------------+ +-------------+ +---------------------+
| Application | ---> | libVendor.a | ----> | FrameworkA (.dylib) |
+-------------+ +-------------+ +---------------------+
到:
+-------------+ +-------------+ +------------+ +---------------------+
| Application | ---> | libVendor.a | ----> | Interposer | ----> | FrameworkA (.dylib) |
+-------------+ +-------------+ +------------+ +---------------------+
此问题的正统解决方案是说服运行时链接程序加载不同的库代替FrameworkA
或加载库dlopen()
。这些都不是iOS上的选项。
一个有效的解决方案是使用sed
重命名libVendor.a
符号表中的符号。
假设我要在FrameworkA_Foo()
中的函数FrameworkA
中插入libVendor.a
来调用sed s/FrameworkA_Foo/InterposeA_Foo/g < libVendor.a > libInterposedVendor.a
:
void InterposeA_Foo()
{
// do some stuff here
// ....
// then (maybe) forward
FrameworkA_Foo();
}
然后介入:
libVendor.a
只要符号名称的长度保持不变,这就可以正常工作。
虽然这种方法有效,但它缺乏优雅感,并且感觉相当hacky。有更好的解决方案吗?
考虑的其他方法:
lld
而不是框架:Apple的链接器(与大多数UNIX平台上的链接器不同)以递归方式解析库中的符号,以及它们在库中的顺序命令行没什么区别)clang
[为清楚起见,这是C(而不是Objective-c)API,工具链是{{1}} / LLVM。由于弃用和缺乏C ++ 11支持,使用Apple提供的GCC不是一个选项]