Hi group! I try to inline a very simple SWI call that returns a value in r0. Somehow I must do it wrong, as gcc messes up the registers. Here's the code: /*** armtest.c ***/ void test(void); void my_printf(const char *fmt, ...); static inline int getXXX(void) { register long res_r0 asm("r0"); long res; asm volatile ("swi 42" : "=r" (res_r0) : : "r12", "cc"); res = res_r0; return (int)res; } void test(void) { my_printf("XXX=%d\n", getXXX()); } /****/ Compile with: arm-elf-gcc -Os -c armtest.c -o armtest.o Disassembly or armtest.o gives: 0: ef00002a swi 0x0000002a 4: e59f0004 ldr r0, [pc, #4] ; 10 <.text+0x10> 8: e1a01000 mov r1, r0 c: eafffffe b c <test+0xc> 10: 00000000 andeq r0, r0, r0 Note how gcc clobbers r0 at offset 4. my_printf would have expected the string pointer in r0 and the result of the swi call in r1. This is the GCC version: Using built-in specs. Target: arm-elf Configured with: ../gcc-4.1.1/configure --target=arm-elf --prefix=/local/gnuarm-4.1.1 --enable-interwork --enable-multilib --enable-languages=c,c++ Thread model: single gcc version 4.1.1 What am I doing wrong? Thanks in advance!
It looks like r0 and r1 are both set to 0. I tried to reproduce this here (with WinARM 20060606) but the result is different (of cause the "other code" might be completly different from yours). [...] static inline int getXXX(void) { register long res_r0 asm("r0"); long res; asm volatile ("swi 42" : "=r" (res_r0) : : "r12", "cc"); res = res_r0; return (int)res; } static inline int getXXX2(void) { unsigned long res; asm ("swi 42; mov %0, r0" : "=r" (res) : : "r0"); return (int)res; } #define rprintf efsl_debug_printf_arm int main(void) { int ch; int8_t res; systemInit(); gpioInit(); uart1Init(UART_BAUD(BAUD), UART_8N1, UART_FIFO_8); // setup the UART /* init efsl debug-output */ efsl_debug_devopen_arm(uart1Putch); ledToggle(); ch = 20; rprintf("T1: %i", ch); rprintf("T2: %i", getXXX() ); rprintf("T3: %i", getXXX2() ); [...] [...] ledToggle(); 1d8: f7ff ffb0 bl 13c <ledToggle> ch = 20; rprintf("T1: %i", ch); 1dc: 4818 ldr r0, [pc, #96] (240 <.text+0x240>) 1de: 2114 movs r1, #20 1e0: f000 f93c bl 45c <efsl_debug_printf_arm> 1e4: df2a svc 42 rprintf("T2: %i", getXXX() ); 1e6: 4917 ldr r1, [pc, #92] (244 <.text+0x244>) 1e8: 1c08 adds r0, r1, #0 1ea: f000 f937 bl 45c <efsl_debug_printf_arm> 1ee: df2a svc 42 1f0: 1c01 adds r1, r0, #0 rprintf("T3: %i", getXXX2() ); 1f2: 4815 ldr r0, [pc, #84] (248 <.text+0x248>) 1f4: f000 f932 bl 45c <efsl_debug_printf_arm> [...] Please create minimal example (source incl. startup-up, makefile, linker-scripts) place it somewhere on an internet-server and send the link here. Martin Thomas
Martin Thomas wrote:
> It looks like r0 and r1 are both set to 0.
This is because the code is not linked yet. I provided the disassembly
of
the armtest.o file.
However, the test you did comes out wrong too here:
1e4: df2a svc 42
rprintf("T2: %i", getXXX() );
1e6: 4917 ldr r1, [pc, #92] (244 <.text+0x244>)
1e8: 1c08 adds r0, r1, #0
1ea: f000 f937 bl 45c <efsl_debug_printf_arm>
At offset 1e8 the r0 register is clobbered.
It seems that gcc does not know that getXXX() returns a value it r0.
getXXX2() does the trick, but has some overhead (sometimes).
I wonder where's the problem here...
Thanks for replying!
Geroge Miller wrote: > At offset 1e8 the r0 register is clobbered. > It seems that gcc does not know that getXXX() returns a value it r0. > > getXXX2() does the trick, but has some overhead (sometimes). Yes, sorry, I should have mentioned that "getXXX2" is my proposal to implement this. I try to avoid "register" where possible. This might produce an overhead but I think this approach is "cleaner" - But this is just a personal "style". > I wonder where's the problem here... Currently I do not know either. Maybe someone else can jump in here and give an explanation. Martin Thomas
Martin Thomas wrote: > Geroge Miller wrote: >> At offset 1e8 the r0 register is clobbered. >> It seems that gcc does not know that getXXX() returns a value it r0. >> >> getXXX2() does the trick, but has some overhead (sometimes). > Currently I do not know either. Maybe someone else can jump in here and > give an explanation. Looking for help with my own swi/gcc problem I came across this long-dormant thread. Surely by now it's been figured out, but anyway, getXXX() does not provide gcc with a %0 placeholder to represent the output argument. So it doesn't surprise me that gcc assumes there is no output. getXXX2() works because it has a %0 placeholder for which gcc can substitute the output argument. I'm not aware that gcc is obliged to assume an output in r0 if not explicitly told. The extra overhead is annoying all right but if you really crank up the optimizer a lot of it goes away. Which leads me to another problem I'm putting in a new thread.
I take it back, yes according to the manual this should work. The manual gives the explicit example register int *p1 asm ("r0") = ...; register int *p2 asm ("r1") = ...; register int *result asm ("r0"); asm ("sysint" : "=r" (result) : "0" (p1), "r" (p2)); For the case of a software interrupt (although for a different architecture). No % placeholders anywhere and the manual authors expected this to work. And for the record, I'm having trouble with this too (arm-elf-gcc 4.1.0).
George, I don't know if you're tracking this, but I think I found a solution. You need to modify your swi call from this: asm volatile ("swi 42" : "=r" (res_r0) : : "r12", "cc"); to this: asm volatile ("swi 42 @ %0" : "=r" (res_r0) : : "r12", "cc"); Apparently the inline assembler, when it sees no %0, %1, etc.-type arguments in the assembler text, decides to ignore any input and output arguments that follow. Including a %0 in the assembler text assures the inline assembler that this argument really does get used. The fact that it is in a comment (it comes after the @ character) keeps other errors at bay. If you want to pass pointers to an SWI there are other compilation issues, at least if you optimize. See my thread on gcc and swi for details (http://en.mikrocontroller.net/topic/146800)
Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
Log in with Google account
No account? Register here.