Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
navlrac
PostPosted: Jul 23, 2007 - 03:48 PM
Rookie


Joined: May 02, 2007
Posts: 30
Location: Sydney, Australia

It seems theres a bug in the AVR32 GCC inline assembly handling when there is a lack of registers to use.

Consider:
Code:
#define SYS_XX 27

long
SyscallXX(long arg0, long arg1, long arg2, long arg3, long arg4,
          long arg5, long *ret0, long *ret1)
{
    register long sys asm("r8") = SYS_XX;
    register long r12 asm("r12") = arg0;
    register long r11 asm("r11") = arg1;
    register long r10 asm("r10") = arg2;
    register long r9 asm("r9") = arg3;
    register long r7 asm("r7") = arg4;
    register long r6 asm("r6") = arg5;
    __asm__ __volatile__ (
        "   scall                       \n"
        : "+r" (sys), "+r" (r12), "+r" (r11),
          "+r" (r10), "+r" (r9), "+r" (r7),
          "+r" (r6)
        :: "r0", "r1", "r2", "r3", "r4", "r5", "memory"
    );
    if (ret0)
        *ret0 = r11;
    if (ret1)
        *ret1 = r10;
    return r12;     // result in r12
}


compiling with avr-linux-gcc -O2 yields:

Code:
00000012 <SyscallXX>:
  12:   eb cd 40 bf     pushm r0-r5,r7,lr
                        12: R_AVR32_ALIGN       *ABS*+0x1
  16:   fa ce ff e0     sub lr,sp,-32
  1a:   7c 17           ld.w r7,lr[0x4]
  1c:   40 86           lddsp r6,sp[0x20]
  1e:   7c 2e           ld.w lr,lr[0x8]
  20:   31 b8           mov r8,27
  22:   d7 33           scall
  24:   58 07           cp.w r7,0
  26:   c0 00           breq 26 <SyscallXX+0x14>
                        26: R_AVR32_9H_PCREL    .text+0x2a
  28:   8f 0b           st.w r7[0x0],r11
  2a:   58 0e           cp.w lr,0
  2c:   c0 00           breq 2c <SyscallXX+0x1a>
                        2c: R_AVR32_9H_PCREL    .text+0x30
  2e:   9d 0a           st.w lr[0x0],r10
  30:   e3 cd 80 bf     ldm sp++,r0-r5,r7,pc


As you can see, r7 is being used as a value holding ret0 rather than arg4. This is likely due to having few registers available. The compile should have loaded ret0 off the stack since only r14 and r13 are unmodified in the assembly block.

If there were no free registers, the compiler should abort with an error, however clobbering r14 (lr) in the list, the compiler generates worse assembly, ignoring the clobber on r4 for example.
 
 View user's profile Send private message  
Reply with quote Back to top
GregoryC
PostPosted: Jul 23, 2007 - 08:46 PM
Hangaround


Joined: Apr 27, 2007
Posts: 136


Have you done inline assembly before?

I would expect more like this:

Code:
asm("mov r12, arg0");
etc...


I don't believe you can create a register object using a construct like asm("r8"). Rather, I would expect you must include an entire assembly language instruction including operands within the asm(" ... ") construct.
 
 View user's profile Send private message  
Reply with quote Back to top
navlrac
PostPosted: Jul 24, 2007 - 02:47 AM
Rookie


Joined: May 02, 2007
Posts: 30
Location: Sydney, Australia

GregoryC wrote:
Have you done inline assembly before?


I've only been writing kernel code with extensive inline assembly on ARM, MIPS, POWERPC, X86 and IA64 for the past 8 years Wink I think what I'm trying to do is sane. GCC on other architectures does a better job and doesn't randomly violate constraints and register assignments.

Quote:

I would expect more like this:

Code:
asm("mov r12, arg0");
etc...



Sure, but thats a waste since you have an extra mov instruction per argument and the compiler does not know which registers you are using. Actuall what you suggest does not work when you have multiple arguments since you need a distinct set of input registers and assigned registers (unless you push everything to the stack and pop it back).
ie:

