2013-01-24 35 views
2

我在Xcode(4.5.2)中有一个使用Debug配置生成良好的项目。但是,现在我已经切换到构建Release配置,我遇到了一个问题:我的一个内联汇编函数出现错误Invalid symbol redefinition。用谷歌搜索那个错误信息发现我有几个人得到了编译器错误,但没有关于它的含义的信息。这里的功能,带注释的错误行:LLVM上的内联ASM中的“无效的符号重定义”

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

我试着__sbt更换__sub,因为我认为__sub可能是一个受保护的名字,但事实并非如此。我不明白为什么这只发生在发布虽然 - 可能是由于优化?

+0

如果你用C编写(使用'int64_t'),你会得到更好的代码。该分支是完全不必要的(它应该是一个符号扩展和添加)。我也对使用带符号数据的无符号乘法指令('mull')感到困扰。虽然对于有问题的程序可能无关紧要,但这可能是一个错误。 –

+0

@StephenCanon那么这个俏皮话是如何与这个问题相关的呢? –

回答

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

符号是“局部的功能”。由于“内联”意味着代码在物理上是重复的,因此您得到多个符号定义的原因是您的符号确实是以“全局”方式多次定义的。当然,如果你有一个调试版本,它通常意味着“不内联”,所以内联函数没有内联,符号只声明一次,而且它“工作”。

[我对此的效率和编译器本身的效率有些怀疑 - 我曾认为至少考虑使用寄存器来处理一些输入会使效率更高]。

+0

感谢您的快速回答!至于效率,这是我一直在移植的东西,所以我只是将最初的英特尔语法ASM转换成GAS。尽管如此,我可能会尝试优化它。 – benwad

+0

我会试图先将它重写为C,然后看看结果如何。 [我不是100%确定它做了什么,但它看起来像是一个大数学函数的一部分 - 但这可能是完全错误的] –

+0

你可以解释跳跃目标上的f和b后缀是什么意思=) –