220 likes | 370 Views
Mixing C and assembly. Safety goggles on!. Prelude: How do arguments get passed into a function when that function is called from C ?. And how do return values get passed back to the calling function from the called function?. What do compilers do?. C/C++ compilers generally
E N D
Mixing C and assembly Safety goggles on! CE-2810 Dr. Mark L. Hornick
Prelude: How do arguments get passed into a function when that function is called from C ? And how do return values get passed back to the calling function from the called function? CE-2810 Dr. Mark L. Hornick
What do compilers do? • C/C++ compilers generally • Pass parameters using a register/stack combination • Return values via registers • Save registers at the beginning of a function • Restore registers before the function returns CS-280 Dr. Mark L. Hornick
Passing arguments among C functions • Every C compiler has it’s own rules and conventions for passing arguments to functions • Arguments can be passed • via Registers • via the Stack • Both of the above CE-2810 Dr. Mark L. Hornick
GCC for Atmega32 uses Registers as much as possible to pass arguments • Consider a function: • int16_t add( uint8_t x, uint16_t y); • uint8_t means “unsigned 8-bit int” • uint16_t means “unsigned 16-bit int” • int16_t means “signed 16-bit int” (same as int on Atmega32) • GNU GCC passes arguments left to right using registers r25 to r8 • All arguments always take an even number of registers • Above, value of x (single byte) is placed in r24:r25 (low, high bytes) • The value of x is placed in r24 • The value of 0 is placed in r25 • Value of y (2 bytes) is placed in r22:r23 • The low byte value of y is placed in r22 • The high byte value of y is placed in r23 • Note that r26:r31 are not used for passing arguments or return values since these registers are also the X, Y, and Z registers which the compiler uses for other purposes • What about the return value?? CE-2810 Dr. Mark L. Hornick
GCC convention for returning values from functions Return values always take an even number of registers • 8-bit values are returned in r24:r25 • Value in r24 • 0 in r25 • 16-bit values returned in r24:r25 • Low byte in r24 • High byte in r25 • 32-bit values returned in r22:r25 • Lowest byte in r22 • Highest byte in r25 • 64-bit values returned in r18:r25 • lowest byte in lowest register CE-2810 Dr. Mark L. Hornick
Example of 2-byte argument passing • Consider the function: • int add( int x, int y); • Size of int in C is dependent on processor • On Atmega32, int is 2 bytes • Within MSVS for your PC, int means 4 bytes • Note: Java int is always 4 bytes • GNU GCC passes arguments left to right using registers r25 to r8 • All arguments always take an even number of registers • Above, value of x (two bytes) is placed in r24:r25 (low, high bytes) • Value of y is placed in r23-r22 • The return value is passed back in r24:r25 (low, high) CE-2810 Dr. Mark L. Hornick
Example of 4-byte argument passing • Consider the function: • long add(int x, long y); • Size of long is 4 bytes • GNU GCC passes arguments left to right using registers r25 to r8 • Above, value of x (2 bytes) is placed in r24:r25 • r24 is low byte; r25 is high byte • Value of y is placed in r20:r23 • r20 is lowest byte; r23 is highest byte • The return value is passed back in r22:r25 • r22 is lowest byte CE-2810 Dr. Mark L. Hornick
What happens when we run out of registers to pass arguments? • Registers r25 to r8 can accommodate only 9 two-byte arguments • 18 bytes total via registers • Consider the function: • long add( long a, long b, long c, long d, long e); • 20 bytes worth of arguments in this case CE-2810 Dr. Mark L. Hornick
When it runs out of Registers, the compiler uses the Stack to pass additional arguments • long add( long a, long b, long c, long d, long e); • 20 bytes worth of arguments in this case, but only 18 1-byte registers are available • Approach: Arguments a, b, c, d (16 bytes total) are passed using registers r25 to r10 • r22:r25 for a, r18:r21 for b • The remaining argument e (4 bytes) is passed on the Stack • Leaving registers r8, r9 unused – the compiler does not split an argument between Stack and Registers SP ??? Return addr (high) Return addr (low) e1 (low) e2 e3 e4 (high) CE-2810 Dr. Mark L. Hornick
What do you think would happen here? • Consider the function: • long add( long a, long b, long c, long d, int e, int f); • Also 20 bytes worth of arguments in this case CE-2810 Dr. Mark L. Hornick
The called subroutine must find the value of e on the Stack behind the return address • Example:long add( long a, long b, long c, long d, long e); • Parameters a, b, c, d (16 bytes) are passed using registers r25 to r10 • Remaining parameter e is passed as 4 bytes on the Stack in the calling code: in ZH, SPH ; load SP to Z in ZL, SPL ; Z points to cell containing ??? now. ldd temp, Z+3 ; load e1 to temp ldd temp, Z+4 ; load e2 to temp ... SP ??? Return addr (high) Return addr (low) e1 (low) e2 e3 e4 (high) CE-2810 Dr. Mark L. Hornick
General rules of register usage in mixed C/ASM These rules apply when you write assembly subroutines that you’re mixing with compiler-generated code • R0 – used by compiler as a temporary register • If you use R0 and then call code generated by the compiler, that code may overwrite R0 • R0 is not saved or restored by compiler-generated C code • So save it before calling compiler code, and restore it afterwards • R1 – assumed to always be 0 by the compiler • Save and clear it before calling compiler code, restore it after the compiler code returns • R2-R31 – used by compiler for various purposes • You must follow the compiler’s rules for register usage • If you are calling compiler code: • Save these before calling; restore after the call returns • If you are being called by compiler code: • Save first thing in your assembly subroutine; restore right before returning CE-2810 Dr. Mark L. Hornick
C and Assembly inEmbedded Systems software • Entire program in C… • …or mix C with assembly. Assembly is generally used for… • Critical code (size and efficiency) • Accessing certain hardware • Existing, proven code already written in assembly CS-280 Dr. Mark L. Hornick
Inline Assembly • Useful when writing mostly in C but a few assembly instructions are needed for… • Calling assembly subroutines • Accessing assembly global variables • (Not covered in detail) • Maximum efficiency for a small but often used piece of code CS-280 Dr. Mark L. Hornick
Inline assembly – calling a function void main() { ... __asm(“rcall sub1"); // Call routine without // a C interface ... } CS-280 Dr. Mark L. Hornick
extern variables • extern – The definition and label for something… • are external (present in another module) • will be resolved by the linker • extern modifies a declaration • Examples • Variables – stored in another module • Functions – implemented in another module CS-280 Dr. Mark L. Hornick
Accessing an assembly variable from C • Assembly .section .data .global counter counter: .word 0x1234 • C++ extern int counter; int main() { counter++; } CS-280 Dr. Mark L. Hornick
The volatile keyword • When a variable is declared volatile, the compiler will always ensure that an up-to-date value of that variable is manipulated whenever that variable is accesses. CS-280 Dr. Mark L. Hornick
Code generated without global variable y declared volatile int fun1() { y=y+3; DDRB = 0xFF; PORTB = 0x00; return y; } 000000be <fun1>: be: 80 91 60 00 lds r24, 0x0060 c2: 90 91 61 00 lds r25, 0x0061 c6: 03 96 adiw r24, 0x03 ; 3 c8: 90 93 61 00 sts 0x0061, r25 cc: 80 93 60 00 sts 0x0060, r24 d0: 2f ef ldi r18, 0xFF ; 255 d2: 27 bb out 0x17, r18 ; 23 d4: 18 ba out 0x18, r1 ; 24 d6: 08 95 ret CS-280 Dr. Mark L. Hornick
Code generated with global variable y declared volatile int fun1() { y=y+3; DDRB = 0xFF; PORTB = 0x00; return y; } 000000be <fun1>: be: 80 91 60 00 lds r24, 0x0060 c2: 90 91 61 00 lds r25, 0x0061 c6: 03 96 adiw r24, 0x03 ; 3 c8: 90 93 61 00 sts 0x0061, r25 cc: 80 93 60 00 sts 0x0060, r24 d0: 2f ef ldi r18, 0xFF ; 255 d2: 27 bb out 0x17, r18 ; 23 d4: 18 ba out 0x18, r1 ; 24 d6: 80 91 60 00 lds r24, 0x0060 da: 90 91 61 00 lds r25, 0x0061 de: 08 95 ret CS-280 Dr. Mark L. Hornick