This is forwarded from PR58660
(<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58660>). Please CC me on
replies as I am not on the list.

In doing some testing of GCC 4.7.3 on a target with an ARMv4T CPU (e.g.
ARM7T or ARM9) I encountered a problem if using Thumb mode with
interworking disabled. For that, obviously I had to created a libgcc
multilib for this combination; for example: -mcpu=arm9 -mthumb
-mno-thumb-interwork.

However this fails to work in GCC 4.7.3 because of a problem in libgcc
making it fail to handle modes correctly for non-interworking operation. A
specific example is aeabi_uldivmod in bpabi.S which is an ARM (not thumb)
function, which includes a bl to __gnu_uldivmod_helper.
__gnu_uldivmod_helper is from bpabi.c and is in Thumb mode.

The linker helpfully adds a little trampoline to switch to Thumb mode
with the bx instruction (____gnu_uldivmod_helper_from_arm). However GCC
returns from __gnu_uldivmod_helper with:

  pop     {r3, r4, r5, r6, r7, pc}

This means that no mode switch happens on the return from the Thumb mode
function to the ARM mode aeabi_uldivmod function.

I am attaching a potential fix for the problem with aeabi_ldivmod and
aeabi_uldivmod (against 4.7.3), so it would be good for that to be applied
at least, including on the 4.7 and 4.8 branches.

2013-10-07  Jonathan Larmour  <j...@ecoscentric.com>

        * config/arm/bpabi.S (aeabi_ldivmod, aeabi_uldivmod): Allow for
        non-interworking Thumb builds.

Someone may also want to double-check whether this sort of problem may
apply to other functions (although I haven't found any others yet myself,
but I'm not sure about how functions like those in unaligned-funcs.c would
be called).

Thanks,

Jifl
-- 
eCosCentric Limited      http://www.eCosCentric.com/     The eCos experts
Barnwell House, Barnwell Drive, Cambridge, UK.       Tel: +44 1223 245571
Registered in England and Wales: Reg No 4422071.
------["Si fractum non sit, noli id reficere"]------       Opinions==mine
diff -x CVS -x .svn -x '*~' -x '.#*' -x autom4te.cache -urpN 
gcc-4.7.3.pre/libgcc/config/arm/bpabi.S gcc-4.7.3/libgcc/config/arm/bpabi.S
--- gcc-4.7.3.pre/libgcc/config/arm/bpabi.S     2011-11-02 15:03:19.000000000 
+0000
+++ gcc-4.7.3/libgcc/config/arm/bpabi.S 2013-10-07 23:39:05.508083589 +0100
@@ -133,10 +133,25 @@ ARM_FUNC_START aeabi_ldivmod
 #else
        do_push {sp, lr}
 #endif
+#if defined(__INTERWORKING_STUBS__)
+       /* In this case, __gnu_ldivmod_helper is compiled in Thumb mode, but
+          without interworking. This means it needs to be called in Thumb
+          mode, and will return in Thumb mode, not ARM. So we handle that.  */
+       orr ip, pc, #1
+       bx ip
+       .code 16
+       bl SYM(__gnu_ldivmod_helper) __PLT__
+       ldr r2, [sp, #4]
+       mov lr, r2
+       ldr r2, [sp, #8]
+       ldr r3, [sp, #12]
+       add sp, sp, #16
+#else
        bl SYM(__gnu_ldivmod_helper) __PLT__
        ldr lr, [sp, #4]
        add sp, sp, #8
        do_pop {r2, r3}
+#endif
        RET
        
 #endif /* L_aeabi_ldivmod */
@@ -153,10 +168,25 @@ ARM_FUNC_START aeabi_uldivmod
 #else
        do_push {sp, lr}
 #endif
+#if defined(__INTERWORKING_STUBS__)
+       /* In this case, __gnu_uldivmod_helper is compiled in Thumb mode, but
+          without interworking. This means it needs to be called in Thumb
+          mode, and will return in Thumb mode, not ARM. So we handle that.  */
+       orr ip, pc, #1
+       bx ip
+       .code 16
+       bl SYM(__gnu_uldivmod_helper) __PLT__
+       ldr r2, [sp, #4]
+       mov lr, r2
+       ldr r2, [sp, #8]
+       ldr r3, [sp, #12]
+       add sp, sp, #16
+#else
        bl SYM(__gnu_uldivmod_helper) __PLT__
        ldr lr, [sp, #4]
        add sp, sp, #8
        do_pop {r2, r3}
+#endif
        RET
        
 #endif /* L_aeabi_divmod */

Reply via email to