通过函数指针使用内部函数时的链接器错误

Posted

技术标签:

【中文标题】通过函数指针使用内部函数时的链接器错误【英文标题】:Linker errors when using intrinsic function via function pointer 【发布时间】:2015-08-26 06:47:10 【问题描述】:

下面的代码不能用 Visual Studio 2013 编译。我得到 mm 函数的链接器错误未解析的外部符号(LNK 2019)。如果我直接使用这些功能,一切都很好。 为什么它不编译?有没有解决办法

        #include "emmintrin.h"
        #include <smmintrin.h>
        #include <intrin.h>


        __m128i (*load)(const __m128i*) = NULL;

        if (it::isAligned<16>(ucpSrc, iXOffset * sizeof(unsigned char)) )
            load = &_mm_load_si128;
        else
            load = &_mm_lddqu_si128;

【问题讨论】:

sizeof(unsigned char) 是 1 确定这些是普通函数而不是仿函数类? 这些内在函数不是函数,而是编译器插入的单个机器指令。 在循环中使用加载,如果我将 mm - 指令包装到函数中,是否会产生任何重大开销 如果您真的要问这个问题,我怀疑您可能不了解基本的 x86 汇编和/或低级编程。在现代处理器上,函数调用比未对齐的负载要糟糕得多。 【参考方案1】:

gcc 和 clang 等一些编译器在这些方法上使用了一些特殊的注解(static extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__)) 用于 gcc,或 static __inline__ __attribute__((__always_inline__, __nodebug__)) 用于 clang),而其他编译器(如 Windows 和 cl 上的 Intel,则不这样做并且可能会做一些特别的事情在引擎盖下。

关键是这些函数并不意味着被视为函数。他们不会显示任何序言,实施标准 ABI。这些只是调用一些汇编指令的 C 语法方式,比 __asm (...) 更具可读性

我相信你可以通过以下方式完成这个函数指针的事情:

__m128i load_aligned (const __m128i* p)

    return _mm_load_si128(p);


__m128i load_unaligned (const __m128i* p)

    return _mm_lddqu_si128(p);



__m128i (*load)(const __m128i*) = NULL;

void f(bool a)

    if (a)
        load = load_aligned;
    else
        load = load_unaligned;


int main()

    __m128i a, b ;
    f(argc != 0);
    return 0;

不过,我要强调一个性能说明:使用函数指针将比一直使用未对齐的负载要昂贵得多。当内存对齐时,未对齐加载的开销约为百分之几,调用函数指针将强制您尊重 ABI,因此将寄存器存储在堆栈上,很可能会经历一些缓存未命中等。

【讨论】:

以上是关于通过函数指针使用内部函数时的链接器错误的主要内容,如果未能解决你的问题,请参考以下文章

链接器为rodata 部分计算错误的地址

链接器计算rodata部分的错误地址

使用 jOOQ 执行 PL/SQL 函数时的 Java 空指针

使用 JNA 将本机 C 函数映射到 Java 接口时的指针问题

使用函数指针消除 gcc 死代码

在构造函数初始化器列表中初始化函数指针数组 - 错误