1 / 21

Mixing C and assembly

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

keegan
Download Presentation

Mixing C and assembly

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Mixing C and assembly Safety goggles on! CE-2810 Dr. Mark L. Hornick

  2. 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

  3. 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

  4. 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

  5. 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

  6. 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

  7. 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

  8. 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

  9. 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

  10. 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

  11. 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

  12. 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

  13. 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

  14. 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

  15. 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

  16. Inline assembly – calling a function void main() { ... __asm(“rcall sub1"); // Call routine without // a C interface ... } CS-280 Dr. Mark L. Hornick

  17. 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

  18. 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

  19. 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

  20. 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

  21. 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

More Related