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!
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)