190075Sobrien Arm / Thumb Interworking 290075Sobrien ======================== 390075Sobrien 490075SobrienThe Cygnus GNU Pro Toolkit for the ARM7T processor supports function 590075Sobriencalls between code compiled for the ARM instruction set and code 690075Sobriencompiled for the Thumb instruction set and vice versa. This document 790075Sobriendescribes how that interworking support operates and explains the 890075Sobriencommand line switches that should be used in order to produce working 990075Sobrienprograms. 1090075Sobrien 1190075SobrienNote: The Cygnus GNU Pro Toolkit does not support switching between 1290075Sobriencompiling for the ARM instruction set and the Thumb instruction set 1390075Sobrienon anything other than a per file basis. There are in fact two 1490075Sobriencompletely separate compilers, one that produces ARM assembler 1590075Sobrieninstructions and one that produces Thumb assembler instructions. The 1690075Sobrientwo compilers share the same assembler, linker and so on. 1790075Sobrien 1890075Sobrien 1990075Sobrien1. Explicit interworking support for C and C++ files 2090075Sobrien==================================================== 2190075Sobrien 2290075SobrienBy default if a file is compiled without any special command line 2390075Sobrienswitches then the code produced will not support interworking. 2490075SobrienProvided that a program is made up entirely from object files and 2590075Sobrienlibraries produced in this way and which contain either exclusively 2690075SobrienARM instructions or exclusively Thumb instructions then this will not 2790075Sobrienmatter and a working executable will be created. If an attempt is 2890075Sobrienmade to link together mixed ARM and Thumb object files and libraries, 2990075Sobrienthen warning messages will be produced by the linker and a non-working 3090075Sobrienexecutable will be created. 3190075Sobrien 3290075SobrienIn order to produce code which does support interworking it should be 3390075Sobriencompiled with the 3490075Sobrien 3590075Sobrien -mthumb-interwork 3690075Sobrien 3790075Sobriencommand line option. Provided that a program is made up entirely from 3890075Sobrienobject files and libraries built with this command line switch a 3990075Sobrienworking executable will be produced, even if both ARM and Thumb 4090075Sobrieninstructions are used by the various components of the program. (No 4190075Sobrienwarning messages will be produced by the linker either). 4290075Sobrien 4390075SobrienNote that specifying -mthumb-interwork does result in slightly larger, 4490075Sobrienslower code being produced. This is why interworking support must be 4590075Sobrienspecifically enabled by a switch. 4690075Sobrien 4790075Sobrien 4890075Sobrien2. Explicit interworking support for assembler files 4990075Sobrien==================================================== 5090075Sobrien 5190075SobrienIf assembler files are to be included into an interworking program 5290075Sobrienthen the following rules must be obeyed: 5390075Sobrien 5490075Sobrien * Any externally visible functions must return by using the BX 5590075Sobrien instruction. 5690075Sobrien 5790075Sobrien * Normal function calls can just use the BL instruction. The 5890075Sobrien linker will automatically insert code to switch between ARM 5990075Sobrien and Thumb modes as necessary. 6090075Sobrien 6190075Sobrien * Calls via function pointers should use the BX instruction if 6290075Sobrien the call is made in ARM mode: 6390075Sobrien 6490075Sobrien .code 32 6590075Sobrien mov lr, pc 6690075Sobrien bx rX 6790075Sobrien 6890075Sobrien This code sequence will not work in Thumb mode however, since 6990075Sobrien the mov instruction will not set the bottom bit of the lr 7090075Sobrien register. Instead a branch-and-link to the _call_via_rX 7190075Sobrien functions should be used instead: 7290075Sobrien 7390075Sobrien .code 16 7490075Sobrien bl _call_via_rX 7590075Sobrien 7690075Sobrien where rX is replaced by the name of the register containing 7790075Sobrien the function address. 7890075Sobrien 7990075Sobrien * All externally visible functions which should be entered in 8090075Sobrien Thumb mode must have the .thumb_func pseudo op specified just 81169689Skan before their entry point. e.g.: 8290075Sobrien 8390075Sobrien .code 16 8490075Sobrien .global function 8590075Sobrien .thumb_func 8690075Sobrien function: 8790075Sobrien ...start of function.... 8890075Sobrien 8990075Sobrien * All assembler files must be assembled with the switch 9090075Sobrien -mthumb-interwork specified on the command line. (If the file 9190075Sobrien is assembled by calling gcc it will automatically pass on the 9290075Sobrien -mthumb-interwork switch to the assembler, provided that it 9390075Sobrien was specified on the gcc command line in the first place.) 9490075Sobrien 9590075Sobrien 9690075Sobrien3. Support for old, non-interworking aware code. 9790075Sobrien================================================ 9890075Sobrien 9990075SobrienIf it is necessary to link together code produced by an older, 10090075Sobriennon-interworking aware compiler, or code produced by the new compiler 10190075Sobrienbut without the -mthumb-interwork command line switch specified, then 10290075Sobrienthere are two command line switches that can be used to support this. 10390075Sobrien 10490075SobrienThe switch 10590075Sobrien 10690075Sobrien -mcaller-super-interworking 10790075Sobrien 10890075Sobrienwill allow calls via function pointers in Thumb mode to work, 10990075Sobrienregardless of whether the function pointer points to old, 11090075Sobriennon-interworking aware code or not. Specifying this switch does 11190075Sobrienproduce slightly slower code however. 11290075Sobrien 11390075SobrienNote: There is no switch to allow calls via function pointers in ARM 11490075Sobrienmode to be handled specially. Calls via function pointers from 11590075Sobrieninterworking aware ARM code to non-interworking aware ARM code work 11690075Sobrienwithout any special considerations by the compiler. Calls via 11790075Sobrienfunction pointers from interworking aware ARM code to non-interworking 11890075Sobrienaware Thumb code however will not work. (Actually under some 11990075Sobriencircumstances they may work, but there are no guarantees). This is 12090075Sobrienbecause only the new compiler is able to produce Thumb code, and this 12190075Sobriencompiler already has a command line switch to produce interworking 12290075Sobrienaware code. 12390075Sobrien 12490075Sobrien 12590075SobrienThe switch 12690075Sobrien 12790075Sobrien -mcallee-super-interworking 12890075Sobrien 12990075Sobrienwill allow non-interworking aware ARM or Thumb code to call Thumb 13090075Sobrienfunctions, either directly or via function pointers. Specifying this 13190075Sobrienswitch does produce slightly larger, slower code however. 13290075Sobrien 13390075SobrienNote: There is no switch to allow non-interworking aware ARM or Thumb 13490075Sobriencode to call ARM functions. There is no need for any special handling 13590075Sobrienof calls from non-interworking aware ARM code to interworking aware 13690075SobrienARM functions, they just work normally. Calls from non-interworking 13790075Sobrienaware Thumb functions to ARM code however, will not work. There is no 13890075Sobrienoption to support this, since it is always possible to recompile the 13990075SobrienThumb code to be interworking aware. 14090075Sobrien 14190075SobrienAs an alternative to the command line switch 14290075Sobrien-mcallee-super-interworking, which affects all externally visible 14390075Sobrienfunctions in a file, it is possible to specify an attribute or 14490075Sobriendeclspec for individual functions, indicating that that particular 14590075Sobrienfunction should support being called by non-interworking aware code. 14690075SobrienThe function should be defined like this: 14790075Sobrien 14890075Sobrien int __attribute__((interfacearm)) function 14990075Sobrien { 15090075Sobrien ... body of function ... 15190075Sobrien } 15290075Sobrien 15390075Sobrienor 15490075Sobrien 15590075Sobrien int __declspec(interfacearm) function 15690075Sobrien { 15790075Sobrien ... body of function ... 15890075Sobrien } 15990075Sobrien 16090075Sobrien 16190075Sobrien 16290075Sobrien4. Interworking support in dlltool 16390075Sobrien================================== 16490075Sobrien 16590075SobrienIt is possible to create DLLs containing mixed ARM and Thumb code. It 16690075Sobrienis also possible to call Thumb code in a DLL from an ARM program and 16790075Sobrienvice versa. It is even possible to call ARM DLLs that have been compiled 16890075Sobrienwithout interworking support (say by an older version of the compiler), 16990075Sobrienfrom Thumb programs and still have things work properly. 17090075Sobrien 17190075Sobrien A version of the `dlltool' program which supports the `--interwork' 17290075Sobriencommand line switch is needed, as well as the following special 17390075Sobrienconsiderations when building programs and DLLs: 17490075Sobrien 17590075Sobrien*Use `-mthumb-interwork'* 17690075Sobrien When compiling files for a DLL or a program the `-mthumb-interwork' 17790075Sobrien command line switch should be specified if calling between ARM and 17890075Sobrien Thumb code can happen. If a program is being compiled and the 17990075Sobrien mode of the DLLs that it uses is not known, then it should be 18090075Sobrien assumed that interworking might occur and the switch used. 18190075Sobrien 18290075Sobrien*Use `-m thumb'* 18390075Sobrien If the exported functions from a DLL are all Thumb encoded then the 18490075Sobrien `-m thumb' command line switch should be given to dlltool when 18590075Sobrien building the stubs. This will make dlltool create Thumb encoded 18690075Sobrien stubs, rather than its default of ARM encoded stubs. 18790075Sobrien 18890075Sobrien If the DLL consists of both exported Thumb functions and exported 18990075Sobrien ARM functions then the `-m thumb' switch should not be used. 19090075Sobrien Instead the Thumb functions in the DLL should be compiled with the 19190075Sobrien `-mcallee-super-interworking' switch, or with the `interfacearm' 19290075Sobrien attribute specified on their prototypes. In this way they will be 19390075Sobrien given ARM encoded prologues, which will work with the ARM encoded 19490075Sobrien stubs produced by dlltool. 19590075Sobrien 19690075Sobrien*Use `-mcaller-super-interworking'* 19790075Sobrien If it is possible for Thumb functions in a DLL to call 19890075Sobrien non-interworking aware code via a function pointer, then the Thumb 19990075Sobrien code must be compiled with the `-mcaller-super-interworking' 20090075Sobrien command line switch. This will force the function pointer calls 20190075Sobrien to use the _interwork_call_via_rX stub functions which will 20290075Sobrien correctly restore Thumb mode upon return from the called function. 20390075Sobrien 20490075Sobrien*Link with `libgcc.a'* 20590075Sobrien When the dll is built it may have to be linked with the GCC 20690075Sobrien library (`libgcc.a') in order to extract the _call_via_rX functions 20790075Sobrien or the _interwork_call_via_rX functions. This represents a partial 20890075Sobrien redundancy since the same functions *may* be present in the 20990075Sobrien application itself, but since they only take up 372 bytes this 21090075Sobrien should not be too much of a consideration. 21190075Sobrien 21290075Sobrien*Use `--support-old-code'* 21390075Sobrien When linking a program with an old DLL which does not support 21490075Sobrien interworking, the `--support-old-code' command line switch to the 21590075Sobrien linker should be used. This causes the linker to generate special 21690075Sobrien interworking stubs which can cope with old, non-interworking aware 21790075Sobrien ARM code, at the cost of generating bulkier code. The linker will 21890075Sobrien still generate a warning message along the lines of: 21990075Sobrien "Warning: input file XXX does not support interworking, whereas YYY does." 22090075Sobrien but this can now be ignored because the --support-old-code switch 22190075Sobrien has been used. 22290075Sobrien 22390075Sobrien 22490075Sobrien 22590075Sobrien5. How interworking support works 22690075Sobrien================================= 22790075Sobrien 22890075SobrienSwitching between the ARM and Thumb instruction sets is accomplished 22990075Sobrienvia the BX instruction which takes as an argument a register name. 23090075SobrienControl is transfered to the address held in this register (with the 23190075Sobrienbottom bit masked out), and if the bottom bit is set, then Thumb 23290075Sobrieninstruction processing is enabled, otherwise ARM instruction 23390075Sobrienprocessing is enabled. 23490075Sobrien 23590075SobrienWhen the -mthumb-interwork command line switch is specified, gcc 23690075Sobrienarranges for all functions to return to their caller by using the BX 23790075Sobrieninstruction. Thus provided that the return address has the bottom bit 238117395Skancorrectly initialized to indicate the instruction set of the caller, 23990075Sobriencorrect operation will ensue. 24090075Sobrien 24190075SobrienWhen a function is called explicitly (rather than via a function 24290075Sobrienpointer), the compiler generates a BL instruction to do this. The 24390075SobrienThumb version of the BL instruction has the special property of 24490075Sobriensetting the bottom bit of the LR register after it has stored the 24590075Sobrienreturn address into it, so that a future BX instruction will correctly 24690075Sobrienreturn the instruction after the BL instruction, in Thumb mode. 24790075Sobrien 24890075SobrienThe BL instruction does not change modes itself however, so if an ARM 24990075Sobrienfunction is calling a Thumb function, or vice versa, it is necessary 25090075Sobriento generate some extra instructions to handle this. This is done in 25190075Sobrienthe linker when it is storing the address of the referenced function 25290075Sobrieninto the BL instruction. If the BL instruction is an ARM style BL 25390075Sobrieninstruction, but the referenced function is a Thumb function, then the 25490075Sobrienlinker automatically generates a calling stub that converts from ARM 25590075Sobrienmode to Thumb mode, puts the address of this stub into the BL 25690075Sobrieninstruction, and puts the address of the referenced function into the 25790075Sobrienstub. Similarly if the BL instruction is a Thumb BL instruction, and 25890075Sobrienthe referenced function is an ARM function, the linker generates a 25990075Sobrienstub which converts from Thumb to ARM mode, puts the address of this 26090075Sobrienstub into the BL instruction, and the address of the referenced 26190075Sobrienfunction into the stub. 26290075Sobrien 26390075SobrienThis is why it is necessary to mark Thumb functions with the 26490075Sobrien.thumb_func pseudo op when creating assembler files. This pseudo op 26590075Sobrienallows the assembler to distinguish between ARM functions and Thumb 26690075Sobrienfunctions. (The Thumb version of GCC automatically generates these 26790075Sobrienpseudo ops for any Thumb functions that it generates). 26890075Sobrien 26990075SobrienCalls via function pointers work differently. Whenever the address of 27090075Sobriena function is taken, the linker examines the type of the function 27190075Sobrienbeing referenced. If the function is a Thumb function, then it sets 27290075Sobrienthe bottom bit of the address. Technically this makes the address 27390075Sobrienincorrect, since it is now one byte into the start of the function, 27490075Sobrienbut this is never a problem because: 27590075Sobrien 27690075Sobrien a. with interworking enabled all calls via function pointer 27790075Sobrien are done using the BX instruction and this ignores the 27890075Sobrien bottom bit when computing where to go to. 27990075Sobrien 28090075Sobrien b. the linker will always set the bottom bit when the address 28190075Sobrien of the function is taken, so it is never possible to take 28290075Sobrien the address of the function in two different places and 28390075Sobrien then compare them and find that they are not equal. 28490075Sobrien 28590075SobrienAs already mentioned any call via a function pointer will use the BX 28690075Sobrieninstruction (provided that interworking is enabled). The only problem 28790075Sobrienwith this is computing the return address for the return from the 28890075Sobriencalled function. For ARM code this can easily be done by the code 28990075Sobriensequence: 29090075Sobrien 29190075Sobrien mov lr, pc 29290075Sobrien bx rX 29390075Sobrien 29490075Sobrien(where rX is the name of the register containing the function 29590075Sobrienpointer). This code does not work for the Thumb instruction set, 29690075Sobriensince the MOV instruction will not set the bottom bit of the LR 29790075Sobrienregister, so that when the called function returns, it will return in 29890075SobrienARM mode not Thumb mode. Instead the compiler generates this 29990075Sobriensequence: 30090075Sobrien 30190075Sobrien bl _call_via_rX 30290075Sobrien 30390075Sobrien(again where rX is the name if the register containing the function 30490075Sobrienpointer). The special call_via_rX functions look like this: 30590075Sobrien 30690075Sobrien .thumb_func 30790075Sobrien_call_via_r0: 30890075Sobrien bx r0 30990075Sobrien nop 31090075Sobrien 31190075SobrienThe BL instruction ensures that the correct return address is stored 31290075Sobrienin the LR register and then the BX instruction jumps to the address 31390075Sobrienstored in the function pointer, switch modes if necessary. 31490075Sobrien 31590075Sobrien 31690075Sobrien6. How caller-super-interworking support works 31790075Sobrien============================================== 31890075Sobrien 31990075SobrienWhen the -mcaller-super-interworking command line switch is specified 32090075Sobrienit changes the code produced by the Thumb compiler so that all calls 32190075Sobrienvia function pointers (including virtual function calls) now go via a 32290075Sobriendifferent stub function. The code to call via a function pointer now 32390075Sobrienlooks like this: 32490075Sobrien 32590075Sobrien bl _interwork_call_via_r0 32690075Sobrien 32790075SobrienNote: The compiler does not insist that r0 be used to hold the 32890075Sobrienfunction address. Any register will do, and there are a suite of stub 32990075Sobrienfunctions, one for each possible register. The stub functions look 33090075Sobrienlike this: 33190075Sobrien 33290075Sobrien .code 16 33390075Sobrien .thumb_func 33490075Sobrien_interwork_call_via_r0 33590075Sobrien bx pc 33690075Sobrien nop 33790075Sobrien 33890075Sobrien .code 32 33990075Sobrien tst r0, #1 34090075Sobrien stmeqdb r13!, {lr} 34190075Sobrien adreq lr, _arm_return 34290075Sobrien bx r0 34390075Sobrien 34490075SobrienThe stub first switches to ARM mode, since it is a lot easier to 34590075Sobrienperform the necessary operations using ARM instructions. It then 34690075Sobrientests the bottom bit of the register containing the address of the 34790075Sobrienfunction to be called. If this bottom bit is set then the function 34890075Sobrienbeing called uses Thumb instructions and the BX instruction to come 34990075Sobrienwill switch back into Thumb mode before calling this function. (Note 35090075Sobrienthat it does not matter how this called function chooses to return to 35190075Sobrienits caller, since the both the caller and callee are Thumb functions, 35290075Sobrienand mode switching is necessary). If the function being called is an 35390075SobrienARM mode function however, the stub pushes the return address (with 35490075Sobrienits bottom bit set) onto the stack, replaces the return address with 35590075Sobrienthe address of the a piece of code called '_arm_return' and then 35690075Sobrienperforms a BX instruction to call the function. 35790075Sobrien 35890075SobrienThe '_arm_return' code looks like this: 35990075Sobrien 36090075Sobrien .code 32 36190075Sobrien_arm_return: 36290075Sobrien ldmia r13!, {r12} 36390075Sobrien bx r12 36490075Sobrien .code 16 36590075Sobrien 36690075Sobrien 36790075SobrienIt simply retrieves the return address from the stack, and then 36890075Sobrienperforms a BX operation to return to the caller and switch back into 36990075SobrienThumb mode. 37090075Sobrien 37190075Sobrien 37290075Sobrien7. How callee-super-interworking support works 37390075Sobrien============================================== 37490075Sobrien 37590075SobrienWhen -mcallee-super-interworking is specified on the command line the 37690075SobrienThumb compiler behaves as if every externally visible function that it 37790075Sobriencompiles has had the (interfacearm) attribute specified for it. What 37890075Sobrienthis attribute does is to put a special, ARM mode header onto the 37990075Sobrienfunction which forces a switch into Thumb mode: 38090075Sobrien 38190075Sobrien without __attribute__((interfacearm)): 38290075Sobrien 38390075Sobrien .code 16 38490075Sobrien .thumb_func 38590075Sobrien function: 38690075Sobrien ... start of function ... 38790075Sobrien 38890075Sobrien with __attribute__((interfacearm)): 38990075Sobrien 39090075Sobrien .code 32 39190075Sobrien function: 39290075Sobrien orr r12, pc, #1 39390075Sobrien bx r12 39490075Sobrien 39590075Sobrien .code 16 39690075Sobrien .thumb_func 39790075Sobrien .real_start_of_function: 39890075Sobrien 39990075Sobrien ... start of function ... 40090075Sobrien 40190075SobrienNote that since the function now expects to be entered in ARM mode, it 40290075Sobrienno longer has the .thumb_func pseudo op specified for its name. 40390075SobrienInstead the pseudo op is attached to a new label .real_start_of_<name> 40490075Sobrien(where <name> is the name of the function) which indicates the start 40590075Sobrienof the Thumb code. This does have the interesting side effect in that 40690075Sobrienif this function is now called from a Thumb mode piece of code 407132718Skanoutside of the current file, the linker will generate a calling stub 40890075Sobriento switch from Thumb mode into ARM mode, and then this is immediately 40990075Sobrienoverridden by the function's header which switches back into Thumb 41090075Sobrienmode. 41190075Sobrien 41290075SobrienIn addition the (interfacearm) attribute also forces the function to 41390075Sobrienreturn by using the BX instruction, even if has not been compiled with 41490075Sobrienthe -mthumb-interwork command line flag, so that the correct mode will 41590075Sobrienbe restored upon exit from the function. 41690075Sobrien 41790075Sobrien 41890075Sobrien8. Some examples 41990075Sobrien================ 42090075Sobrien 42190075Sobrien Given these two test files: 42290075Sobrien 42390075Sobrien int arm (void) { return 1 + thumb (); } 42490075Sobrien 42590075Sobrien int thumb (void) { return 2 + arm (); } 42690075Sobrien 42790075Sobrien The following pieces of assembler are produced by the ARM and Thumb 42890075Sobrienversion of GCC depending upon the command line options used: 42990075Sobrien 43090075Sobrien `-O2': 43190075Sobrien .code 32 .code 16 43290075Sobrien .global _arm .global _thumb 43390075Sobrien .thumb_func 43490075Sobrien _arm: _thumb: 43590075Sobrien mov ip, sp 43690075Sobrien stmfd sp!, {fp, ip, lr, pc} push {lr} 43790075Sobrien sub fp, ip, #4 43890075Sobrien bl _thumb bl _arm 43990075Sobrien add r0, r0, #1 add r0, r0, #2 44090075Sobrien ldmea fp, {fp, sp, pc} pop {pc} 44190075Sobrien 44290075Sobrien Note how the functions return without using the BX instruction. If 44390075Sobrienthese files were assembled and linked together they would fail to work 44490075Sobrienbecause they do not change mode when returning to their caller. 44590075Sobrien 44690075Sobrien `-O2 -mthumb-interwork': 44790075Sobrien 44890075Sobrien .code 32 .code 16 44990075Sobrien .global _arm .global _thumb 45090075Sobrien .thumb_func 45190075Sobrien _arm: _thumb: 45290075Sobrien mov ip, sp 45390075Sobrien stmfd sp!, {fp, ip, lr, pc} push {lr} 45490075Sobrien sub fp, ip, #4 45590075Sobrien bl _thumb bl _arm 45690075Sobrien add r0, r0, #1 add r0, r0, #2 45790075Sobrien ldmea fp, {fp, sp, lr} pop {r1} 45890075Sobrien bx lr bx r1 45990075Sobrien 46090075Sobrien Now the functions use BX to return their caller. They have grown by 46190075Sobrien4 and 2 bytes respectively, but they can now successfully be linked 46290075Sobrientogether and be expect to work. The linker will replace the 46390075Sobriendestinations of the two BL instructions with the addresses of calling 46490075Sobrienstubs which convert to the correct mode before jumping to the called 46590075Sobrienfunction. 46690075Sobrien 46790075Sobrien `-O2 -mcallee-super-interworking': 46890075Sobrien 46990075Sobrien .code 32 .code 32 47090075Sobrien .global _arm .global _thumb 47190075Sobrien _arm: _thumb: 47290075Sobrien orr r12, pc, #1 47390075Sobrien bx r12 47490075Sobrien mov ip, sp .code 16 47590075Sobrien stmfd sp!, {fp, ip, lr, pc} push {lr} 47690075Sobrien sub fp, ip, #4 47790075Sobrien bl _thumb bl _arm 47890075Sobrien add r0, r0, #1 add r0, r0, #2 47990075Sobrien ldmea fp, {fp, sp, lr} pop {r1} 48090075Sobrien bx lr bx r1 48190075Sobrien 48290075Sobrien The thumb function now has an ARM encoded prologue, and it no longer 48390075Sobrienhas the `.thumb-func' pseudo op attached to it. The linker will not 48490075Sobriengenerate a calling stub for the call from arm() to thumb(), but it will 48590075Sobrienstill have to generate a stub for the call from thumb() to arm(). Also 48690075Sobriennote how specifying `--mcallee-super-interworking' automatically 48790075Sobrienimplies `-mthumb-interworking'. 48890075Sobrien 48990075Sobrien 49090075Sobrien9. Some Function Pointer Examples 49190075Sobrien================================= 49290075Sobrien 49390075Sobrien Given this test file: 49490075Sobrien 49590075Sobrien int func (void) { return 1; } 49690075Sobrien 49790075Sobrien int call (int (* ptr)(void)) { return ptr (); } 49890075Sobrien 49990075Sobrien The following varying pieces of assembler are produced by the Thumb 50090075Sobrienversion of GCC depending upon the command line options used: 50190075Sobrien 50290075Sobrien `-O2': 50390075Sobrien .code 16 50490075Sobrien .globl _func 50590075Sobrien .thumb_func 50690075Sobrien _func: 50790075Sobrien mov r0, #1 50890075Sobrien bx lr 50990075Sobrien 51090075Sobrien .globl _call 51190075Sobrien .thumb_func 51290075Sobrien _call: 51390075Sobrien push {lr} 51490075Sobrien bl __call_via_r0 51590075Sobrien pop {pc} 51690075Sobrien 51790075Sobrien Note how the two functions have different exit sequences. In 51890075Sobrienparticular call() uses pop {pc} to return, which would not work if the 51990075Sobriencaller was in ARM mode. func() however, uses the BX instruction, even 52090075Sobrienthough `-mthumb-interwork' has not been specified, as this is the most 52190075Sobrienefficient way to exit a function when the return address is held in the 52290075Sobrienlink register. 52390075Sobrien 52490075Sobrien `-O2 -mthumb-interwork': 52590075Sobrien 52690075Sobrien .code 16 52790075Sobrien .globl _func 52890075Sobrien .thumb_func 52990075Sobrien _func: 53090075Sobrien mov r0, #1 53190075Sobrien bx lr 53290075Sobrien 53390075Sobrien .globl _call 53490075Sobrien .thumb_func 53590075Sobrien _call: 53690075Sobrien push {lr} 53790075Sobrien bl __call_via_r0 53890075Sobrien pop {r1} 53990075Sobrien bx r1 54090075Sobrien 54190075Sobrien This time both functions return by using the BX instruction. This 54290075Sobrienmeans that call() is now two bytes longer and several cycles slower 54390075Sobrienthan the previous version. 54490075Sobrien 54590075Sobrien `-O2 -mcaller-super-interworking': 54690075Sobrien .code 16 54790075Sobrien .globl _func 54890075Sobrien .thumb_func 54990075Sobrien _func: 55090075Sobrien mov r0, #1 55190075Sobrien bx lr 55290075Sobrien 55390075Sobrien .globl _call 55490075Sobrien .thumb_func 55590075Sobrien _call: 55690075Sobrien push {lr} 55790075Sobrien bl __interwork_call_via_r0 55890075Sobrien pop {pc} 55990075Sobrien 56090075Sobrien Very similar to the first (non-interworking) version, except that a 56190075Sobriendifferent stub is used to call via the function pointer. This new stub 56290075Sobrienwill work even if the called function is not interworking aware, and 56390075Sobrientries to return to call() in ARM mode. Note that the assembly code for 56490075Sobriencall() is still not interworking aware itself, and so should not be 56590075Sobriencalled from ARM code. 56690075Sobrien 56790075Sobrien `-O2 -mcallee-super-interworking': 56890075Sobrien 56990075Sobrien .code 32 57090075Sobrien .globl _func 57190075Sobrien _func: 57290075Sobrien orr r12, pc, #1 57390075Sobrien bx r12 57490075Sobrien 57590075Sobrien .code 16 57690075Sobrien .globl .real_start_of_func 57790075Sobrien .thumb_func 57890075Sobrien .real_start_of_func: 57990075Sobrien mov r0, #1 58090075Sobrien bx lr 58190075Sobrien 58290075Sobrien .code 32 58390075Sobrien .globl _call 58490075Sobrien _call: 58590075Sobrien orr r12, pc, #1 58690075Sobrien bx r12 58790075Sobrien 58890075Sobrien .code 16 58990075Sobrien .globl .real_start_of_call 59090075Sobrien .thumb_func 59190075Sobrien .real_start_of_call: 59290075Sobrien push {lr} 59390075Sobrien bl __call_via_r0 59490075Sobrien pop {r1} 59590075Sobrien bx r1 59690075Sobrien 59790075Sobrien Now both functions have an ARM coded prologue, and both functions 59890075Sobrienreturn by using the BX instruction. These functions are interworking 59990075Sobrienaware therefore and can safely be called from ARM code. The code for 60090075Sobrienthe call() function is now 10 bytes longer than the original, non 60190075Sobrieninterworking aware version, an increase of over 200%. 60290075Sobrien 60390075Sobrien If a prototype for call() is added to the source code, and this 60490075Sobrienprototype includes the `interfacearm' attribute: 60590075Sobrien 60690075Sobrien int __attribute__((interfacearm)) call (int (* ptr)(void)); 60790075Sobrien 60890075Sobrien then this code is produced (with only -O2 specified on the command 60990075Sobrienline): 61090075Sobrien 61190075Sobrien .code 16 61290075Sobrien .globl _func 61390075Sobrien .thumb_func 61490075Sobrien _func: 61590075Sobrien mov r0, #1 61690075Sobrien bx lr 61790075Sobrien 61890075Sobrien .globl _call 61990075Sobrien .code 32 62090075Sobrien _call: 62190075Sobrien orr r12, pc, #1 62290075Sobrien bx r12 62390075Sobrien 62490075Sobrien .code 16 62590075Sobrien .globl .real_start_of_call 62690075Sobrien .thumb_func 62790075Sobrien .real_start_of_call: 62890075Sobrien push {lr} 62990075Sobrien bl __call_via_r0 63090075Sobrien pop {r1} 63190075Sobrien bx r1 63290075Sobrien 63390075Sobrien So now both call() and func() can be safely called via 63490075Sobriennon-interworking aware ARM code. If, when such a file is assembled, 63590075Sobrienthe assembler detects the fact that call() is being called by another 63690075Sobrienfunction in the same file, it will automatically adjust the target of 63790075Sobrienthe BL instruction to point to .real_start_of_call. In this way there 63890075Sobrienis no need for the linker to generate a Thumb-to-ARM calling stub so 63990075Sobrienthat call can be entered in ARM mode. 64090075Sobrien 64190075Sobrien 64290075Sobrien10. How to use dlltool to build ARM/Thumb DLLs 64390075Sobrien============================================== 64490075Sobrien Given a program (`prog.c') like this: 64590075Sobrien 64690075Sobrien extern int func_in_dll (void); 64790075Sobrien 64890075Sobrien int main (void) { return func_in_dll(); } 64990075Sobrien 65090075Sobrien And a DLL source file (`dll.c') like this: 65190075Sobrien 65290075Sobrien int func_in_dll (void) { return 1; } 65390075Sobrien 65490075Sobrien Here is how to build the DLL and the program for a purely ARM based 65590075Sobrienenvironment: 65690075Sobrien 65790075Sobrien*Step One 65890075Sobrien Build a `.def' file describing the DLL: 65990075Sobrien 66090075Sobrien ; example.def 66190075Sobrien ; This file describes the contents of the DLL 66290075Sobrien LIBRARY example 66390075Sobrien HEAPSIZE 0x40000, 0x2000 66490075Sobrien EXPORTS 66590075Sobrien func_in_dll 1 66690075Sobrien 66790075Sobrien*Step Two 66890075Sobrien Compile the DLL source code: 66990075Sobrien 67090075Sobrien arm-pe-gcc -O2 -c dll.c 67190075Sobrien 67290075Sobrien*Step Three 67390075Sobrien Use `dlltool' to create an exports file and a library file: 67490075Sobrien 67590075Sobrien dlltool --def example.def --output-exp example.o --output-lib example.a 67690075Sobrien 67790075Sobrien*Step Four 67890075Sobrien Link together the complete DLL: 67990075Sobrien 68090075Sobrien arm-pe-ld dll.o example.o -o example.dll 68190075Sobrien 68290075Sobrien*Step Five 68390075Sobrien Compile the program's source code: 68490075Sobrien 68590075Sobrien arm-pe-gcc -O2 -c prog.c 68690075Sobrien 68790075Sobrien*Step Six 68890075Sobrien Link together the program and the DLL's library file: 68990075Sobrien 69090075Sobrien arm-pe-gcc prog.o example.a -o prog 69190075Sobrien 69290075Sobrien If instead this was a Thumb DLL being called from an ARM program, the 69390075Sobriensteps would look like this. (To save space only those steps that are 69490075Sobriendifferent from the previous version are shown): 69590075Sobrien 69690075Sobrien*Step Two 69790075Sobrien Compile the DLL source code (using the Thumb compiler): 69890075Sobrien 69990075Sobrien thumb-pe-gcc -O2 -c dll.c -mthumb-interwork 70090075Sobrien 70190075Sobrien*Step Three 70290075Sobrien Build the exports and library files (and support interworking): 70390075Sobrien 70490075Sobrien dlltool -d example.def -z example.o -l example.a --interwork -m thumb 70590075Sobrien 70690075Sobrien*Step Five 70790075Sobrien Compile the program's source code (and support interworking): 70890075Sobrien 70990075Sobrien arm-pe-gcc -O2 -c prog.c -mthumb-interwork 71090075Sobrien 71190075Sobrien If instead, the DLL was an old, ARM DLL which does not support 71290075Sobrieninterworking, and which cannot be rebuilt, then these steps would be 71390075Sobrienused. 71490075Sobrien 71590075Sobrien*Step One 71690075Sobrien Skip. If you do not have access to the sources of a DLL, there is 71790075Sobrien no point in building a `.def' file for it. 71890075Sobrien 71990075Sobrien*Step Two 72090075Sobrien Skip. With no DLL sources there is nothing to compile. 72190075Sobrien 72290075Sobrien*Step Three 72390075Sobrien Skip. Without a `.def' file you cannot use dlltool to build an 72490075Sobrien exports file or a library file. 72590075Sobrien 72690075Sobrien*Step Four 72790075Sobrien Skip. Without a set of DLL object files you cannot build the DLL. 72890075Sobrien Besides it has already been built for you by somebody else. 72990075Sobrien 73090075Sobrien*Step Five 73190075Sobrien Compile the program's source code, this is the same as before: 73290075Sobrien 73390075Sobrien arm-pe-gcc -O2 -c prog.c 73490075Sobrien 73590075Sobrien*Step Six 73690075Sobrien Link together the program and the DLL's library file, passing the 73790075Sobrien `--support-old-code' option to the linker: 73890075Sobrien 73990075Sobrien arm-pe-gcc prog.o example.a -Wl,--support-old-code -o prog 74090075Sobrien 74190075Sobrien Ignore the warning message about the input file not supporting 74290075Sobrien interworking as the --support-old-code switch has taken care if this. 743