https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86755
Bug ID: 86755 Summary: [ASAN] Libasan failed to be build for arm with -mthumb and -fno-omit-frame-pointer Product: gcc Version: 9.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: sanitizer Assignee: unassigned at gcc dot gnu.org Reporter: d.khalikov at partner dot samsung.com CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org, jakub at gcc dot gnu.org, kcc at gcc dot gnu.org, marxin at gcc dot gnu.org Target Milestone: --- Created attachment 44471 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44471&action=edit Reduced test case GCC fails to build libasan with -mthumb and -fno-omit-frame-pointer ../../../../libsanitizer/sanitizer_common/sanitizer_linux.cc: In function '__sanitizer::uptr __sanitizer::internal_clone(int (*)(void*), void*, int, void*, int*, void*, int*)': ../../../../libsanitizer/sanitizer_common/sanitizer_linux.cc:1540:1: error: r7 cannot be used in asm here } The problem is inside internal_clone function defined for arm. Reduced test case: $cat clone.cc #define __NR_clone 120 #define __NR_exit 1 using uptr = unsigned int; unsigned int EINVAL = 1; uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { unsigned int res; if (!fn || !child_stack) return -EINVAL; child_stack = (char *)child_stack - 2 * sizeof(unsigned int); ((unsigned int *)child_stack)[0] = (uptr)fn; ((unsigned int *)child_stack)[1] = (uptr)arg; register int r0 __asm__("r0") = flags; register void *r1 __asm__("r1") = child_stack; register int *r2 __asm__("r2") = parent_tidptr; register void *r3 __asm__("r3") = newtls; register int *r4 __asm__("r4") = child_tidptr; register int r7 __asm__("r7") = __NR_clone; #if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__) # define ARCH_HAS_BX #endif #if __ARM_ARCH > 4 # define ARCH_HAS_BLX #endif #ifdef ARCH_HAS_BX # ifdef ARCH_HAS_BLX # define BLX(R) "blx " #R "\n" # else # define BLX(R) "mov lr, pc; bx " #R "\n" # endif #else # define BLX(R) "mov lr, pc; mov pc," #R "\n" #endif __asm__ __volatile__( /* %r0 = syscall(%r7 = SYSCALL(clone), * %r0 = flags, * %r1 = child_stack, * %r2 = parent_tidptr, * %r3 = new_tls, * %r4 = child_tidptr) */ /* Do the system call */ "swi 0x0\n" /* if (%r0 != 0) * return %r0; */ "cmp r0, #0\n" "bne 1f\n" /* In the child, now. Call "fn(arg)". */ "ldr r0, [sp, #4]\n" "ldr ip, [sp], #8\n" BLX(ip) /* Call _exit(%r0). */ "mov r7, %7\n" "swi 0x0\n" "1:\n" "mov %0, r0\n" : "=r"(res) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), "i"(__NR_exit) : "memory"); return res; } $armv7l-linux-gnueabi-g++ -o clone.s clone.cc -fno-omit-frame-pointer -mthumb -S clone.cc: In function ‘uptr internal_clone(int (*)(void*), void*, int, void*, int*, void*, int*)’: clone.cc:70:1: error: r7 cannot be used in asm here Regarding to arm ABI, r7 register is using for syscall number, r0 for return value, and r1 - r6 for syscall arguments, by the way r7 for arm with THUMB2 mode is using as frame pointer and it looks like we have a conflict in this case. As far as I understood, GCC has a special check inside IRA if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM)), which does not allow to have frame pointer register as clobber register. In other way, there is no issue with clang: clang++ -target armv7l -S -o clone.s clone.cc -mthumb -fno-omit-frame-pointer So, looks like we can save syscall number in r8 register, move it to r7 before we the interruption, and restore the value in the parent task. register int r8 __asm__("r8") = __NR_clone; __asm__ __volatile__( /* %r0 = syscall(%r7 = SYSCALL(clone), * %r0 = flags, * %r1 = child_stack, * %r2 = parent_tidptr, * %r3 = new_tls, * %r4 = child_tidptr) */ "push {r7}\n" "mov r7, r8\n" /* Do the system call */ "swi 0x0\n" /* if (%r0 != 0) * return %r0; */ "cmp r0, #0\n" "bne 1f\n" /* In the child, now. Call "fn(arg)". */ "ldr r0, [sp, #4]\n" "ldr ip, [sp], #8\n" BLX(ip) /* Call _exit(%r0). */ "mov r7, %7\n" "swi 0x0\n" "1:\n" "pop {r7}\n" "mov %0, r0\n" : "=r"(res) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r8), "i"(__NR_exit) : "memory"); return res; }