“Invalid symbol redefinition” in inline ASM on LLVM

一曲冷凌霜 提交于 2019-12-21 21:55:52

问题


I've got a project in Xcode (4.5.2) that builds fine using the Debug configuration. However, now that I've switched to building the Release configuration, I'm getting an issue: one of my inline assembly functions is getting the error Invalid symbol redefinition. Googling that error message finds me a few people who have got that compiler error, but no information as to what it means. Here's the function, with the error lines annotated:

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;
}

I've tried replacing __sub with __sbt because I thought __sub might be a protected name, but that wasn't the case. I don't understand why this only happens in Release though - could it be due to optimisation?


回答1:


Use local labels, such as 1: and 2:, and jxx 1f or jxx 1b. The direction of the jump (f for forwards or b for backwards) is required. So your code should be like this:

__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"
)

Symbols consisting purely of numbers are "local to the function". Since "inline" means the code is physically duplicated, the reason you get multiple symbol definitions is that your symbols are indeed defined multiple times in a "global" way.

Of course, if you have a debug build, it normally means "no inline", so the inlined function isn't inlined, symbols only declared once, and it "works".

[I'm slightly dubious as to the efficiency of this vs. what the compiler would do itself - I'd have thought at least considering using registers for some of the inputs would make it more efficient].



来源:https://stackoverflow.com/questions/14506151/invalid-symbol-redefinition-in-inline-asm-on-llvm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!