Quote:
This section was written by Marc Brooker
This is not an assembler tutorial, it is intended for someone who already
can do assembler and wishes to learn to write inline assembler in DJGPP.
Why would I want Inline Assembler?
There are a variety of reasons why you would opt to include inline assembler
in your program. The djgpp compiler outputs high quality code, but it is not
always the fastest/smallest you can get away with. Sometimes, you would want
to write your own code in assembler to achieve your aims. This is most
important in an inner loop which is likely to be executed more then 10 times
per second. If you have code that is only executed once, then it your code
would not make too much of an impact on the speed of your program.
Why wouldn't I want Inline Assembler?
You can also make things worse by adding inline assembler. If the code that
GCC would have created or the library code that you are replacing is faster,
you will make your program slower. Often the assembler code that you write
is not as stable as DJGPP's code, but you can counter this by writing code
that is more stable :-). A lot of people tend to make speed/stability
tradeoffs, IMO this is stupid if taken too far.
Using Inline Assembler
There are some things to note when using inline assembler in DJGPP, firstly,
DJGPP uses the AT&T format, not the Intel format that most people are used
to. In the AT&T format, the operands are reversed. If you use a register as
an operand, prefix it with % and immediate values get a $. You also have to
add a suffix to the instructions to specify the size of the operands.
movl %ecx, %ebx
Notice the 'l' at the end of mov. This specifies that the instruction is
working on 32 bit operands. 'w' indicates that the instruction is using 16
bit operands and 'b' for 8 bit.
So, with all that under your belt, how do you actually add it into your
code? You use the asm keyword. It takes the following form.
asm("instructions" : outputs : inputs : clobber list);
You don't actually need to use the last three, but for longer code you will
need them. Let's see what they do.
asm ("
pushl %%eax
movl %1, %%eax
movl %2, %%ebx
addl %%ebx, %%eax
movl %%eax, %0
popl %%eax"
: "=g" (i)
: "g" (j), "g" (k)
: "bx" );
Wow. Let's go through that piece of code step by step. The actual code, as
you can probably figure out, adds j and k and puts the output in i. Firstly,
what's with the '%%'? If you have any inputs or outputs, then you must put
%% before your register names. Next up, the input list. Who is 'g'? G simply
tells the compiler to put the argument anywhere. You can then reference them
in order, %0 is i, %1 is j and %2 is k. '=g' tells the compiler that it is
output. We put ebx into the clobbered list because it gets clobbered.
We have seen our first example and learned a lot in the last couple of
lines. Go get yourself a cup of strong coffee (or maas if you don't drink
coffee:-) and read on. Next up, what about 'jmp' and it's friends. You can
use them but you must suffix your lables with b for backward and f for
forward, the following piece will illustrate this.
asm ("0:
//some stuff
jmp 0b
//more stuff
jmp 1f
1:" );
That is all said and done, but what about memory references, are they
different too? Yeah, like everything, they are different, for example, if
you wanted to access ebp + 4 then you would use the line movl 4(%ebp), %eax.
Wow, that is weird, I hear people saying. Depending on what you do in
assembler you might never need to use this syntax, it's full form is
disp(base, index, scale).
That should get you rolling as far as porting that app that uses inline asm
from a different system. I apologize for any problems in this I wrote it one
nigh at about 11:30 for a friend who was starting in DJGPP.