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.
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.
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.
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.
|webmaster||delorie software privacy|
|Copyright © 2019 by root||Updated Apr 23 2019|