Graham Borland
Graham Borland

Reputation: 60711

Adding two numbers

I am trying to familiarise myself with x86 assembly using GCC's inline assembler. I'm trying to add two numbers (a and b) and store the result in c. I have four slightly different attempts, three of which work; the last doesn't produce the expected result.

The first two examples use an intermediate register, and these both work fine. The third and fourth examples try to add the two values directly without the intermediate register, but the results vary depending on the optimization level and the order in which I add the input values. What am I getting wrong?

Environment is:

i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)

First, the variables are declared as follows:

int a = 4;
int b = 7;
int c;

Example 1:

asm("   movl    %1,%%eax;"
    "   addl    %2,%%eax;"
    "   movl    %%eax,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
    : "%eax"
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output: a=4, b=7, c=11

Example 2:

asm("   movl    %2,%%eax;"
    "   addl    %1,%%eax;"
    "   movl    %%eax,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
    : "%eax"
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output: a=4, b=7, c=11

Example 3:

asm("   movl    %2,%0;"
    "   addl    %1,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=11
// output with -O3: a=4, b=7, c=14

Example 4:

// this one appears to calculate a+a instead of a+b
asm("   movl    %1,%0;"
    "   addl    %2,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=8
// output with -O3: a=4, b=7, c=11

SOLVED. Matthew Slattery's answer is correct. Before, it was trying to reuse eax for both b and c:

movl    -4(%rbp), %edx
movl    -8(%rbp), %eax
movl    %edx, %eax
addl    %eax, %eax

With Matthew's suggested fix in place, it now uses ecx to hold c separately.

movl    -4(%rbp), %edx
movl    -8(%rbp), %eax
movl    %edx, %ecx
addl    %eax, %ecx

Upvotes: 11

Views: 4297

Answers (2)

Matthew Slattery
Matthew Slattery

Reputation: 47058

By default, gcc will assume that an inline asm block will finish using the input operands before updating the output operands. This means that both an input and an output may be assigned to the same register.

But, that isn't necessarily the case in your examples 3 and 4.

e.g. in example 3:

asm("   movl    %2,%0;"
    "   addl    %1,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
   );

...you have updated c (%0) before reading a (%1). If gcc happens to assign the same register to both %0 and %1, then it will calculate c = b; c += c, and hence will fail in exactly the way you observe:

printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=11
// output with -O3: a=4, b=7, c=14

You can fix it by telling gcc that the output operand may be used before the inputs are consumed, by adding the "&" modifier to the operand, like this:

asm("   movl    %2,%0;"
    "   addl    %1,%0;"
    : "=&r" (c)
    : "r" (a), "r" (b)
   );

(See "Constraint Modifier Characters" in the gcc docs.)

Upvotes: 8

gilgamash
gilgamash

Reputation: 902

Hoi, i do not see a problem there and it compiles and works fine here. However, a small hint: I got confused with the unnamed variables/registers quite soon, so I decided on using named ones. The add thingy you could for instance implement like this:

static inline void atomicAdd32(volInt32 *dest, int32_t source) {
// IMPLEMENTS:  add m32, r32
__asm__ __volatile__(
        "lock; addl %[in], %[out]"
        : [out] "+m"(*dest)
        : [in] "ir"(source)//, "[out]" "m"(*dest)
        );
return;
  }

(you can just ignore the atomic/ lock things for now), that makes clear what happens:

1) what registers are writeable, readable or both

2) what is used (memory, registers), which can be important when it comes to performance and clock cycles, as register operations are quicker than those accessing the memory.

Cheers, G.

P.S.: Have you checked whether your compiler rearranges code?

Upvotes: 0

Related Questions