ROOL C, writing local variable in inline assembler via pointer.
Timothy Baldwin (184) 242 posts |
The C compiler in DDE30 compiles this:
Into this:
Unfortunately both those functions return 0 despite that __PVirt_LinuxSyscall has a pointer to pts_no. In this scenario GCC requires the addition of “memory” to the clobber list of the inline assembler, but nothing is documented for DDE. Inserting calls __schedule_barrier() before (or before and after, but not just after) the inline assembler seems to fix the issue, but that is not a documented behaviour. Is the compiler broken, and is inserting __schedule_barrier() before and after the inline assembly a reasonable workaround? In the original code the inline assembler is in inline functions. |
Stuart Swales (1481) 351 posts |
By fix do you mean actually initialising pts_no to zero before the call in command_handler? The compiler is surely wrong here. |
Rick Murray (539) 13751 posts |
Have you tried fully specifying all the registers, such as: BL __PVirt_LinuxSyscall, {R2}, {}, {PSR} Just in case that makes a difference? But, yes, reading the code it certainly looks like the compiler is failing to properly recognise R2 as a dependency of the branch, so it’s doing the branch part first and then setting the value of R2… |
Jeffrey Lee (213) 6048 posts |
Yeah, it looks like Norcroft is missing the memory clobber functionality. Since the compiler isn’t aware that pts_no is being modified, I think your options are:
One thing that doesn’t work is moving the assembler block into a (static inline) function, i.e.: static inline void call_syscall(void *arg) { __asm { MOV R2, arg BL __PVirt_LinuxSyscall, {R2} } } ... call_syscall(&pts_no); |
Timothy Baldwin (184) 242 posts |
I didn’t spot that failure, but that is broken as well. I was just looking for a read from the memory location passed Have you tried fully specifying all the registers, such as: Adding PSR to the clobber section makes no difference. Here is a more complete and would be functional example:
Unfortunately putting __schedule_barrier() calls in the inline function doesn’t work. But putting it before call does workaround the problem, so I have added lots macros to wrap the inline functions. Also leaving pts_no uninitialised prevents the read being omitted, but this is useless if it is required to be initialised. And here is the complete routine the calls the inline functions with fixes. |
Timothy Baldwin (184) 242 posts |
Also if local variable is an array or struct it works correctly, which would explain why it works in most cases; most RISC OS non-APCS routines do not take pointers to small word sized values. |