Hi All. I'm having difficulty creating a Thumb-mode assembly language module that will successfully link in a uVision3+CARM project that is compiled in ARM mode. The module compiles, links and works fine with the rest of the project when everything is built in Thumb mode. Since CARM's calling convention and the module's internals conform with the ARM interworking veneer (or whatever it's called), it would seem to me that I could add PUBLIC FnName?A FnName?A to the existing PUBLIC FnName?T FnName?T PROC CODE16 in the Thumb assembly module so that the linker has an ARM-mode entry point into the function as well as its Thumb-mode entry point. But the function itself is purely Thumb mode, of course. Since the function is BL'd to, and the assembly module is written in Thumb and the function is EXEC16 (Thumb), its address is odd ([0]=1), and so the processor will successfully switch to Thumb mode from ARM when it executes the function via BL. Unfortunately, I'm having problems with the linker. Specifically, it's reporting alignment errors in other C modules in the project, if I build the entire project in ARM mode. Building in Thumb mode succeeds. The ARM docs (from ARM, not Keil) specifically mention an ALIGN assembler directive (see STM/LDM instruction summary examples). It seems to me that this might be the solution to my problem, if my problem is indeed due to a non-word alignment due to Thumb-mode instructions in an otherwise ARM build. Can anyone help? Thanks,
This is a code example:
AREA ?PR?myfunc, CODE, READONLY, ALIGN=2 PUBLIC myfunc?T, myfunc?A myfunc?T PROC CODE16 ; Thumb entry BX PC NOP ENDP myfunc?A PROC CODE32 ; ARM entry STMDB SP!,{R4, LR} ; save required registers RETURN: LDMIA SP!,{R4,LR} ; restore registers BX LR ; return to ARM or Thumb code
That looks promising -- can you also give an example where the "main code" is Thumb instead of ARM? Thanks,
OK, I worked it out:
$IF (MAKE_FOR_ARM = 1) $IF (MAKE_FOR_INTERWORK = 1) PUBLIC myfunc?T myfunc?T PROC CODE16 ; Thumb entry, ARM mode BX PC NOP ENDP $ENDIF PUBLIC myfunc?A myfunc?A PROC CODE32 ; ARM entry, ARM mode $ELSE $IF (MAKE_FOR_INTERWORK = 1) PUBLIC myfunc?A myfunc?A PROC CODE32 ; ARM entry, Thumb mode LDR R12,[PC] BX R12 ENDP $ENDIF PUBLIC myfunc?T myfunc?T PROC CODE16 ; Thumb entry, Thumb mode $ENDIF ... BX LR ENDP
Correction:
$IF (MAKE_FOR_ARM = 1) $IF (MAKE_FOR_INTERWORK = 1) PUBLIC myfunc?T myfunc?T PROC CODE16 ; Thumb entry, ARM mode BX PC NOP ENDP $ENDIF PUBLIC myfunc?A myfunc?A PROC CODE32 ; ARM entry, ARM mode $ELSE $IF (MAKE_FOR_INTERWORK = 1) PUBLIC myfunc?A myfunc?A PROC CODE32 ; ARM entry, Thumb mode ADR R0,myfunc?T BX R0 ENDP $ENDIF PUBLIC myfunc?T myfunc?T PROC CODE16 ; Thumb entry, Thumb mode $ENDIF ... BX LR ENDP
Here is the opposite example: Thumb Function which may be called from Thumb or ARM Code
AREA ?PR?myfunc, CODE, READONLY, ALIGN=2 PUBLIC myfunc?T, myfunc?A myfunc?A PROC CODE32 ; ARM entry LDR R12,[R15] BX R12 DD myfunc?T BX PC NOP ENDP myfunc?T PROC CODE16 ; ARM entry PUSH {R4, LR} ; save required registers RETURN: POP {R4} ; restore registers POP {R3} BX R3 ; return to ARM or Thumb code ENDP