Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ &引用;无效符号重新定义“;LLVM上的内联ASM_C++_Assembly_Llvm_Clang_Gnu Assembler - Fatal编程技术网

C++ &引用;无效符号重新定义“;LLVM上的内联ASM

C++ &引用;无效符号重新定义“;LLVM上的内联ASM,c++,assembly,llvm,clang,gnu-assembler,C++,Assembly,Llvm,Clang,Gnu Assembler,我在Xcode(4.5.2)中有一个项目,它使用调试配置构建得很好。然而,现在我已经切换到构建发行版配置,我遇到了一个问题:我的一个内联汇编函数得到了错误无效符号重新定义。通过谷歌搜索那个错误消息,我发现有几个人犯了那个编译器错误,但并没有关于它意味着什么的信息。下面是函数,注释了错误行: inline int MulDivAdd(int nNumber, int nNumerator, int nDenominator,

我在Xcode(4.5.2)中有一个项目,它使用调试配置构建得很好。然而,现在我已经切换到构建发行版配置,我遇到了一个问题:我的一个内联汇编函数得到了错误
无效符号重新定义
。通过谷歌搜索那个错误消息,我发现有几个人犯了那个编译器错误,但并没有关于它意味着什么的信息。下面是函数,注释了错误行:

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;
}
我尝试用
\uu sbt
替换
\uu sub
,因为我认为
\uu sub
可能是一个受保护的名称,但事实并非如此。我不明白为什么这只发生在发行版中-可能是因为优化吗?

使用本地标签,例如
1:
2:
,以及
jxx 1f
jxx 1b
。需要跳跃方向(
f
用于向前或
b
用于向后)。因此,您的代码应该如下所示:

\uuuuu asm\uuuuu volatile\uuuuu(
mov%4,%%ecx\n
mov%1,%%eax\n
“考虑%2\n”
“cmp$0,%%ecx\n”
“jl 1f\n”
添加%%ecx,%%eax\n
“adc$0,%%edx\n”
“JMP2F\n”
“1:\n”
“neg%%ecx\n”
“subl%%ecx,%%eax\n”
sbb$0,%%edx\n
“2:\n”
“divl%3\n”
“mov%%eax,%0\n”
)
纯粹由数字组成的符号是“函数的局部”。因为“内联”意味着代码在物理上是重复的,所以您得到多个符号定义的原因是您的符号确实以“全局”的方式定义了多次

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


[我对这种方法的效率与编译器本身会做什么有点怀疑-我认为至少考虑对一些输入使用寄存器会使它更有效]

谢谢你的快速回答!至于效率,这是我一直在移植的东西,所以我只是将原始的Intel语法ASM转换为GAS。不过,我可能会尝试在将来对它进行优化。我会尝试先将它重写为C,然后看看它是如何运行的。[我不是100%确定它是做什么的,但它看起来像是一个大数数学函数的一部分-但这可能是完全错误的]你可以解释一下跳转目标上的
f
b
后缀是什么意思=)@Mats-“使用数字标签…”-我认为这些被称为本地标签。看,它们实际上不是函数的局部。如果重新排列代码而不更正标签引用中的
f
orward和
b
ack方向,则可以跳转到内联asm块的上一个副本中的
1:
。gas不支持x86目标的
1$:
有限范围本地标签名称。仅供参考:。如果用C编写(使用
int64\t
),您将获得更好的codegen。分支完全没有必要(它应该是一个扩展和添加的符号)。我还对使用带符号数据的无符号乘法指令(
mull
)感到困扰。虽然这可能与所讨论的程序无关,但它可能是一个bug。@StephenCanon那么这与问题有什么关系呢?这不需要是易变的。它只需要运行就可以产生输出。(而且,
volatile
不会阻止它内联到多个位置,从而导致问题)。但是Stephen是对的,对于强制内存操作数的效率来说,这看起来很糟糕。这里使用内联asm的唯一原因是如果您知道64b/32b=>32b
div
不会溢出商和错误。gccl/clang仍然不知道如何利用这一点,使用单个
idiv
,而不是为64b/64b分区调用libgcc帮助函数。