This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Interworking Thumb-Mode Assembly Module -- How?

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
    is an example of assembly code that can be compiled as ARM or Thumb code, with or without the veneer for CPU mode switching ...

  • 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