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?
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].