LLVM上的内联ASM中的“无效符号重新定义”

时间:2013-01-24 16:32:10

标签: c++ assembly llvm clang gas

我在Xcode(4.5.2)中有一个使用Debug配置构建的项目。但是,现在我已经切换到构建Release配置,我遇到了一个问题:我的一个内联汇编函数正在收到错误Invalid symbol redefinition。谷歌搜索该错误消息发现我有一些人有编译器错误,但没有关于它意味着什么的信息。这是函数,带有注释错误行:

inline int MulDivAdd(int nNumber,
                int nNumerator,
                int nDenominator,
                int nToAdd)
{
    int nRet;

    __asm__ __volatile__ (
        "mov    %4,     %%ecx   \n"
        "mov    %1,     %%eax   \n"
        "mull   %2              \n"
        "cmp    $0,     %%ecx   \n"
        "jl     __sub           \n"
        "addl   %%ecx,  %%eax   \n"
        "adc    $0,     %%edx   \n"
        "jmp    __div           \n"
    "__sub:                     \n"    // "Invalid symbol redefinition"
        "neg    %%ecx           \n"
        "subl   %%ecx,  %%eax   \n"
        "sbb    $0,     %%edx   \n"
    "__div:                     \n"    // "Invalid symbol redefinition"
        "divl   %3              \n"
        "mov    %%eax,  %0      \n"

        :   "=m"    (nRet)
        :   "m"     (nNumber),
            "m"     (nNumerator),
            "m"     (nDenominator),
            "m"     (nToAdd)
        :   "eax", "ecx", "edx"

    );

    return nRet;
}

我已尝试将__sub替换为__sbt,因为我认为__sub可能是受保护的名称,但事实并非如此。我不明白为什么这只发生在Release中 - 可能是由于优化?

1 个答案:

答案 0 :(得分:11)

使用 本地标签 ,例如1:2:以及jxx 1fjxx 1b。跳跃的方向(前进f或后退b)是必需的。所以你的代码应该是这样的:

__asm__ __volatile__ (
    "mov    %4,     %%ecx   \n"
    "mov    %1,     %%eax   \n"
    "mull   %2              \n"
    "cmp    $0,     %%ecx   \n"
    "jl     1f              \n"
    "addl   %%ecx,  %%eax   \n"
    "adc    $0,     %%edx   \n"
    "jmp    2f              \n"
"1:                         \n"   
    "neg    %%ecx           \n"
    "subl   %%ecx,  %%eax   \n"
    "sbb    $0,     %%edx   \n"
"2:                         \n"   
    "divl   %3              \n"
    "mov    %%eax,  %0      \n"
)

纯粹由数字组成的符号是“函数的本地”。由于“内联”意味着代码在物理上是重复的,因此获得多个符号定义的原因是您的符号确实以“全局”方式多次定义。

当然,如果你有一个调试版本,它通常意味着“没有内联”,所以内联函数没有内联,符号只声明一次,它“工作”。

[我对这个效率与编译器本身的效率有点怀疑 - 我认为至少考虑使用寄存器进行某些输入可以提高效率]。