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

ben*_*wad 2 c++ assembly gnu-assembler llvm clang

我在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;
}
Run Code Online (Sandbox Code Playgroud)

我试着更换__sub__sbt,因为我觉得__sub可能是一个受保护的名字,但事实并非如此.我不明白为什么这只发生在Release中 - 可能是由于优化?

Mat*_*son 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"
)
Run Code Online (Sandbox Code Playgroud)

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

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

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