我有为多个CPU编写的性能关键代码.我在运行时检测CPU,并根据检测到的CPU使用适当的函数.所以,现在我必须使用函数指针并使用这些函数指针调用函数:
void do_something_neon(void);
void do_something_armv6(void);
void (*do_something)(void);
if(cpu == NEON) {
do_something = do_something_neon;
}else{
do_something = do_something_armv6;
}
//Use function pointer:
do_something();
...
Run Code Online (Sandbox Code Playgroud)
这并不重要,但我会提到我已经针对不同的cpu优化了功能:armv6和armv7以及NEON支持.问题是通过在许多地方使用函数指针,代码变得更慢,我想避免这个问题.
基本上,在加载时,链接器使用函数地址解析relocs和patch代码.有没有办法更好地控制这种行为?
就个人而言,我提出了两种避免函数指针的方法:为cpu依赖函数创建两个独立的.so(或.dll),将它们放在不同的文件夹中,并根据检测到的CPU将这些文件夹中的一个添加到搜索路径中(或者LD_LIB_PATH).加载主代码和动态链接器将从搜索路径中获取所需的dll.另一种方法是编译两个独立的库副本:)第一种方法的缺点是它迫使我至少有3个共享对象(dll):两个用于cpu依赖函数,一个用于使用它们的主代码.我需要3,因为在加载使用这些cpu相关函数的代码之前,我必须能够进行CPU检测.关于第一种方法的好处是应用程序不需要为多个CPU加载相同代码的多个副本,它将仅加载将使用的副本.第二种方法的缺点是非常明显的,不需要谈论它.
我想知道是否有办法在不使用共享对象的情况下执行此操作并在运行时手动加载它们.其中一种方法是涉及在运行时修补代码的一些hackery,它可能太复杂而无法正确完成它).有没有更好的方法来控制加载时的重定位?也许将cpu依赖函数放在不同的部分,然后以某种方式指定哪个部分具有优先级?我认为MAC的男子气概有类似的东西.
ELF-only(针对手臂目标)解决方案对我来说已经足够了,我并不真正关心PE(dll's).
谢谢
您可能想要查找GNU动态链接器扩展STT_GNU_IFUNC.来自Drepper的博客添加时:
因此,我设计了一个ELF扩展,允许决定每个进程运行一次使用哪个实现.它使用新的ELF符号类型(STT_GNU_IFUNC)实现.只要符号查找解析为具有此类型的符号,动态链接器就不会立即返回找到的值.相反,它将值解释为函数指针,该函数指向不带参数的函数并返回要使用的实际函数指针.调用的代码可以在实现者的控制之下,并且可以基于实现者想要使用的任何信息来选择要使用的两个或更多个实现中的哪个.
资料来源:http://udrepper.livejournal.com/20948.html
尽管如此,正如其他人所说,我认为你误解了间接电话的性能影响.共享库中的所有代码都将通过GOT中的(隐藏)函数指针和加载/调用该函数指针的PLT条目来调用.