Search |
 |
|
 |
| Author |
Message |
|
|
Posted: Jul 23, 2007 - 03:48 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jul 23, 2007 - 08:46 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jul 24, 2007 - 02:47 AM |
|

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 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
Quote:
I don't believe you can create a register object using a construct like asm("r8").
Of coarse you can! |
|
|
| |
|
|
|
|
|
Posted: Jul 24, 2007 - 08:07 PM |
|

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! (and it's 'of course')
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. |
|
|
| |
|
|
|
|
|
Posted: Jul 25, 2007 - 03:35 AM |
|

Joined: May 02, 2007
Posts: 30
Location: Sydney, Australia
|
|
|
|
|
|
|
Posted: Aug 03, 2007 - 10:23 PM |
|


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