2

I am trying to write my first inline asm program which is a prime number function. I get these errors...

../prime.c:30: Error: symbol `loop_top' is already defined
../prime.c:38: Error: symbol `loop_bot' is already defined
../prime.c:40: Error: symbol `loop_end' is already defined

int inline_prime(long n)
{
    if(n == 2)
        return 1;
    if(n % 2 == 0)
        return 0;
    long sr = sqrt(n);
    long prime = 0;
    __asm__
    (
        "jmp loop_bot \n"
        "movq $3, %%r8 \n"
        "loop_top:\n"

        "movq $0, %[prime] \n"
        "movq %[n], %%rax \n"
        "divq %%r8 \n"
        "test %[prime], %[prime] \n"
        "jz loop_end \n"


        "addq $2, %%r8 \n"
        "cmpq %[sr], %%r8 \n"
        "loop_bot: \n"
        "jle loop_top \n"
        "loop_end: \n"
        : [prime]"=d"(prime)
        : [n]"r"(n), [sr]"r"(sr)
        : "%r8", "%rax"
    );
    return prime;
}

How should I define my labels and jumps?

jww
  • 97,681
  • 90
  • 411
  • 885
chasep255
  • 11,745
  • 8
  • 58
  • 115

1 Answers1

10

Use the Special Format String %= as defined here.

For example:

"loop_top_%=:\n"
"jmp loop_top_%=\n"
David Wohlferd
  • 7,110
  • 2
  • 29
  • 56
  • I only got the error the OP experienced when using the -O2 flag. I gave this a whirl and received errors. "Invalid character '%' in mnemonic." Followed by, "Invalid character '=' in operand 1." I used -S to get the assembly with no optimizations and it looked ridiculous. Lot of wasted instructions. But I don't think the code produced by -S would work..... – Nolan Robidoux Apr 12 '16 at 20:43
  • 4
    I found the answer on my own (exciting because it usually doesn't happen)... I had to remove inlining with `__attribute__((noinline))`. Works perfectly. – Nolan Robidoux Apr 12 '16 at 20:45
  • @NolanRobidoux: Using `noinline` defeats a lot of the benefit of inline assembly. If `%=` didn't work, you're doing it wrong (or your gcc is too old). You can use local numbered labels instead of `name%=` on older gcc, see the linked duplicate. – Peter Cordes Mar 22 '18 at 03:01
  • @Peter - Does this trick work as expected with a `call`, too? – jww Jul 13 '18 at 19:45
  • @jww: `%=` only works within one asm statement. It would be weird to use `call` within one statement inside a function, and if your `asm` is at global scope you don't need it. – Peter Cordes Jul 13 '18 at 23:12
  • @jww: Basically, `%=` expands to a the same number within the same instance of the same asm statement. It expands to a different number in different asm statements, or different instances of the same asm statement. If you're defining a label you want to `call`, you probably only need one copy of the loop body that all instances can share, so `%=` would not be appropriate. Unless you're still using `%[input]` operands so different instances could have different register allocation. But anyway, `%=` is a simple text-substitution to produce unique labels. – Peter Cordes Jul 14 '18 at 00:50
  • @Peter - Thanks. I think we were working around a [newly introduced?] compiler bug. Some code with inline assembly that has been around for 10 or 15 years began to fail to compile due to multiply defined symbols. Using this trick caused link to fail due to missing symbols. We [cleared the issue](https://github.com/weidai11/cryptopp/commit/28e20d6e5) by avoiding an unnamed namespace. Someone on the GCC Help mailing list is having a [similar problem](https://gcc.gnu.org/ml/gcc-help/2018-07/msg00072.html). – jww Jul 14 '18 at 09:58
  • @jww: I think gcc is just doing its job and optimizing; I don't see any evidence of a compiler bug. The gcc bugreport doesn't look similar to me; you're having assembler errors not linker errors, presumably from inlining an asm statement containing a bare label. In this case the right fix is to split the function out because you only want it defined once. – Peter Cordes Jul 14 '18 at 13:50