Dark Bit Factory & Gravity
PROGRAMMING => Other languages => ASM => Topic started by: ninogenio on October 01, 2006
-
i brought this over from my old board as i thought it might be helpfull this was jims answer to me asking about dev cpp inline asm.
quote jim:
Are you ready for this?..it's going to get seriously complicated! :-)
When you write programs with dev-c++ or gcc, gnuC, whatever it's called, the C or C++ is first translated to assembler, then 'as' or 'gas' (gnu assembler) turns that into an object file. The object files are linked together into the exe.
When you use inline assembler, you're basically turning off the C part of the compiler and that code gets spat straight out into the assembler.
So the first thing to do is make sure it's formatted correctly for the assembler. You need a tab at the start of the line and a new line at the end.
So you need
asm("\tmovl $5,eax\n");
\t is tab, \n is newline.
So, now to some real code. You could do a lot worse than go to http://support.intel.com/design/PentiumD/documentation.htm and download and read the entire set of manuals from the Manuals section, especially Vol 1 which describes how the cpu works, and 2A and 2B which describe the entire (and huge) set of instructions you can work with.
The first thing you might want to do is to load the global variable 'screen_ptr' into a register. That's done with the 'mov' instruction.
asm("\tmov _screen_ptr,%esi\n");
That moves the value at 'screen_pointer' into the register esi. There are 8 registers, eax,ebx,ecx,edx,esi,edi,ebp,esp. You can use the first 6 for pretty much anything, the last two handle the stack.
When you pass values into a function, they appear on the stack. When you declare variables in a function they also appear on the stack. When you enter a function, esp points at the stack. Then a 'stack frame' is created to hold the local variables. This is done by subtracting the size of the variables off esp and placing it in ebp. Your x and y can be referenced off ebp. Now, I'm not quite sure how dev-c++ manages it's stack frame, but we can get the values of x and y by doing
asm("\tmov 8(%ebp),%eax\n");
asm("\tmov 12(%ebp),%ebx\n");
So, now you have x,y and the screen pointer, it should be possible to calculate the address of the pixel you want to write.
That is, screen_ptr + (x + y * 640)*4
We can do that by doing
asm("\timul $640,%ebx\n");
asm("\tadd %ebx,%eax\n");
asm("\tleal (%esi,%eax,4),%esi\n");
Now the address of the pixel is in esi. We can write the pixel (yay!)
asm("\tmovl $0xffff00ff,(%esi)\n");
There's still a bit of housekeeping to do. You may not corrupt esi or ebx in your inline asm, so you have to save them somewhere. The stack is a good place.
So before this code do
asm("\tpush %esi\n");
asm("\tpush %ebx\n");
then after
asm("\tpop %ebx\n");
asm("\tpush %esi\n");
There you go, a basic asm tutorial.
Here's the final routine cut&paste out of my app
void plot_pixel(int x, int y)
{
asm("\tpush %ebx\n");
asm("\tpush %esi\n");
asm("\tmov 8(%ebp),%eax\n");
asm("\tmov 12(%ebp),%ebx\n");
asm("\tmov _screen_ptr,%esi\n");
asm("\timul $640,%ebx\n");
asm("\tadd %ebx,%eax\n");
asm("\tleal (%esi,%eax,4),%esi\n");
asm("\tmovl $0xffff00ff,(%esi)\n");
asm("\tpop %esi\n");
asm("\tpop %ebx\n");
}
-
That's what you'd call the AT and T syntax. Lillo once told me that it's cleaner than intel's but I still don't like it.
You could always use:
.intel_syntax noprefixDo inline asm in Devcpp.
asm(".intel_syntax noprefix
asm( mov eax, 20
asm( mov ebx, 20
asm( add eax, ebx
asm( mov x, eax\n");
-
In my experience, the \t isn't necessary. Here are some more GCC in-line tips from my experience.
One of the most expensive things to do in C is cast a float to an int...because of the rather restrictive IEEE spec on floating points.
So
int j=(int)f;
is a "no,no" for size coders. Unfortunately its very useful for synths to do calculations in float and then cast to shorts.
An alternative in in-line assembler for GCC is:
asm ("fistp %0" : "=m"(j) : "t"(f): "st");
This might save 50 bytes!
In brief it means, use the fistp intsruction on the floating point variable f, which should be at the top of the fp stack, and output to (=)the integer variable j.
The first part is the asm in a string, the second is always the output variables, the third the input variables and lastly, the "st" statement means to the compiler that the fp stack is used and corrupted during this assembler. This is called a clobber statement and is used to tell the compiler which registers are used by the assembler.
The key to remember is the C compiler and the assembler know nothing about each other. This means they can walk all over each others registers. You therefore have to tell the compiler which registers are used. I'm confused why I dont say here some register like eax too, but probably I get lucky and don't need to but it looks a little unsafe to me.
One more example:
s=sin(s);is
asm ("fsin" :"=t"(s) :"0"(s));
Using these two calls in a program saved me >70 bytes because I was no longer pulling in maths .dll, calling functions in it and so forth. Infact I was able to make a program 1k which simply wouldn't have fit otherwise.
(sin(s) isnt a double call in GCC under mingw *if* s is a float...the function is overloaded to be the same as fsin)
One more tip, with inline asm, sin and cos can be had in one instruction (fsincos) meaning spheres, circles etc are very efficient even in a C program. My personal belief is that a small library of such functions used in a C program is the best way to size code: it allows for maximum creativity and changing of ideas whilst avoids the big overheads that C introduces.
-
cheers very much guys have some karma for that :)
anything else anyone wants to add would be very much appreciated as im sure it would be most usefull to me and any one else learning.
-
huh?
Does the line ".intel_syntax noprefix" make it possible to code inline asm wihtout the crazy at&t syntax?
(or didnt I simply understand anything)
-
hello saida i think thats exactly what rel`s saying in which case itll benifit me because i was finding the at&t a real pain.
-
huh?
Does the line ".intel_syntax noprefix" make it possible to code inline asm wihtout the crazy at&t syntax?
(or didnt I simply understand anything)
Yep.
DevCPP uses GCC and GCC's Assembler is GAS. Incidentally, Freebasic's emitter uses GAS and outputs its asm code with ".intel_syntax noprefix" directive.
-
wow thats really awesome - ive been looking for a sollution to get arround the at&t syntax
Relsoft, im giveing you some karma, as soon as i figure out how ;)
-
just hit the applaud button mate ;)
-
He needs more posts before he can affect karma so I'll give Saida a post boost ;)
++ Posts
-
thx ;)
Well, here is your carma relsoft
:cheers: