2
votes
//quick inline asm statements performing the swap_byte for key_scheduling
inline void swap_byte(unsigned char *x, unsigned char *y)
{
 unsigned char t;
 asm("movl %1, %%eax;"
     "movl %%eax, %0;"
     :"=r"(t)
     :"r"(*x)
     :"%eax");
 asm("movl %1, %%eax;"
     "movl %%eax, %0;"
     :"=r"(*x)
     :"r"(*y)
     :"%eax");
 asm("movl %1, %%eax;"
     "movl %%eax, %0;"
     :"=r"(*y)
     :"r"(t)
     :"%eax");       
}

Here I am trying to swap the char from x and store in y, and the same for y to x. I have compiled these instructions by changing movl to mov but with no success. Where is the problem in compiling/linking?

Here is the output from compiling in cygwin:

$ gcc rc4_main.c -o rc4ex
/tmp/ccy0wo6H.s: Assembler messages:
/tmp/ccy0wo6H.s:18: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:18: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:26: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:26: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:34: Error: operand type mismatch for `mov'
/tmp/ccy0wo6H.s:34: Error: operand type mismatch for `mov'
3
If this is meant to be production code and you're triyng to speed up the key scheduling loop of RC4 or some other cipher then using inline assembly here can only pessimize your code. You're better off using plain C to do the swap as the compiler will be able to optimize it better.Ross Ridge

3 Answers

6
votes

To simplify it even more (than user35443):

asm("" : "=r" (*x), "=r" (*y) : "1" (*x), "0" (*y));

Look ma! No code! And yes, this really works.

To explain how this works:

When the compiler is building the code, it keeps track of what value is in each register. So if had these for inputs to asm:

"r" (*x), "r" (*y)

The compiler will pick a register and put *x in it, then pick a register and put *y in it, then call your asm. But it also keeps track of what variable is in which register. If there were just some way to tell the compiler that all it had to do was start treating the two registers as the opposite variables, then we'd be set. And that's what this code does:

  1. Saying "=r" (*x) means that we are going to be overwriting the value in *x, that that we will be putting the value into a register.
  2. Saying "0" (*y) means that on input to the asm, the compiler must put the value of *y into the same register as is being used by output parameter #0.

So, without using any actually assembly instructions, we have told the compiler to swap these two values.

We don't get this quite "for free" since the compiler must load the values into registers before calling the asm. But since that has to happen anyway...

What about actually updating memory? The compiler will (if necessary) write these values from the registers back to memory. And since it knows what variable is in which register, all works as expected.

2
votes
unsigned char t;
asm("movl %1, %%eax;"
     "movl %%eax, %0;"
     :"=r"(t)  /* <--here */
     :"r"(*x)  /* <-- and here */
     :"%eax");

You can not move a value from a 32-bit register to a single-byte memory location. t is on the stack and x is somewhere else, but both are accessed in the same way. Problems on the other lines are similar. You should move only a byte.

Try something like this, but there are more ways to do it (I haven't tried that, read below):

unsigned char t;
asm("movb %1, %%al\n"
     "movb %%al, %0\n"
     :"=r"(t)
     :"r"(*x)
     :"%al");
asm("movb %1, %%al\n"
     "movb %%al, %0\n"
     :"=r"(*x)
     :"r"(*y)
     :"%al");
asm("movb %1, %%al\n"
     "movb %%al, %0\n"
     :"=r"(*y)
     :"r"(t)
     :"%al"); 

The whole procedure can be simplified into this:

asm("movb (%1), %%al\n"
    "movb (%2), %%ah\n"
    "movb %%ah, (%1)\n"
    "movb %%al, (%2)\n"
    : /* no outputs for compiler to know about */
    : "r" (x), "r" (y)
    : "%ax", "memory");
-1
votes

line

movl %%eax, %0; 

is full nonsence! So you try to change 0 constant by %eax register It's impossible. In fortran many years ago It was. After that all programs will behave quite unpredictable. Since to avoid that was introduce the rule that any identificatot can't begin with number. But You try do it. It's well to get error. You maybe mean another

movl %0, %%eax; 

to set zerro to eax. So better do another code

xorl %%eax, %%eax;

is much better!