[LLVMdev] Bug in ARM Thumb inline asm?

Richard Pennington rich at pennware.com
Wed Feb 18 11:12:32 PST 2015


On 02/10/2015 03:10 PM, Richard Pennington wrote:
> I'm porting the musl C library to ARM Thumb. It looks like inline asm 
> is failing in some cases. Here's one:

I've put together a simple test file and am puzzled by the results.
If I compile this for Thumb:

typedef long long off_t;

#if 1
long foo(long);
#else
#define foo(x) (x)
#endif

#if 1
inline long __syscall5(n, a, b, c, d, e)
{
  register long r7 __asm__("r7") = n;
  register long r0 __asm__("r0") = a;
  register long r1 __asm__("r1") = b;
  register long r2 __asm__("r2") = c;
  register long r3 __asm__("r3") = d;
  register long r4 __asm__("r4") = e;
  do { __asm__ __volatile__ ( "svc 0" : "=r"(r0) : "r"(r7), "0"(r0), 
"r"(r1), "r"(r2), "r"(r3), "r"(r4) : "memory"); return r0; } while (0);
}
#else

#define __syscall5(n, a, b, c, d, e) \
({ \
  register long r7 __asm__("r7") = n; \
  register long r0 __asm__("r0") = a; \
  register long r1 __asm__("r1") = b; \
  register long r2 __asm__("r2") = c; \
  register long r3 __asm__("r3") = d; \
  register long r4 __asm__("r4") = e; \
  do { __asm__ __volatile__ ( "svc 0" : "=r"(r0) : "r"(r7), "0"(r0), 
"r"(r1), "r"(r2), "r"(r3), "r"(r4) : "memory"); return r0; } while (0); \
  ;r0; })
#endif

off_t lseek(int fd, off_t offset, int whence)
{

  off_t result;
  return foo(__syscall5(140,((long) (fd)),((long) (offset>>32)),
    ((long) (offset)),((long) (&result)),((long) (whence)))) ? -1 : result;
}

I get

         .globl  lseek
         .align  2
         .type   lseek,%function
         .code   16                      @ @lseek
         .thumb_func
lseek:
         .fnstart
.Leh_func_begin0:
@ BB#0:                                 @ %entry
         push    {r4, r7, lr}
         add     r7, sp, #4
         sub     sp, #12
         movs    r7, #140
         mov     r12, sp
         mov     r1, r3
         ldr     r4, [r7, #8]
         mov     r3, r12
         @APP
         svc     #0
         @NO_APP
         bl      foo
         ldr     r2, [sp]
         ldr     r1, [sp, #4]
         cmp     r0, #0
         itt     ne
         movne.w r2, #-1
         movne.w r1, #-1
         mov     r0, r2
         add     sp, #12
         pop     {r4, r7, pc}
.Ltmp0:
         .size   lseek, .Ltmp0-lseek
         .cantunwind
         .fnend

where the "ldr r4, [r7, #8]" instruction uses r7 as a frame pointer even 
though it was over-written earlier.

If I use -fomit-frame-pointer or any other combination if the 
conditionals (macro vs. inline, used as a function parameter vs. not) 
the code emitted is correct.

Is there some in the original code that causes it to break while the 
other forms do not? Or are the other forms working just because of luck?
Should the original code work?

-Rich



More information about the llvm-dev mailing list