mov r12, arg0
mov r11, arg1
mov r10, arg2
mov r9, arg3

the compiler is free to choose r12 for arg3 (unless you expilictly add r12 to the clobber list) which will break. If you add all the left-hand-side registers to the clobber list, there will be no free registers for input, besides the AVR32 GCC just ignores that when there is a lack of registers and generates broken code Sad

Quote:

I don't believe you can create a register object using a construct like asm("r8").

Of coarse you can!
 
 View user's profile Send private message  
Reply with quote Back to top
GregoryC
PostPosted: Jul 24, 2007 - 08:07 PM
Hangaround


Joined: Apr 27, 2007
Posts: 136


I've used inline assembly countless times over the past 1-2 decades on numerous different compilers and I've never seen one that does that. All the inline I've seen the compiler simply takes the part between the quotes and spits that into the assembly code being generated.
Quote:
Of coarse you can!

Okay hotshot, but evidently you can't! Razz Wink (and it's 'of course') Smile

I'll be very interested if somebody shows how what you want can be done. It will be the first time I've ever seen that in inline! Would you accept no responses or solely negative responses as proof it can't be done? I'll accept as proof your posting a working example.
 
 View user's profile Send private message  
Reply with quote Back to top
navlrac
PostPosted: Jul 25, 2007 - 03:35 AM
Rookie


Joined: May 02, 2007
Posts: 30
Location: Sydney, Australia

This is kind of pointless arguing.

The fact is, the AVR32 GCC compiler is causing lots of problems on inline assembly and frequently is violating or ignoring constraints.

Some examples for you: (arm, ia64, powerpc, powerpc64, mips64, sparc64, alpha)
http://www.disy.cse.unsw.edu.au/lxr/aos ... syscalls.h
http://www.disy.cse.unsw.edu.au/lxr/aos ... syscalls.h
http://www.disy.cse.unsw.edu.au/lxr/aos ... syscalls.h
http://www.disy.cse.unsw.edu.au/lxr/aos ... syscalls.h
http://www.disy.cse.unsw.edu.au/lxr/aos ... syscalls.h
http://www.disy.cse.unsw.edu.au/lxr/aos ... syscalls.h
http://www.disy.cse.unsw.edu.au/lxr/aos ... syscalls.h

See:
http://gcc.gnu.org/onlinedocs/gcc/Local-Reg-Vars.html
http://gcc.gnu.org/onlinedocs/gcc/Exten ... 0asm%20reg
http://www.ethernut.de/en/documents/arm-inline-asm.html

There are tons of examples around:
http://www.gelato.unsw.edu.au/lxr/sourc ... h/unistd.h
http://www.gelato.unsw.edu.au/lxr/sourc ... r/unistd.h
http://wiki.tuxedo-es.org/ARM_Assembly
http://www.gelato.unsw.edu.au/lxr/sourc ... 2/unistd.h
http://www.koders.com/c/fid49461D80E02A ... 28FCA.aspx
http://www.koders.com/c/fid65FA5A49DC99 ... AE934.aspx
http://www.koders.com/c/fidF73555DCDF6F ... 30963.aspx

All these work in production kernel/libc etc code with GCC.
 
 View user's profile Send private message  
Reply with quote Back to top
how
PostPosted: Aug 03, 2007 - 10:23 PM
Posting Freak


Joined: Apr 26, 2006
Posts: 1079
Location: Trondheim, Norway

navlrac is right. gcc seems to be very confused by something, although the example looks like a horribly complicated way to do syscalls...

GregoryC, welcome to the wonderful world of gcc and its extremely powerful and subtle inline assembly syntax. Have a look at the syscall stubs in uClibc some time -- they use the exact same technique to load syscall parameters into specific registers, although it doesn't clobber nearly as many other registers...

Btw, note that r7 is sometimes used as framepointer and r6 as GOT pointer. If you're compiling with frame pointers and/or PIC, it could be gcc is getting confused by you clobbering those registers. But even if it is, silently generating wrong code is definitely a bug -- it should at least output a big fat warning message.
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits