Xref: news2.mv.net comp.os.msdos.djgpp:6369 From: korpela AT albert DOT ssl DOT berkeley DOT edu (Eric J. Korpela) Newsgroups: comp.os.msdos.djgpp Subject: Re: Referencing local variables with inline assembly. Date: 24 Jul 1996 18:31:01 GMT Organization: Cal Berkeley-- Space Sciences Lab Lines: 121 Message-ID: <4t5q55$5al@agate.berkeley.edu> References: NNTP-Posting-Host: albert.ssl.berkeley.edu To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp In article , Luke Steele wrote: >Hi, > How do you reference local variables with inline assembly? I _have_ >read the GCC documentation on the subject, but I cannot work out what >to do. A few lines of code demonstating how to do this would be >great. > Secondly: Which segment registers are used by the compiler, and so >which ones can I use without worrying about their values becoming >corrupted? The answer to both your questions is the Extended Assembly format. A good tutorial is at "http://www.pegasuz.com/binky/attasm.htm". The basic format of extended assembly is .... __asm__ ( "assembly code" : output list : input list : clobbered registers ); To use the input and output lists properly you need to use appropriate macros (%0, %1, %2, ...) which correspond to the first, second, third ... parameters in the output and input lists. You also need to understand the operand codes. They are "r" any general purpose register (eax,ebx,ecx,edx,esi,edi) "q" any of (eax,ebx,ecx,edx) "a","b","c","d","S","D" (eax,ebx,ecx,edx,esi,edi) respectively "A" a 64 bit register pair (i.e. edx:eax) "f" a floating point register "t" first fp register (top of floating point stack) "u" second fp register "m" a memory operand "i" an immediate operand "0" "1" "2" ... (use the same operand as %0 an "=" sign must be used in output operands. So here's an example done several ways... ------------------------------------------------------------------------- inline int multiply_by_5(int x) { int x_times_5; __asm__ ("leal (%1,%1,2),%0", : "=a" (x_times_5) /* use the eax register and store the result in */ /* the variable x_times_5 */ : "b" (x) /* use the ebx register and load it with the variable x */ ) /* no clobbered registers other than above */ return(x_times_5); } ------------------------------------------------------------------------- if x and x_times_5 were global variables the above would compile as... movl _x,%eax leal (%eax,%eax,2),%ebx movl %ebx,_x_times_5 if the eax and ebx registers need to be saved gcc will do it automatically. Here it is another way .............. ------------------------------------------------------------------------- inline int multiply_by_5(int x) { int x_times_5; __asm__ ("leal (%1,%1,2),%0", : "=r" (x_times_5) /* use any register and store the result in */ /* the variable x_times_5 */ : "0" (x) /* use the same register and load it with the variable x */ ) /* no clobbered registers other than above */ return(x_times_5); } ------------------------------------------------------------------------- This would probably compile as (again if _x and _x_times_5 were global) movl _x,%edx leal (%edx,%edx,2),%edx movl %edx,_x_times_5 Again, whatever register is used will be saved if necessary. One more time..... ------------------------------------------------------------------------- inline int multiply_by_5(int x) { int x_times_5; __asm__ ("leal (%1,%1,2),%0 xor %%ebx,%%ebx", /* clobber a register for no reason */ : "=a" (x_times_5) /* use eax register and store the result in */ /* the variable x_times_5 */ : "0" (x) /* use the same register and load it with the variable x */ : "ebx" ); /* we clobbered the ebx register for no reason */ return(x_times_5); } -------------------------------------------------------------------------- In this case because we clobbered the ebx register we had to tell the compiler about it by adding it to the clobbered register list. If it's in the clobbered list gcc will save and restore it's value if necessary. (It actually rarely is). There are a couple other things you may need to add to you clobbered list. One is "memory". If you explicitly write to a global variable you should add "memory" to the clobbered list. Otherwise the compiler could keep its value cached in a register during your assembly code. It's also possible that you could run into trouble if the compiler expects the condition codes to be the same when your assebly is complete. If so you need to add "cc" to your clobbered list. As far as segment registers go, there are no codes for them so you'll need to add them to your clobbered list if you change them. If you change a segment register make sure you're loading it with a valid descriptor, otherwise you get SIGSEGVs up the yin-yang. (It's protected mode after all.) Only play with segments if it's absolutely necessary. Hope this helped. Eric -- Eric Korpela | An object at rest can never be korpela AT ssl DOT berkeley DOT edu | stopped. Click here for more info.