pandoragami
pandoragami

Reputation: 5585

GCC inline assembler output problems

I'm trying to multiply in assembler by shifting and adding and I get the weirdest output from the following code. If the last two function calls in the int main are commented out I get a normal result but otherwise I get a normal result for the first call and two garbage results for the second and third?

#include <iostream>

using namespace std;

int times_ten(int multiply_by_ten)
{
    int multiplied_by_ten = 0;
    //this multiplies by 10
    __asm__("shld   %%eax,%1;"
                  "movl %%eax,%%ebx;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "addl  %%ebx,%%eax;"
                  : "=r" (multiplied_by_ten)
                  : "a" (multiply_by_ten)
    );

    return multiplied_by_ten;
}
int times_hundred(int multiply_by_hundred)
{
    int multiplied_by_hundred = 0;
    //this multiplies by 100
    __asm__("shld   %%eax,%1;"
                  "shld   %%eax,%1;"
                  "movl %%eax,%%ebx;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "movl %%eax,%%edx;"
                  "shld  %%eax,%1;"
                  "addl  %%ebx,%%eax;"
                  "addl  %%edx,%%eax;"
                  : "=r" (multiplied_by_hundred)
                  : "a" (multiply_by_hundred)

    );

    return multiplied_by_hundred;
}
int main()
{
    cout<<times_hundred(1)<<endl;
    cout<<times_ten(1)<<endl;
    cout<<times_hundred(1)<<endl;

    return 0;
}

The following has the clobber list but it wont compile. the errors are below it.

#include <iostream>

using namespace std;

int times_ten(int multiply_by_ten)
{
    int multiplied_by_ten = 0;
    //this multiplies by 10
    __asm__("shld   %%eax,%1;"
                  "movl %%eax,%%ebx;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "addl  %%ebx,%%eax;"
                  : "=r" (multiplied_by_ten)
                  : "a" (multiply_by_ten)
                  : "%%eax", "%%ebx"
    );

    return multiplied_by_ten;
}
int times_hundred(int multiply_by_hundred)
{
    int multiplied_by_hundred = 0;
    //this multiplies by 100
    __asm__("shld   %%eax,%1;"
                  "shld   %%eax,%1;"
                  "movl %%eax,%%ebx;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "movl %%eax,%%edx;"
                  "shld  %%eax,%1;"
                  "addl  %%ebx,%%eax;"
                  "addl  %%edx,%%eax;"
                  : "=r" (multiplied_by_hundred)
                  : "a" (multiply_by_hundred)
                  : "%%eax", "%%ebx", "%%edx"
    );

    return multiplied_by_hundred;
}
int main()
{
    cout<<times_hundred(1)<<endl;
    cout<<times_ten(1)<<endl;
    cout<<times_hundred(1)<<endl;

    return 0;
}

|In function 'int times_ten(int)':|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
In function 'int times_hundred(int)':|
error: unknown register name '%%edx' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
In function 'int main()':|
error: unknown register name '%%edx' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
error: unknown register name '%%edx' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
||=== Build finished: 13 errors, 0 warnings ===|

Upvotes: 1

Views: 2978

Answers (2)

pandoragami
pandoragami

Reputation: 5585

This code works now.

#include <iostream> 

using namespace std; 

int times_ten(int multiply_by_ten) 
{ 
         int multiplied_by_ten = 0; 
         //this multiplies by 10 
         __asm__("shl   $1, %%eax;" 
                                   "movl %%eax,%%ebx;" 
                                   "shl  $2, %%eax;" 
                                   "addl  %%ebx,%%eax;" 
                                   : "=a" (multiplied_by_ten) 
                                   : "0" (multiply_by_ten) : "%ebx" 
         ); 

         return multiplied_by_ten; 
} 
int times_hundred(int multiply_by_hundred) 
{ 
         int multiplied_by_hundred = 0; 
         //this multiplies by 100 
         __asm__("shl   $2, %%eax;" 
                                   "movl %%eax,%%ebx;" 
                                   "shl  $3, %%eax;" 
                                   "movl %%eax,%%edx;" 
                                   "shl  $1, %%eax;" 
                                   "addl  %%ebx,%%eax;" 
                                   "addl  %%edx,%%eax;" 
                                   : "=a" (multiplied_by_hundred) 
                                   : "0" (multiply_by_hundred) : "%ebx","%edx" 

         ); 

         return multiplied_by_hundred; 
} 
int main() 
{ 
         cout<<times_hundred(1)<<endl; 
         cout<<times_ten(1)<<endl; 
         cout<<times_hundred(1)<<endl; 

     return 0; 
} 

Upvotes: 0

Richard Pennington
Richard Pennington

Reputation: 19965

After you've fixed the %% clobber problem, change the output register:

...
"addl  %%edx,%%eax;"
              : "=a" (multiplied_by_hundred)
              : "a" (multiply_by_hundred)
              : "%eax", "%ebx", "%edx"

from "=r" to "=a". Edit: This works with clang, but not gcc. Sorry.

Upvotes: 1

Related Questions