Using either the (almost) latest dev GDC (commit 5434139180a410f9fc79cabe0871b3601cee167f) or gdc-4.9 on Ubuntu Linux and X86_64 I get the following problem compiling the below code: ulong /*RAX*/ exchangeAndAdd(ulong * counter /*RSI*/, ulong addition /*RDI*/) { ulong retVal = void; asm {" mov %2, %0; lock; xadd %0, (%1); " : "=r"(retVal) : "r"(counter), "r"(addition) : "memory"; } return retVal; } int main() { ulong a = 10; ulong b = exchangeAndAdd(&a, 2); assert(a==12); assert(b==10); return 0; } when compiling with no optimizations or with -O1 all is well, the exchangeAndAdd assembly looks like: 4065d9: 48 89 f0 mov %rsi,%rax 4065dc: f0 48 0f c1 07 lock xadd %rax,(%rdi) 4065e1: c3 retq it's called from main and everybody is happy. when compiling with -O2 the exchangeAndAdd function assembly is the same but it is also inlined into main like so (invalid assembly): 406614: ba 02 00 00 00 mov $0x2,%edx 406619: 48 c7 44 24 08 0a 00 movq $0xa,0x8(%rsp) 406620: 00 00 406622: 48 8d 44 24 08 lea 0x8(%rsp),%rax 406627: 48 89 d0 mov %rdx,%rax 40662a: f0 48 0f c1 00 lock xadd %rax,(%rax) This obviously segfaults as rax is garbaged.
> asm {" > mov %2, %0; > lock; > xadd %0, (%1); > > " > : "=r"(retVal) > : "r"(counter), "r"(addition) > : "memory"; } > when compiling with -O2 the exchangeAndAdd function assembly is the same but > it is also inlined into main like so (invalid assembly): > > 406614: ba 02 00 00 00 mov $0x2,%edx > 406619: 48 c7 44 24 08 0a 00 movq $0xa,0x8(%rsp) > 406620: 00 00 > 406622: 48 8d 44 24 08 lea 0x8(%rsp),%rax > 406627: 48 89 d0 mov %rdx,%rax > 40662a: f0 48 0f c1 00 lock xadd %rax,(%rax) > > This obviously segfaults as rax is garbaged. That happens because you're modifying the output before using the inputs. Not a bug; you need to mark the output as an earlyclobber: ulong /*RAX*/ exchangeAndAdd(ulong * counter /*RSI*/, ulong addition /*RDI*/) { ulong retVal = void; asm {" mov %2, %0; lock; xadd %0, (%1); " : "=&r"(retVal) : "r"(counter), "r"(addition) : "memory"; } return retVal; }