在运行时可以确定某些平台特定功能的可用性,例如SSE或AVX。如果不想为不同的功能编译和发送不同的对象,则这非常有用。
例如,以下代码允许我检查AVX并使用提供cpuid.h
头文件的gcc进行编译:
#include "stdbool.h"
#include "cpuid.h"
bool has_avx(void)
{
uint32_t eax, ebx, ecx, edx;
__get_cpuid(1, &eax, &ebx, &ecx, &edx);
return ecx & bit_AVX;
}
不要在代码中频繁执行运行时检查(例如上述内容),这样会使代码混乱、速度变慢,同时引入分支结构(尽管可以缓存检查结果以减少开销,但仍会引入分支结构);相反,我考虑使用动态链接器/装载器提供的基础设施。
在ELF平台上,具有外部链接的函数的调用已经是间接的,并通过程序链接表/PLT和全局偏移表/GOT进行。
假设存在两个内部函数,一个是基本的_do_something_basic
,总是执行同样的操作,另一个是一种优化过的版本_do_something_avx
,它使用AVX。我可以导出一个通用的do_something
符号,并将其别名用于基本的加法:
static void _do_something_basic(…) {
// Basic implementation
}
static void _do_something_avx(…) {
// Optimized implementation using AVX
}
void do_something(…) __attribute__((alias("_do_something_basic")));
在我的库或程序的加载期间,我想通过使用
has_avx
检查AVX的可用性,并根据检查结果将do_something
符号指向_do_something_avx
。最好的情况是,如果我能够将do_something
符号的初始版本指向一个自修改函数,该函数使用has_avx
检查AVX的可用性,并用_do_something_basic
或_do_something_avx
替换它自己。
理论上这应该是可能的,但我如何通过编程方式找到PLT/GOT的位置呢?是否有由ELF加载器(例如ld-linux.so.2)提供的ABI/API可用于此?我需要链接脚本来获取PLT/GOT的位置吗?至于安全考虑,如果我获得指向PLT/GOT的指针,我能否写入其中?
也许某个项目已经完成了类似的工作。 我完全意识到解决方案将高度特定于平台,但既然我已经不得不处理低级平台特定细节,例如指令集的特性,那么这没问题。
dlopen
加载适当的版本。不必自己操纵PLT。请参见此答案示例。 - Jester