1 1.1 mrg Arm / Thumb Interworking 2 1.1 mrg ======================== 3 1.1 mrg 4 1.1 mrg The Cygnus GNU Pro Toolkit for the ARM7T processor supports function 5 1.1 mrg calls between code compiled for the ARM instruction set and code 6 1.1 mrg compiled for the Thumb instruction set and vice versa. This document 7 1.1 mrg describes how that interworking support operates and explains the 8 1.1 mrg command line switches that should be used in order to produce working 9 1.1 mrg programs. 10 1.1 mrg 11 1.1 mrg Note: The Cygnus GNU Pro Toolkit does not support switching between 12 1.1 mrg compiling for the ARM instruction set and the Thumb instruction set 13 1.1 mrg on anything other than a per file basis. There are in fact two 14 1.1 mrg completely separate compilers, one that produces ARM assembler 15 1.1 mrg instructions and one that produces Thumb assembler instructions. The 16 1.1 mrg two compilers share the same assembler, linker and so on. 17 1.1 mrg 18 1.1 mrg 19 1.1 mrg 1. Explicit interworking support for C and C++ files 20 1.1 mrg ==================================================== 21 1.1 mrg 22 1.1 mrg By default if a file is compiled without any special command line 23 1.1 mrg switches then the code produced will not support interworking. 24 1.1 mrg Provided that a program is made up entirely from object files and 25 1.1 mrg libraries produced in this way and which contain either exclusively 26 1.1 mrg ARM instructions or exclusively Thumb instructions then this will not 27 1.1 mrg matter and a working executable will be created. If an attempt is 28 1.1 mrg made to link together mixed ARM and Thumb object files and libraries, 29 1.1 mrg then warning messages will be produced by the linker and a non-working 30 1.1 mrg executable will be created. 31 1.1 mrg 32 1.1 mrg In order to produce code which does support interworking it should be 33 1.1 mrg compiled with the 34 1.1 mrg 35 1.1 mrg -mthumb-interwork 36 1.1 mrg 37 1.1 mrg command line option. Provided that a program is made up entirely from 38 1.1 mrg object files and libraries built with this command line switch a 39 1.1 mrg working executable will be produced, even if both ARM and Thumb 40 1.1 mrg instructions are used by the various components of the program. (No 41 1.1 mrg warning messages will be produced by the linker either). 42 1.1 mrg 43 1.1 mrg Note that specifying -mthumb-interwork does result in slightly larger, 44 1.1 mrg slower code being produced. This is why interworking support must be 45 1.1 mrg specifically enabled by a switch. 46 1.1 mrg 47 1.1 mrg 48 1.1 mrg 2. Explicit interworking support for assembler files 49 1.1 mrg ==================================================== 50 1.1 mrg 51 1.1 mrg If assembler files are to be included into an interworking program 52 1.1 mrg then the following rules must be obeyed: 53 1.1 mrg 54 1.1 mrg * Any externally visible functions must return by using the BX 55 1.1 mrg instruction. 56 1.1 mrg 57 1.1 mrg * Normal function calls can just use the BL instruction. The 58 1.1 mrg linker will automatically insert code to switch between ARM 59 1.1 mrg and Thumb modes as necessary. 60 1.1 mrg 61 1.1 mrg * Calls via function pointers should use the BX instruction if 62 1.1 mrg the call is made in ARM mode: 63 1.1 mrg 64 1.1 mrg .code 32 65 1.1 mrg mov lr, pc 66 1.1 mrg bx rX 67 1.1 mrg 68 1.1 mrg This code sequence will not work in Thumb mode however, since 69 1.1 mrg the mov instruction will not set the bottom bit of the lr 70 1.1 mrg register. Instead a branch-and-link to the _call_via_rX 71 1.1 mrg functions should be used instead: 72 1.1 mrg 73 1.1 mrg .code 16 74 1.1 mrg bl _call_via_rX 75 1.1 mrg 76 1.1 mrg where rX is replaced by the name of the register containing 77 1.1 mrg the function address. 78 1.1 mrg 79 1.1 mrg * All externally visible functions which should be entered in 80 1.1 mrg Thumb mode must have the .thumb_func pseudo op specified just 81 1.1 mrg before their entry point. e.g.: 82 1.1 mrg 83 1.1 mrg .code 16 84 1.1 mrg .global function 85 1.1 mrg .thumb_func 86 1.1 mrg function: 87 1.1 mrg ...start of function.... 88 1.1 mrg 89 1.1 mrg * All assembler files must be assembled with the switch 90 1.1 mrg -mthumb-interwork specified on the command line. (If the file 91 1.1 mrg is assembled by calling gcc it will automatically pass on the 92 1.1 mrg -mthumb-interwork switch to the assembler, provided that it 93 1.1 mrg was specified on the gcc command line in the first place.) 94 1.1 mrg 95 1.1 mrg 96 1.1 mrg 3. Support for old, non-interworking aware code. 97 1.1 mrg ================================================ 98 1.1 mrg 99 1.1 mrg If it is necessary to link together code produced by an older, 100 1.1 mrg non-interworking aware compiler, or code produced by the new compiler 101 1.1 mrg but without the -mthumb-interwork command line switch specified, then 102 1.1 mrg there are two command line switches that can be used to support this. 103 1.1 mrg 104 1.1 mrg The switch 105 1.1 mrg 106 1.1 mrg -mcaller-super-interworking 107 1.1 mrg 108 1.1 mrg will allow calls via function pointers in Thumb mode to work, 109 1.1 mrg regardless of whether the function pointer points to old, 110 1.1 mrg non-interworking aware code or not. Specifying this switch does 111 1.1 mrg produce slightly slower code however. 112 1.1 mrg 113 1.1 mrg Note: There is no switch to allow calls via function pointers in ARM 114 1.1 mrg mode to be handled specially. Calls via function pointers from 115 1.1 mrg interworking aware ARM code to non-interworking aware ARM code work 116 1.1 mrg without any special considerations by the compiler. Calls via 117 1.1 mrg function pointers from interworking aware ARM code to non-interworking 118 1.1 mrg aware Thumb code however will not work. (Actually under some 119 1.1 mrg circumstances they may work, but there are no guarantees). This is 120 1.1 mrg because only the new compiler is able to produce Thumb code, and this 121 1.1 mrg compiler already has a command line switch to produce interworking 122 1.1 mrg aware code. 123 1.1 mrg 124 1.1 mrg 125 1.1 mrg The switch 126 1.1 mrg 127 1.1 mrg -mcallee-super-interworking 128 1.1 mrg 129 1.1 mrg will allow non-interworking aware ARM or Thumb code to call Thumb 130 1.1 mrg functions, either directly or via function pointers. Specifying this 131 1.1 mrg switch does produce slightly larger, slower code however. 132 1.1 mrg 133 1.1 mrg Note: There is no switch to allow non-interworking aware ARM or Thumb 134 1.1 mrg code to call ARM functions. There is no need for any special handling 135 1.1 mrg of calls from non-interworking aware ARM code to interworking aware 136 1.1 mrg ARM functions, they just work normally. Calls from non-interworking 137 1.1 mrg aware Thumb functions to ARM code however, will not work. There is no 138 1.1 mrg option to support this, since it is always possible to recompile the 139 1.1 mrg Thumb code to be interworking aware. 140 1.1 mrg 141 1.1 mrg As an alternative to the command line switch 142 1.1 mrg -mcallee-super-interworking, which affects all externally visible 143 1.1 mrg functions in a file, it is possible to specify an attribute or 144 1.1 mrg declspec for individual functions, indicating that that particular 145 1.1 mrg function should support being called by non-interworking aware code. 146 1.1 mrg The function should be defined like this: 147 1.1 mrg 148 1.1 mrg int __attribute__((interfacearm)) function 149 1.1 mrg { 150 1.1 mrg ... body of function ... 151 1.1 mrg } 152 1.1 mrg 153 1.1 mrg or 154 1.1 mrg 155 1.1 mrg int __declspec(interfacearm) function 156 1.1 mrg { 157 1.1 mrg ... body of function ... 158 1.1 mrg } 159 1.1 mrg 160 1.1 mrg 161 1.1 mrg 162 1.1 mrg 4. Interworking support in dlltool 163 1.1 mrg ================================== 164 1.1 mrg 165 1.1 mrg It is possible to create DLLs containing mixed ARM and Thumb code. It 166 1.1 mrg is also possible to call Thumb code in a DLL from an ARM program and 167 1.1 mrg vice versa. It is even possible to call ARM DLLs that have been compiled 168 1.1 mrg without interworking support (say by an older version of the compiler), 169 1.1 mrg from Thumb programs and still have things work properly. 170 1.1 mrg 171 1.1 mrg A version of the `dlltool' program which supports the `--interwork' 172 1.1 mrg command line switch is needed, as well as the following special 173 1.1 mrg considerations when building programs and DLLs: 174 1.1 mrg 175 1.1 mrg *Use `-mthumb-interwork'* 176 1.1 mrg When compiling files for a DLL or a program the `-mthumb-interwork' 177 1.1 mrg command line switch should be specified if calling between ARM and 178 1.1 mrg Thumb code can happen. If a program is being compiled and the 179 1.1 mrg mode of the DLLs that it uses is not known, then it should be 180 1.1 mrg assumed that interworking might occur and the switch used. 181 1.1 mrg 182 1.1 mrg *Use `-m thumb'* 183 1.1 mrg If the exported functions from a DLL are all Thumb encoded then the 184 1.1 mrg `-m thumb' command line switch should be given to dlltool when 185 1.1 mrg building the stubs. This will make dlltool create Thumb encoded 186 1.1 mrg stubs, rather than its default of ARM encoded stubs. 187 1.1 mrg 188 1.1 mrg If the DLL consists of both exported Thumb functions and exported 189 1.1 mrg ARM functions then the `-m thumb' switch should not be used. 190 1.1 mrg Instead the Thumb functions in the DLL should be compiled with the 191 1.1 mrg `-mcallee-super-interworking' switch, or with the `interfacearm' 192 1.1 mrg attribute specified on their prototypes. In this way they will be 193 1.1 mrg given ARM encoded prologues, which will work with the ARM encoded 194 1.1 mrg stubs produced by dlltool. 195 1.1 mrg 196 1.1 mrg *Use `-mcaller-super-interworking'* 197 1.1 mrg If it is possible for Thumb functions in a DLL to call 198 1.1 mrg non-interworking aware code via a function pointer, then the Thumb 199 1.1 mrg code must be compiled with the `-mcaller-super-interworking' 200 1.1 mrg command line switch. This will force the function pointer calls 201 1.1 mrg to use the _interwork_call_via_rX stub functions which will 202 1.1 mrg correctly restore Thumb mode upon return from the called function. 203 1.1 mrg 204 1.1 mrg *Link with `libgcc.a'* 205 1.1 mrg When the dll is built it may have to be linked with the GCC 206 1.1 mrg library (`libgcc.a') in order to extract the _call_via_rX functions 207 1.1 mrg or the _interwork_call_via_rX functions. This represents a partial 208 1.1 mrg redundancy since the same functions *may* be present in the 209 1.1 mrg application itself, but since they only take up 372 bytes this 210 1.1 mrg should not be too much of a consideration. 211 1.1 mrg 212 1.1 mrg *Use `--support-old-code'* 213 1.1 mrg When linking a program with an old DLL which does not support 214 1.1 mrg interworking, the `--support-old-code' command line switch to the 215 1.1 mrg linker should be used. This causes the linker to generate special 216 1.1 mrg interworking stubs which can cope with old, non-interworking aware 217 1.1 mrg ARM code, at the cost of generating bulkier code. The linker will 218 1.1 mrg still generate a warning message along the lines of: 219 1.1 mrg "Warning: input file XXX does not support interworking, whereas YYY does." 220 1.1 mrg but this can now be ignored because the --support-old-code switch 221 1.1 mrg has been used. 222 1.1 mrg 223 1.1 mrg 224 1.1 mrg 225 1.1 mrg 5. How interworking support works 226 1.1 mrg ================================= 227 1.1 mrg 228 1.1 mrg Switching between the ARM and Thumb instruction sets is accomplished 229 1.1 mrg via the BX instruction which takes as an argument a register name. 230 1.3 mrg Control is transferred to the address held in this register (with the 231 1.1 mrg bottom bit masked out), and if the bottom bit is set, then Thumb 232 1.1 mrg instruction processing is enabled, otherwise ARM instruction 233 1.1 mrg processing is enabled. 234 1.1 mrg 235 1.1 mrg When the -mthumb-interwork command line switch is specified, gcc 236 1.1 mrg arranges for all functions to return to their caller by using the BX 237 1.1 mrg instruction. Thus provided that the return address has the bottom bit 238 1.1 mrg correctly initialized to indicate the instruction set of the caller, 239 1.1 mrg correct operation will ensue. 240 1.1 mrg 241 1.1 mrg When a function is called explicitly (rather than via a function 242 1.1 mrg pointer), the compiler generates a BL instruction to do this. The 243 1.1 mrg Thumb version of the BL instruction has the special property of 244 1.1 mrg setting the bottom bit of the LR register after it has stored the 245 1.1 mrg return address into it, so that a future BX instruction will correctly 246 1.1 mrg return the instruction after the BL instruction, in Thumb mode. 247 1.1 mrg 248 1.1 mrg The BL instruction does not change modes itself however, so if an ARM 249 1.1 mrg function is calling a Thumb function, or vice versa, it is necessary 250 1.1 mrg to generate some extra instructions to handle this. This is done in 251 1.1 mrg the linker when it is storing the address of the referenced function 252 1.1 mrg into the BL instruction. If the BL instruction is an ARM style BL 253 1.1 mrg instruction, but the referenced function is a Thumb function, then the 254 1.1 mrg linker automatically generates a calling stub that converts from ARM 255 1.1 mrg mode to Thumb mode, puts the address of this stub into the BL 256 1.1 mrg instruction, and puts the address of the referenced function into the 257 1.1 mrg stub. Similarly if the BL instruction is a Thumb BL instruction, and 258 1.1 mrg the referenced function is an ARM function, the linker generates a 259 1.1 mrg stub which converts from Thumb to ARM mode, puts the address of this 260 1.1 mrg stub into the BL instruction, and the address of the referenced 261 1.1 mrg function into the stub. 262 1.1 mrg 263 1.1 mrg This is why it is necessary to mark Thumb functions with the 264 1.1 mrg .thumb_func pseudo op when creating assembler files. This pseudo op 265 1.1 mrg allows the assembler to distinguish between ARM functions and Thumb 266 1.1 mrg functions. (The Thumb version of GCC automatically generates these 267 1.1 mrg pseudo ops for any Thumb functions that it generates). 268 1.1 mrg 269 1.1 mrg Calls via function pointers work differently. Whenever the address of 270 1.1 mrg a function is taken, the linker examines the type of the function 271 1.1 mrg being referenced. If the function is a Thumb function, then it sets 272 1.1 mrg the bottom bit of the address. Technically this makes the address 273 1.1 mrg incorrect, since it is now one byte into the start of the function, 274 1.1 mrg but this is never a problem because: 275 1.1 mrg 276 1.1 mrg a. with interworking enabled all calls via function pointer 277 1.1 mrg are done using the BX instruction and this ignores the 278 1.1 mrg bottom bit when computing where to go to. 279 1.1 mrg 280 1.1 mrg b. the linker will always set the bottom bit when the address 281 1.1 mrg of the function is taken, so it is never possible to take 282 1.1 mrg the address of the function in two different places and 283 1.1 mrg then compare them and find that they are not equal. 284 1.1 mrg 285 1.1 mrg As already mentioned any call via a function pointer will use the BX 286 1.1 mrg instruction (provided that interworking is enabled). The only problem 287 1.1 mrg with this is computing the return address for the return from the 288 1.1 mrg called function. For ARM code this can easily be done by the code 289 1.1 mrg sequence: 290 1.1 mrg 291 1.1 mrg mov lr, pc 292 1.1 mrg bx rX 293 1.1 mrg 294 1.1 mrg (where rX is the name of the register containing the function 295 1.1 mrg pointer). This code does not work for the Thumb instruction set, 296 1.1 mrg since the MOV instruction will not set the bottom bit of the LR 297 1.1 mrg register, so that when the called function returns, it will return in 298 1.1 mrg ARM mode not Thumb mode. Instead the compiler generates this 299 1.1 mrg sequence: 300 1.1 mrg 301 1.1 mrg bl _call_via_rX 302 1.1 mrg 303 1.1 mrg (again where rX is the name if the register containing the function 304 1.1 mrg pointer). The special call_via_rX functions look like this: 305 1.1 mrg 306 1.1 mrg .thumb_func 307 1.1 mrg _call_via_r0: 308 1.1 mrg bx r0 309 1.1 mrg nop 310 1.1 mrg 311 1.1 mrg The BL instruction ensures that the correct return address is stored 312 1.1 mrg in the LR register and then the BX instruction jumps to the address 313 1.1 mrg stored in the function pointer, switch modes if necessary. 314 1.1 mrg 315 1.1 mrg 316 1.1 mrg 6. How caller-super-interworking support works 317 1.1 mrg ============================================== 318 1.1 mrg 319 1.1 mrg When the -mcaller-super-interworking command line switch is specified 320 1.1 mrg it changes the code produced by the Thumb compiler so that all calls 321 1.1 mrg via function pointers (including virtual function calls) now go via a 322 1.1 mrg different stub function. The code to call via a function pointer now 323 1.1 mrg looks like this: 324 1.1 mrg 325 1.1 mrg bl _interwork_call_via_r0 326 1.1 mrg 327 1.1 mrg Note: The compiler does not insist that r0 be used to hold the 328 1.1 mrg function address. Any register will do, and there are a suite of stub 329 1.1 mrg functions, one for each possible register. The stub functions look 330 1.1 mrg like this: 331 1.1 mrg 332 1.1 mrg .code 16 333 1.1 mrg .thumb_func 334 1.1 mrg _interwork_call_via_r0 335 1.1 mrg bx pc 336 1.1 mrg nop 337 1.1 mrg 338 1.1 mrg .code 32 339 1.1 mrg tst r0, #1 340 1.1 mrg stmeqdb r13!, {lr} 341 1.1 mrg adreq lr, _arm_return 342 1.1 mrg bx r0 343 1.1 mrg 344 1.1 mrg The stub first switches to ARM mode, since it is a lot easier to 345 1.1 mrg perform the necessary operations using ARM instructions. It then 346 1.1 mrg tests the bottom bit of the register containing the address of the 347 1.1 mrg function to be called. If this bottom bit is set then the function 348 1.1 mrg being called uses Thumb instructions and the BX instruction to come 349 1.1 mrg will switch back into Thumb mode before calling this function. (Note 350 1.1 mrg that it does not matter how this called function chooses to return to 351 1.1 mrg its caller, since the both the caller and callee are Thumb functions, 352 1.1 mrg and mode switching is necessary). If the function being called is an 353 1.1 mrg ARM mode function however, the stub pushes the return address (with 354 1.1 mrg its bottom bit set) onto the stack, replaces the return address with 355 1.1 mrg the address of the a piece of code called '_arm_return' and then 356 1.1 mrg performs a BX instruction to call the function. 357 1.1 mrg 358 1.1 mrg The '_arm_return' code looks like this: 359 1.1 mrg 360 1.1 mrg .code 32 361 1.1 mrg _arm_return: 362 1.1 mrg ldmia r13!, {r12} 363 1.1 mrg bx r12 364 1.1 mrg .code 16 365 1.1 mrg 366 1.1 mrg 367 1.1 mrg It simply retrieves the return address from the stack, and then 368 1.1 mrg performs a BX operation to return to the caller and switch back into 369 1.1 mrg Thumb mode. 370 1.1 mrg 371 1.1 mrg 372 1.1 mrg 7. How callee-super-interworking support works 373 1.1 mrg ============================================== 374 1.1 mrg 375 1.1 mrg When -mcallee-super-interworking is specified on the command line the 376 1.1 mrg Thumb compiler behaves as if every externally visible function that it 377 1.1 mrg compiles has had the (interfacearm) attribute specified for it. What 378 1.1 mrg this attribute does is to put a special, ARM mode header onto the 379 1.1 mrg function which forces a switch into Thumb mode: 380 1.1 mrg 381 1.1 mrg without __attribute__((interfacearm)): 382 1.1 mrg 383 1.1 mrg .code 16 384 1.1 mrg .thumb_func 385 1.1 mrg function: 386 1.1 mrg ... start of function ... 387 1.1 mrg 388 1.1 mrg with __attribute__((interfacearm)): 389 1.1 mrg 390 1.1 mrg .code 32 391 1.1 mrg function: 392 1.1 mrg orr r12, pc, #1 393 1.1 mrg bx r12 394 1.1 mrg 395 1.1 mrg .code 16 396 1.1 mrg .thumb_func 397 1.1 mrg .real_start_of_function: 398 1.1 mrg 399 1.1 mrg ... start of function ... 400 1.1 mrg 401 1.1 mrg Note that since the function now expects to be entered in ARM mode, it 402 1.1 mrg no longer has the .thumb_func pseudo op specified for its name. 403 1.1 mrg Instead the pseudo op is attached to a new label .real_start_of_<name> 404 1.1 mrg (where <name> is the name of the function) which indicates the start 405 1.1 mrg of the Thumb code. This does have the interesting side effect in that 406 1.1 mrg if this function is now called from a Thumb mode piece of code 407 1.1 mrg outside of the current file, the linker will generate a calling stub 408 1.1 mrg to switch from Thumb mode into ARM mode, and then this is immediately 409 1.1 mrg overridden by the function's header which switches back into Thumb 410 1.1 mrg mode. 411 1.1 mrg 412 1.1 mrg In addition the (interfacearm) attribute also forces the function to 413 1.1 mrg return by using the BX instruction, even if has not been compiled with 414 1.1 mrg the -mthumb-interwork command line flag, so that the correct mode will 415 1.1 mrg be restored upon exit from the function. 416 1.1 mrg 417 1.1 mrg 418 1.1 mrg 8. Some examples 419 1.1 mrg ================ 420 1.1 mrg 421 1.1 mrg Given these two test files: 422 1.1 mrg 423 1.1 mrg int arm (void) { return 1 + thumb (); } 424 1.1 mrg 425 1.1 mrg int thumb (void) { return 2 + arm (); } 426 1.1 mrg 427 1.1 mrg The following pieces of assembler are produced by the ARM and Thumb 428 1.1 mrg version of GCC depending upon the command line options used: 429 1.1 mrg 430 1.1 mrg `-O2': 431 1.1 mrg .code 32 .code 16 432 1.1 mrg .global _arm .global _thumb 433 1.1 mrg .thumb_func 434 1.1 mrg _arm: _thumb: 435 1.1 mrg mov ip, sp 436 1.1 mrg stmfd sp!, {fp, ip, lr, pc} push {lr} 437 1.1 mrg sub fp, ip, #4 438 1.1 mrg bl _thumb bl _arm 439 1.1 mrg add r0, r0, #1 add r0, r0, #2 440 1.1 mrg ldmea fp, {fp, sp, pc} pop {pc} 441 1.1 mrg 442 1.1 mrg Note how the functions return without using the BX instruction. If 443 1.1 mrg these files were assembled and linked together they would fail to work 444 1.1 mrg because they do not change mode when returning to their caller. 445 1.1 mrg 446 1.1 mrg `-O2 -mthumb-interwork': 447 1.1 mrg 448 1.1 mrg .code 32 .code 16 449 1.1 mrg .global _arm .global _thumb 450 1.1 mrg .thumb_func 451 1.1 mrg _arm: _thumb: 452 1.1 mrg mov ip, sp 453 1.1 mrg stmfd sp!, {fp, ip, lr, pc} push {lr} 454 1.1 mrg sub fp, ip, #4 455 1.1 mrg bl _thumb bl _arm 456 1.1 mrg add r0, r0, #1 add r0, r0, #2 457 1.1 mrg ldmea fp, {fp, sp, lr} pop {r1} 458 1.1 mrg bx lr bx r1 459 1.1 mrg 460 1.1 mrg Now the functions use BX to return their caller. They have grown by 461 1.1 mrg 4 and 2 bytes respectively, but they can now successfully be linked 462 1.1 mrg together and be expect to work. The linker will replace the 463 1.1 mrg destinations of the two BL instructions with the addresses of calling 464 1.1 mrg stubs which convert to the correct mode before jumping to the called 465 1.1 mrg function. 466 1.1 mrg 467 1.1 mrg `-O2 -mcallee-super-interworking': 468 1.1 mrg 469 1.1 mrg .code 32 .code 32 470 1.1 mrg .global _arm .global _thumb 471 1.1 mrg _arm: _thumb: 472 1.1 mrg orr r12, pc, #1 473 1.1 mrg bx r12 474 1.1 mrg mov ip, sp .code 16 475 1.1 mrg stmfd sp!, {fp, ip, lr, pc} push {lr} 476 1.1 mrg sub fp, ip, #4 477 1.1 mrg bl _thumb bl _arm 478 1.1 mrg add r0, r0, #1 add r0, r0, #2 479 1.1 mrg ldmea fp, {fp, sp, lr} pop {r1} 480 1.1 mrg bx lr bx r1 481 1.1 mrg 482 1.1 mrg The thumb function now has an ARM encoded prologue, and it no longer 483 1.1 mrg has the `.thumb-func' pseudo op attached to it. The linker will not 484 1.1 mrg generate a calling stub for the call from arm() to thumb(), but it will 485 1.1 mrg still have to generate a stub for the call from thumb() to arm(). Also 486 1.1 mrg note how specifying `--mcallee-super-interworking' automatically 487 1.1 mrg implies `-mthumb-interworking'. 488 1.1 mrg 489 1.1 mrg 490 1.1 mrg 9. Some Function Pointer Examples 491 1.1 mrg ================================= 492 1.1 mrg 493 1.1 mrg Given this test file: 494 1.1 mrg 495 1.1 mrg int func (void) { return 1; } 496 1.1 mrg 497 1.1 mrg int call (int (* ptr)(void)) { return ptr (); } 498 1.1 mrg 499 1.1 mrg The following varying pieces of assembler are produced by the Thumb 500 1.1 mrg version of GCC depending upon the command line options used: 501 1.1 mrg 502 1.1 mrg `-O2': 503 1.1 mrg .code 16 504 1.1 mrg .globl _func 505 1.1 mrg .thumb_func 506 1.1 mrg _func: 507 1.1 mrg mov r0, #1 508 1.1 mrg bx lr 509 1.1 mrg 510 1.1 mrg .globl _call 511 1.1 mrg .thumb_func 512 1.1 mrg _call: 513 1.1 mrg push {lr} 514 1.1 mrg bl __call_via_r0 515 1.1 mrg pop {pc} 516 1.1 mrg 517 1.1 mrg Note how the two functions have different exit sequences. In 518 1.1 mrg particular call() uses pop {pc} to return, which would not work if the 519 1.1 mrg caller was in ARM mode. func() however, uses the BX instruction, even 520 1.1 mrg though `-mthumb-interwork' has not been specified, as this is the most 521 1.1 mrg efficient way to exit a function when the return address is held in the 522 1.1 mrg link register. 523 1.1 mrg 524 1.1 mrg `-O2 -mthumb-interwork': 525 1.1 mrg 526 1.1 mrg .code 16 527 1.1 mrg .globl _func 528 1.1 mrg .thumb_func 529 1.1 mrg _func: 530 1.1 mrg mov r0, #1 531 1.1 mrg bx lr 532 1.1 mrg 533 1.1 mrg .globl _call 534 1.1 mrg .thumb_func 535 1.1 mrg _call: 536 1.1 mrg push {lr} 537 1.1 mrg bl __call_via_r0 538 1.1 mrg pop {r1} 539 1.1 mrg bx r1 540 1.1 mrg 541 1.1 mrg This time both functions return by using the BX instruction. This 542 1.1 mrg means that call() is now two bytes longer and several cycles slower 543 1.1 mrg than the previous version. 544 1.1 mrg 545 1.1 mrg `-O2 -mcaller-super-interworking': 546 1.1 mrg .code 16 547 1.1 mrg .globl _func 548 1.1 mrg .thumb_func 549 1.1 mrg _func: 550 1.1 mrg mov r0, #1 551 1.1 mrg bx lr 552 1.1 mrg 553 1.1 mrg .globl _call 554 1.1 mrg .thumb_func 555 1.1 mrg _call: 556 1.1 mrg push {lr} 557 1.1 mrg bl __interwork_call_via_r0 558 1.1 mrg pop {pc} 559 1.1 mrg 560 1.1 mrg Very similar to the first (non-interworking) version, except that a 561 1.1 mrg different stub is used to call via the function pointer. This new stub 562 1.1 mrg will work even if the called function is not interworking aware, and 563 1.1 mrg tries to return to call() in ARM mode. Note that the assembly code for 564 1.1 mrg call() is still not interworking aware itself, and so should not be 565 1.1 mrg called from ARM code. 566 1.1 mrg 567 1.1 mrg `-O2 -mcallee-super-interworking': 568 1.1 mrg 569 1.1 mrg .code 32 570 1.1 mrg .globl _func 571 1.1 mrg _func: 572 1.1 mrg orr r12, pc, #1 573 1.1 mrg bx r12 574 1.1 mrg 575 1.1 mrg .code 16 576 1.1 mrg .globl .real_start_of_func 577 1.1 mrg .thumb_func 578 1.1 mrg .real_start_of_func: 579 1.1 mrg mov r0, #1 580 1.1 mrg bx lr 581 1.1 mrg 582 1.1 mrg .code 32 583 1.1 mrg .globl _call 584 1.1 mrg _call: 585 1.1 mrg orr r12, pc, #1 586 1.1 mrg bx r12 587 1.1 mrg 588 1.1 mrg .code 16 589 1.1 mrg .globl .real_start_of_call 590 1.1 mrg .thumb_func 591 1.1 mrg .real_start_of_call: 592 1.1 mrg push {lr} 593 1.1 mrg bl __call_via_r0 594 1.1 mrg pop {r1} 595 1.1 mrg bx r1 596 1.1 mrg 597 1.1 mrg Now both functions have an ARM coded prologue, and both functions 598 1.1 mrg return by using the BX instruction. These functions are interworking 599 1.1 mrg aware therefore and can safely be called from ARM code. The code for 600 1.1 mrg the call() function is now 10 bytes longer than the original, non 601 1.1 mrg interworking aware version, an increase of over 200%. 602 1.1 mrg 603 1.1 mrg If a prototype for call() is added to the source code, and this 604 1.1 mrg prototype includes the `interfacearm' attribute: 605 1.1 mrg 606 1.1 mrg int __attribute__((interfacearm)) call (int (* ptr)(void)); 607 1.1 mrg 608 1.1 mrg then this code is produced (with only -O2 specified on the command 609 1.1 mrg line): 610 1.1 mrg 611 1.1 mrg .code 16 612 1.1 mrg .globl _func 613 1.1 mrg .thumb_func 614 1.1 mrg _func: 615 1.1 mrg mov r0, #1 616 1.1 mrg bx lr 617 1.1 mrg 618 1.1 mrg .globl _call 619 1.1 mrg .code 32 620 1.1 mrg _call: 621 1.1 mrg orr r12, pc, #1 622 1.1 mrg bx r12 623 1.1 mrg 624 1.1 mrg .code 16 625 1.1 mrg .globl .real_start_of_call 626 1.1 mrg .thumb_func 627 1.1 mrg .real_start_of_call: 628 1.1 mrg push {lr} 629 1.1 mrg bl __call_via_r0 630 1.1 mrg pop {r1} 631 1.1 mrg bx r1 632 1.1 mrg 633 1.1 mrg So now both call() and func() can be safely called via 634 1.1 mrg non-interworking aware ARM code. If, when such a file is assembled, 635 1.1 mrg the assembler detects the fact that call() is being called by another 636 1.1 mrg function in the same file, it will automatically adjust the target of 637 1.1 mrg the BL instruction to point to .real_start_of_call. In this way there 638 1.1 mrg is no need for the linker to generate a Thumb-to-ARM calling stub so 639 1.1 mrg that call can be entered in ARM mode. 640 1.1 mrg 641 1.1 mrg 642 1.1 mrg 10. How to use dlltool to build ARM/Thumb DLLs 643 1.1 mrg ============================================== 644 1.1 mrg Given a program (`prog.c') like this: 645 1.1 mrg 646 1.1 mrg extern int func_in_dll (void); 647 1.1 mrg 648 1.1 mrg int main (void) { return func_in_dll(); } 649 1.1 mrg 650 1.1 mrg And a DLL source file (`dll.c') like this: 651 1.1 mrg 652 1.1 mrg int func_in_dll (void) { return 1; } 653 1.1 mrg 654 1.1 mrg Here is how to build the DLL and the program for a purely ARM based 655 1.1 mrg environment: 656 1.1 mrg 657 1.1 mrg *Step One 658 1.1 mrg Build a `.def' file describing the DLL: 659 1.1 mrg 660 1.1 mrg ; example.def 661 1.1 mrg ; This file describes the contents of the DLL 662 1.1 mrg LIBRARY example 663 1.1 mrg HEAPSIZE 0x40000, 0x2000 664 1.1 mrg EXPORTS 665 1.1 mrg func_in_dll 1 666 1.1 mrg 667 1.1 mrg *Step Two 668 1.1 mrg Compile the DLL source code: 669 1.1 mrg 670 1.1 mrg arm-pe-gcc -O2 -c dll.c 671 1.1 mrg 672 1.1 mrg *Step Three 673 1.1 mrg Use `dlltool' to create an exports file and a library file: 674 1.1 mrg 675 1.1 mrg dlltool --def example.def --output-exp example.o --output-lib example.a 676 1.1 mrg 677 1.1 mrg *Step Four 678 1.1 mrg Link together the complete DLL: 679 1.1 mrg 680 1.1 mrg arm-pe-ld dll.o example.o -o example.dll 681 1.1 mrg 682 1.1 mrg *Step Five 683 1.1 mrg Compile the program's source code: 684 1.1 mrg 685 1.1 mrg arm-pe-gcc -O2 -c prog.c 686 1.1 mrg 687 1.1 mrg *Step Six 688 1.1 mrg Link together the program and the DLL's library file: 689 1.1 mrg 690 1.1 mrg arm-pe-gcc prog.o example.a -o prog 691 1.1 mrg 692 1.1 mrg If instead this was a Thumb DLL being called from an ARM program, the 693 1.1 mrg steps would look like this. (To save space only those steps that are 694 1.1 mrg different from the previous version are shown): 695 1.1 mrg 696 1.1 mrg *Step Two 697 1.1 mrg Compile the DLL source code (using the Thumb compiler): 698 1.1 mrg 699 1.1 mrg thumb-pe-gcc -O2 -c dll.c -mthumb-interwork 700 1.1 mrg 701 1.1 mrg *Step Three 702 1.1 mrg Build the exports and library files (and support interworking): 703 1.1 mrg 704 1.1 mrg dlltool -d example.def -z example.o -l example.a --interwork -m thumb 705 1.1 mrg 706 1.1 mrg *Step Five 707 1.1 mrg Compile the program's source code (and support interworking): 708 1.1 mrg 709 1.1 mrg arm-pe-gcc -O2 -c prog.c -mthumb-interwork 710 1.1 mrg 711 1.1 mrg If instead, the DLL was an old, ARM DLL which does not support 712 1.1 mrg interworking, and which cannot be rebuilt, then these steps would be 713 1.1 mrg used. 714 1.1 mrg 715 1.1 mrg *Step One 716 1.1 mrg Skip. If you do not have access to the sources of a DLL, there is 717 1.1 mrg no point in building a `.def' file for it. 718 1.1 mrg 719 1.1 mrg *Step Two 720 1.1 mrg Skip. With no DLL sources there is nothing to compile. 721 1.1 mrg 722 1.1 mrg *Step Three 723 1.1 mrg Skip. Without a `.def' file you cannot use dlltool to build an 724 1.1 mrg exports file or a library file. 725 1.1 mrg 726 1.1 mrg *Step Four 727 1.1 mrg Skip. Without a set of DLL object files you cannot build the DLL. 728 1.1 mrg Besides it has already been built for you by somebody else. 729 1.1 mrg 730 1.1 mrg *Step Five 731 1.1 mrg Compile the program's source code, this is the same as before: 732 1.1 mrg 733 1.1 mrg arm-pe-gcc -O2 -c prog.c 734 1.1 mrg 735 1.1 mrg *Step Six 736 1.1 mrg Link together the program and the DLL's library file, passing the 737 1.1 mrg `--support-old-code' option to the linker: 738 1.1 mrg 739 1.1 mrg arm-pe-gcc prog.o example.a -Wl,--support-old-code -o prog 740 1.1 mrg 741 1.1 mrg Ignore the warning message about the input file not supporting 742 1.1 mrg interworking as the --support-old-code switch has taken care if this. 743 1.1 mrg 744 1.1 mrg 746 1.1 mrg Copyright (C) 1998-2022 Free Software Foundation, Inc. 747 1.1 mrg 748 1.1 mrg Copying and distribution of this file, with or without modification, 749 1.1 mrg are permitted in any medium without royalty provided the copyright 750 notice and this notice are preserved. 751