4.3.1. Compiling code for interworking

The --apcs /interwork compiler option enables the ARM compiler to compile C and C++ modules containing routines that can be called by routines compiled for the other processor state:


armcc --c90 --thumb --apcs /interwork
armcc --c90 --arm --apcs /interwork
armcc --cpp --thumb --apcs /interwork
armcc --cpp --arm --apcs /interwork

Note

--arm is the default option. --c90 is the default for files with the extension .c, and --cpp is the default for files with the extension .cpp.

Modules that are compiled for interworking on ARMv4T generate slightly larger code. There is no difference for ARMv5.

In a leaf function, that is a function whose body contains no function calls, the only change in the code generated by the compiler is to replace MOV pc,lr with BX lr. The MOV instruction does not cause the necessary state change.

In nonleaf functions built for ARMv4T in Thumb mode, the compiler must replace, for example, the single instruction:

     POP  {r4,r5,pc}

with the sequence:

     POP  {r4,r5}	
     POP  {r3}	
     BX   r3

This has a small impact on performance. Compile all source modules for interworking, unless you are sure they are never going to be used with interworking.

The --apcs /interwork option also sets the interwork attribute for the code area the modules are compiled into. The linker detects this attribute and inserts the appropriate veneer.

Note

ARM code compiled for interworking can only be used on ARMv4T and later, because earlier processors do not implement the BX instruction.

Use the linker option --info veneers to find the amount of space taken by the veneers.

C interworking example

Example 4.3 shows a Thumb routine that carries out an interworking call to an ARM subroutine. The ARM subroutine call makes an interworking call to printf() in the Thumb library. These two modules are provided in the main examples directory, in ...\interwork as thumbmain.c and armsub.c.

Example 4.3. 

     /*********************
     *       thumbmain.c  *
     **********************/
     #include <stdio.h>
     extern void arm_function(void);
     int main(void)
     {
          printf("Hello from Thumb\n");	
          arm_function();	
          printf("And goodbye from Thumb\n");	
          return (0);	
     }

     /*********************
     *        armsub.c    *
     **********************/
     #include <stdio.h>
     void arm_function(void)
     {
          printf("Hello and Goodbye from ARM\n");	
     }

To compile and link these modules:

  1. To compile the Thumb code for interworking, type:


    armcc --thumb -c -g -O1 --apcs /interwork -o thumbmain.o thumbmain.c

  2. To compile the ARM code for interworking, type:


    armcc -c -g -O1 --apcs /interwork -o armsub.o armsub.c

  3. To link the object files, type:


    armlink thumbmain.o armsub.o -o thumbtoarm.axf

    Alternatively, to view the size of the interworking veneers (as shown in Example 4.4) type:


    armlink armsub.o thumbmain.o -o thumbtoarm.axf --info veneers

Example 4.4. 

    Adding TA veneer (4 bytes, Inline) for call to 'arm_function' from thumbmain.o(.text).
    Adding AT veneer (8 bytes, Inline) for call to '__0printf' from armsub.o(.text).
    Adding AT veneer (8 bytes, Inline) for call to '__rt_lib_init' from kernel.o(.text).
    Adding AT veneer (12 bytes, Long) for call to '__rt_lib_shutdown' from kernel.o(.text).
    Adding TA veneer (4 bytes, Inline) for call to '__aeabi_memclr4' from stdio.o(.text).
    Adding TA veneer (4 bytes, Inline) for call to '_mutex_initialize' from stdio.o(.text).
    Adding TA veneer (4 bytes, Inline) for call to '__rt_raise' from stdio.o(.text).
    Adding AT veneer (8 bytes, Inline) for call to '__raise' from rt_raise.o(.text).
    Adding TA veneer (4 bytes, Inline) for call to '__heap_extend' from malloc.o(.text).
    Adding TA veneer (4 bytes, Inline) for call to '__user_perproc_libspace' from malloc.o(.text).
    Adding TA veneer (8 bytes, Short) for call to '__rt_exit' from exit.o(.text).
    Adding TA veneer (4 bytes, Inline) for call to '_fp_init' from lib_init.o(.text).
    Adding TA veneer (4 bytes, Inline) for call to '__ARM_argv_veneer' from lib_init.o(.text). 
    Adding TA veneer (4 bytes, Inline) for call to '_sys_exit' from abort.o(.text).

14 Veneer(s) (total 80bytes) added to the image.	
Copyright © 2002-2006 ARM Limited. All rights reserved.ARM DUI 0203G
Non-Confidential