📄 readme-interworking
字号:
==============================================When -mcallee-super-interworking is specified on the command line theThumb compiler behaves as if every externally visible function that itcompiles has had the (interfacearm) attribute specified for it. Whatthis attribute does is to put a special, ARM mode header onto thefunction which forces a switch into Thumb mode: without __attribute__((interfacearm)): .code 16 .thumb_func function: ... start of function ... with __attribute__((interfacearm)): .code 32 function: orr r12, pc, #1 bx r12 .code 16 .thumb_func .real_start_of_function: ... start of function ...Note that since the function now expects to be entered in ARM mode, itno longer has the .thumb_func pseudo op specified for its name.Instead the pseudo op is attached to a new label .real_start_of_<name>(where <name> is the name of the function) which indicates the startof the Thumb code. This does have the interesting side effect in thatif this function is now called from a Thumb mode piece of codeoutsside of the current file, the linker will generate a calling stubto switch from Thumb mode into ARM mode, and then this is immediatelyoverridden by the function's header which switches back into Thumbmode. In addition the (interfacearm) attribute also forces the function toreturn by using the BX instruction, even if has not been compiled withthe -mthumb-interwork command line flag, so that the correct mode willbe restored upon exit from the function.8. Some examples================ Given these two test files: int arm (void) { return 1 + thumb (); } int thumb (void) { return 2 + arm (); } The following pieces of assembler are produced by the ARM and Thumbversion of GCC depending upon the command line options used: `-O2': .code 32 .code 16 .global _arm .global _thumb .thumb_func _arm: _thumb: mov ip, sp stmfd sp!, {fp, ip, lr, pc} push {lr} sub fp, ip, #4 bl _thumb bl _arm add r0, r0, #1 add r0, r0, #2 ldmea fp, {fp, sp, pc} pop {pc} Note how the functions return without using the BX instruction. Ifthese files were assembled and linked together they would fail to workbecause they do not change mode when returning to their caller. `-O2 -mthumb-interwork': .code 32 .code 16 .global _arm .global _thumb .thumb_func _arm: _thumb: mov ip, sp stmfd sp!, {fp, ip, lr, pc} push {lr} sub fp, ip, #4 bl _thumb bl _arm add r0, r0, #1 add r0, r0, #2 ldmea fp, {fp, sp, lr} pop {r1} bx lr bx r1 Now the functions use BX to return their caller. They have grown by4 and 2 bytes respectively, but they can now successfully be linkedtogether and be expect to work. The linker will replace thedestinations of the two BL instructions with the addresses of callingstubs which convert to the correct mode before jumping to the calledfunction. `-O2 -mcallee-super-interworking': .code 32 .code 32 .global _arm .global _thumb _arm: _thumb: orr r12, pc, #1 bx r12 mov ip, sp .code 16 stmfd sp!, {fp, ip, lr, pc} push {lr} sub fp, ip, #4 bl _thumb bl _arm add r0, r0, #1 add r0, r0, #2 ldmea fp, {fp, sp, lr} pop {r1} bx lr bx r1 The thumb function now has an ARM encoded prologue, and it no longerhas the `.thumb-func' pseudo op attached to it. The linker will notgenerate a calling stub for the call from arm() to thumb(), but it willstill have to generate a stub for the call from thumb() to arm(). Alsonote how specifying `--mcallee-super-interworking' automaticallyimplies `-mthumb-interworking'.9. Some Function Pointer Examples================================= Given this test file: int func (void) { return 1; } int call (int (* ptr)(void)) { return ptr (); } The following varying pieces of assembler are produced by the Thumbversion of GCC depending upon the command line options used: `-O2': .code 16 .globl _func .thumb_func _func: mov r0, #1 bx lr .globl _call .thumb_func _call: push {lr} bl __call_via_r0 pop {pc} Note how the two functions have different exit sequences. Inparticular call() uses pop {pc} to return, which would not work if thecaller was in ARM mode. func() however, uses the BX instruction, eventhough `-mthumb-interwork' has not been specified, as this is the mostefficient way to exit a function when the return address is held in thelink register. `-O2 -mthumb-interwork': .code 16 .globl _func .thumb_func _func: mov r0, #1 bx lr .globl _call .thumb_func _call: push {lr} bl __call_via_r0 pop {r1} bx r1 This time both functions return by using the BX instruction. Thismeans that call() is now two bytes longer and several cycles slowerthan the previous version. `-O2 -mcaller-super-interworking': .code 16 .globl _func .thumb_func _func: mov r0, #1 bx lr .globl _call .thumb_func _call: push {lr} bl __interwork_call_via_r0 pop {pc} Very similar to the first (non-interworking) version, except that adifferent stub is used to call via the function pointer. This new stubwill work even if the called function is not interworking aware, andtries to return to call() in ARM mode. Note that the assembly code forcall() is still not interworking aware itself, and so should not becalled from ARM code. `-O2 -mcallee-super-interworking': .code 32 .globl _func _func: orr r12, pc, #1 bx r12 .code 16 .globl .real_start_of_func .thumb_func .real_start_of_func: mov r0, #1 bx lr .code 32 .globl _call _call: orr r12, pc, #1 bx r12 .code 16 .globl .real_start_of_call .thumb_func .real_start_of_call: push {lr} bl __call_via_r0 pop {r1} bx r1 Now both functions have an ARM coded prologue, and both functionsreturn by using the BX instruction. These functions are interworkingaware therefore and can safely be called from ARM code. The code forthe call() function is now 10 bytes longer than the original, noninterworking aware version, an increase of over 200%. If a prototype for call() is added to the source code, and thisprototype includes the `interfacearm' attribute: int __attribute__((interfacearm)) call (int (* ptr)(void)); then this code is produced (with only -O2 specified on the commandline): .code 16 .globl _func .thumb_func _func: mov r0, #1 bx lr .globl _call .code 32 _call: orr r12, pc, #1 bx r12 .code 16 .globl .real_start_of_call .thumb_func .real_start_of_call: push {lr} bl __call_via_r0 pop {r1} bx r1 So now both call() and func() can be safely called vianon-interworking aware ARM code. If, when such a file is assembled,the assembler detects the fact that call() is being called by anotherfunction in the same file, it will automatically adjust the target ofthe BL instruction to point to .real_start_of_call. In this way thereis no need for the linker to generate a Thumb-to-ARM calling stub sothat call can be entered in ARM mode.10. How to use dlltool to build ARM/Thumb DLLs============================================== Given a program (`prog.c') like this: extern int func_in_dll (void); int main (void) { return func_in_dll(); } And a DLL source file (`dll.c') like this: int func_in_dll (void) { return 1; } Here is how to build the DLL and the program for a purely ARM basedenvironment:*Step One Build a `.def' file describing the DLL: ; example.def ; This file describes the contents of the DLL LIBRARY example HEAPSIZE 0x40000, 0x2000 EXPORTS func_in_dll 1*Step Two Compile the DLL source code: arm-pe-gcc -O2 -c dll.c*Step Three Use `dlltool' to create an exports file and a library file: dlltool --def example.def --output-exp example.o --output-lib example.a*Step Four Link together the complete DLL: arm-pe-ld dll.o example.o -o example.dll*Step Five Compile the program's source code: arm-pe-gcc -O2 -c prog.c*Step Six Link together the program and the DLL's library file: arm-pe-gcc prog.o example.a -o prog If instead this was a Thumb DLL being called from an ARM program, thesteps would look like this. (To save space only those steps that aredifferent from the previous version are shown):*Step Two Compile the DLL source code (using the Thumb compiler): thumb-pe-gcc -O2 -c dll.c -mthumb-interwork*Step Three Build the exports and library files (and support interworking): dlltool -d example.def -z example.o -l example.a --interwork -m thumb*Step Five Compile the program's source code (and support interworking): arm-pe-gcc -O2 -c prog.c -mthumb-interwork If instead, the DLL was an old, ARM DLL which does not supportinterworking, and which cannot be rebuilt, then these steps would beused.*Step One Skip. If you do not have access to the sources of a DLL, there is no point in building a `.def' file for it.*Step Two Skip. With no DLL sources there is nothing to compile.*Step Three Skip. Without a `.def' file you cannot use dlltool to build an exports file or a library file.*Step Four Skip. Without a set of DLL object files you cannot build the DLL. Besides it has already been built for you by somebody else.*Step Five Compile the program's source code, this is the same as before: arm-pe-gcc -O2 -c prog.c*Step Six Link together the program and the DLL's library file, passing the `--support-old-code' option to the linker: arm-pe-gcc prog.o example.a -Wl,--support-old-code -o prog Ignore the warning message about the input file not supporting interworking as the --support-old-code switch has taken care if this.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -