Reputation: 319
I am pretty good at C, not so much with assembly, but out of interest i wanted to get some working inside C using gcc. Problem is my program either gives some silly number or crashes.
unsigned sadd32(unsigned a, unsigned b)
{
unsigned c = 0;
__asm__("movl %%eax, %0" : "=a"(a));
__asm__("addl %%eax, %0" : "=b"(b));
__asm__("movl %edx, 0xffffffff");
__asm__("cmovc %eax, %edx");
__asm__("movl %0, %%eax" : "=c"(c));
return c;
}
I'm sure i've done something silly, if it's obvious to anyone?? ;)
Upvotes: 2
Views: 2149
Reputation: 10580
Edit: Code corrected, as Michael commented that this is saturated add.
The main points on how to use gcc inline assembly:
asm(
... )
block.mov
to set the values in the beginning of inline assembly block, just define the inputs.Here's the code:
#include <stdio.h>
unsigned my_sadd(unsigned a, unsigned b)
{
asm(
"addl %2, %0;"
"cmovcl %3, %0;"
/* outputs */
: "=r"(a)
/* inputs */
: "0"(a), "r"(b), "r" (0xffffffff)
);
return a;
}
int main(void)
{
unsigned a;
unsigned b;
unsigned c;
a = 123456;
b = 314159;
c = my_sadd(a, b);
printf("%u + %u = %u\n", a, b, c);
a = 0x80000000;
b = 0xF0000000;
c = my_sadd(a, b);
printf("%u + %u = %u\n", a, b, c);
return 0;
}
Upvotes: 2
Reputation: 22348
Apart from the advice about using a single __asm__
'instruction', and AT&T syntax, it might be better to let the compiler load the register with the maximum value. Ideally:
/* static __inline__ */ unsigned sadd32 (unsigned a, unsigned b)
{
__asm__ ("addl %k1, %k0\n\t"
"cmovcl %k2, %k0\n\t"
: "+r" (a) : "r" (b), "r" (0xffffffff) : "cc");
return (a);
}
This form also works well on x86-64, where the first and second arguments will be in %rdi
(using %edi
) and %rsi
(using %esi
) respectively. It would be even better to specify this function with an inline
qualifier: the compiler might have 'max' already loaded, or may be able to schedule a better way to load it, etc. It also need not return the value in %rax
or %eax
.
A lot of tutorials for gcc inline asm are out of date. The best I've found is the Lockless Inc tutorial for x86[-64].
Upvotes: 2
Reputation: 1335
#include <stdio.h>
#include <stdlib.h>
unsigned sadd32(unsigned a, unsigned b)
{
unsigned c = 0;
__asm__ ("movl %2, %%eax\n\t"
"addl %1, %%eax\n\t"
"movl %%eax, %0\n\t"
:"=r"(c)
:"r"(a),"r"(b)
:"%eax"
);
return c;
}
int main()
{
unsigned int a=3,b=5;
printf("The sum of %u and %u is %u\n",a,b,sadd32(a,b));
return 0;
}
Referring to : http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
From what I see, your code has some flaws::
unsigned sadd32(unsigned a, unsigned b)
{
unsigned c = 0;
__asm__("movl %%eax, %0" : "=a"(a));
__asm__("addl %%eax, %0" : "=b"(b));
__asm__("movl %edx, 0xffffffff"); /* this here, you are specifying a manual location, may not be accessible or valid */
__asm__("cmovc %eax, %edx"); /* resulting in its error */
__asm__("movl %0, %%eax" : "=c"(c));
return c;
}
Also, I believe you did not understand the "=$" concept. From what I see, you are just writing the variable name there, but that is not how it works. From the site, the constraint restraints(as they are known), are as follows:
m’
constraint but not the
o’constraint. Refer to the site for more examples and other constraints. Hope this helped! :)
Upvotes: 2