diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rwxr-xr-x | gcc/config.sub | 4 | ||||
-rw-r--r-- | gcc/config/arm/README-interworking | 553 | ||||
-rw-r--r-- | gcc/config/arm/lib1funcs.asm | 117 | ||||
-rw-r--r-- | gcc/config/arm/lib1thumb.asm | 159 | ||||
-rw-r--r-- | gcc/config/arm/t-pe | 31 | ||||
-rw-r--r-- | gcc/config/arm/t-pe-thumb | 37 | ||||
-rw-r--r-- | gcc/config/arm/t-semi | 2 | ||||
-rw-r--r-- | gcc/config/arm/t-thumb | 2 | ||||
-rw-r--r-- | gcc/config/arm/thumb.c | 183 | ||||
-rw-r--r-- | gcc/config/arm/thumb.h | 86 | ||||
-rw-r--r-- | gcc/config/arm/thumb.md | 27 | ||||
-rw-r--r-- | gcc/config/arm/tpe.h | 420 | ||||
-rwxr-xr-x | gcc/configure | 10 | ||||
-rw-r--r-- | gcc/configure.in | 10 |
15 files changed, 1506 insertions, 152 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 988ec23d8ab..8e821948519 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +Wed Apr 1 17:06:19 1998 Nick Clifton <nickc@cygnus.com> + + * config/arm/thumb.h: Add super interworking support. + * config/arm/thumb.c: Add super interworking support. + * config/arm/thumb.md: Add super interworking support. + * config/arm/tpe.h: New file. + * config/arm/lib1funcs.asm: Add interworking support. + * config/arm/lib1thumb.asm: Add super interworking support. + * config/arm/t-pe: New file. + * config/arm/t-semi: Add interworking support. + * config/arm/t-thumb: Add interworking support. + * config/arm/t-pe-thumb: New file. + * config/arm/README-interworking: New file. + * config.sub: Add thumb-pe target. + * configure.in: Add thumb-pe target. + * configure: Add thumb-pe target. + Wed Apr 1 14:38:10 1998 Jim Wilson <wilson@cygnus.com> * config/mips/iris6.h (MD_EXEC_PREFIX): Set to /usr/bin/. diff --git a/gcc/config.sub b/gcc/config.sub index dd52e87aee8..0271e3452ba 100755 --- a/gcc/config.sub +++ b/gcc/config.sub @@ -162,6 +162,10 @@ case $basic_machine in thumb | thumbel) basic_machine=$basic_machine-unknown ;; + thumb-pe) # CYGNUS LOCAL nickc/thumb-pe + basic_machine=$basic_machine-unknown + ;; + # END CYGNUS LOCAL nickc/thumb-pe # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. diff --git a/gcc/config/arm/README-interworking b/gcc/config/arm/README-interworking new file mode 100644 index 00000000000..a0069a9ea80 --- /dev/null +++ b/gcc/config/arm/README-interworking @@ -0,0 +1,553 @@ + Arm / Thumb Interworking + ======================== + +The Cygnus GNU Pro Toolkit for the ARM7T processor supports function +calls between code compiled for the ARM instruction set and code +compiled for the Thumb instruction set and vice versa. This document +describes how that interworking support operates and explains the +command line switches that should be used in order to produce working +programs. + +Note: The Cygnus GNU Pro Toolkit does not support switching between +compiling for the ARM instruction set and the Thumb instruction set +on anything other than a per file basis. There are in fact two +completely separate compilers, one that produces ARM assembler +instructions and one that produces Thumb assembler instructions. The +two compilers share the same assembler, linker and so on. + + +1. Explicit interworking support for C and C++ files +==================================================== + +By default if a file is compiled without any special command line +switches then the code produced will not support interworking. +Provided that a program is made up entirely from object files and +libraries produced in this way and which contain either exclusively +ARM instructions or exclusively Thumb instructions then this will not +matter and a working executable will be created. If an attempt is +made to link together mixed ARM and Thumb object files and libraries, +then warning messages will be produced by the linker and a non-working +executable will be created. + +In order to produce code which does support interworking it should be +compiled with the + + -mthumb-interwork + +command line option. Provided that a program is made up entirely from +object files and libraries built with this command line switch a +working executable will be produced, even if both ARM and Thumb +instructions are used by the various components of the program. (No +warning messages will be produced by the linker either). + +Note that specifying -mthumb-interwork does result in slightly larger, +slower code being produced. This is why interworking support must be +specifically enabled by a switch. + + +2. Explicit interworking support for assembler files +==================================================== + +If assembler files are to be included into an interworking program +then the following rules must be obeyed: + + * Any externally visible functions must return by using the BX + instruction. + + * Normal function calls can just use the BL instruction. The + linker will automatically insert code to switch between ARM + and Thumb modes as necessary. + + * Calls via function pointers should use the BX instruction if + the call is made in ARM mode: + + .code 32 + mov lr, pc + bx rX + + This code sequence will not work in Thumb mode however, since + the mov instruction will not set the bottom bit of the lr + register. Instead a branch-and-link to the _call_via_rX + functions should be used instead: + + .code 16 + bl _call_via_rX + + where rX is replaced by the name of the register containing + the function address. + + * All externally visible functions which should be entered in + Thumb mode must have the .thumb_func pseudo op specified just + before their entry point. eg: + + .code 16 + .global function + .thumb_func + function: + ...start of function.... + + * All assembler files must be assembled with the switch + -mthumb-interwork specified on the command line. (If the file + is assembled by calling gcc it will automatically pass on the + -mthumb-interwork switch to the assembler, provided that it + was specified on the gcc command line in the first place.) + + +3. Support for old, non-interworking aware code. +================================================ + +If it is necessary to link together code produced by an older, +non-interworking aware compiler, or code produced by the new compiler +but without the -mthumb-interwork command line switch specified, then +there are two command line switches that can be used to support this. + +The switch + + -mcaller-super-interworking + +will allow calls via function pointers in Thumb mode to work, +regardless of whether the function pointer points to old, +non-interworking aware code or not. Specifying this switch does +produce slightly slower code however. + +Note: There is no switch to allow calls via function pointers in ARM +mode to be handled specially. Calls via function pointers from +interworking aware ARM code to non-interworking aware ARM code work +without any special considerations by the compiler. Calls via +function pointers from interworking aware ARM code to non-interworking +aware Thumb code however will not work. (Actually under some +circumstances they may work, but there are no guarantees). This is +because only the new compiler is able to produce Thumb code, and this +compiler already has a command line switch to produce interworking +aware code. + + +The switch + + -mcallee-super-interworking + +will allow non-interworking aware ARM or Thumb code to call Thumb +functions, either directly or via function pointers. Specifying this +switch does produce slightly larger, slower code however. + +Note: There is no switch to allow non-interworking aware ARM or Thumb +code to call ARM functions. There is no need for any special handling +of calls from non-interworking aware ARM code to interworking aware +ARM functions, they just work normally. Calls from non-interworking +aware Thumb functions to ARM code however, will not work. There is no +option to support this, since it is always possible to recompile the +Thumb code to be interworking aware. + +As an alternative to the command line switch +-mcallee-super-interworking, which affects all externally visible +functions in a file, it is possible to specify an attribute or +declspec for individual functions, indicating that that particular +function should support being called by non-interworking aware code. +The function should be defined like this: + + int function __attribute__((interfacearm)) + { + ... body of function ... + } + +or + + int function __declspec(interfacearm) + { + ... body of function ... + } + + + +4. Interworking support in dlltool +================================== + +Currently there is no interworking support in dlltool. This may be a +future enhancement. + + + +5. How interworking support works +================================= + +Switching between the ARM and Thumb instruction sets is accomplished +via the BX instruction which takes as an argument a register name. +Control is transfered to the address held in this register (with the +bottom bit masked out), and if the bottom bit is set, then Thumb +instruction processing is enabled, otherwise ARM instruction +processing is enabled. + +When the -mthumb-interwork command line switch is specified, gcc +arranges for all functions to return to their caller by using the BX +instruction. Thus provided that the return address has the bottom bit +correctly initialised to indicate the instruction set of the caller, +correct operation will ensue. + +When a function is called explicitly (rather than via a function +pointer), the compiler generates a BL instruction to do this. The +Thumb version of the BL instruction has the special property of +setting the bottom bit of the LR register after it has stored the +return address into it, so that a future BX instruction will correctly +return the instruction after the BL instruction, in Thumb mode. + +The BL instruction does not change modes itself however, so if an ARM +function is calling a Thumb function, or vice versa, it is necessary +to generate some extra instructions to handle this. This is done in +the linker when it is storing the address of the referenced function +into the BL instruction. If the BL instruction is an ARM style BL +instruction, but the referenced function is a Thumb function, then the +linker automatically generates a calling stub that converts from ARM +mode to Thumb mode, puts the address of this stub into the BL +instruction, and puts the address of the referenced function into the +stub. Similarly if the BL instruction is a Thumb BL instruction, and +the referenced function is an ARM function, the linker generates a +stub which converts from Thumb to ARM mode, puts the address of this +stub into the BL instruction, and the address of the referenced +function into the stub. + +This is why it is necessary to mark Thumb functions with the +.thumb_func pseudo op when creating assembler files. This pseudo op +allows the assembler to distinguish between ARM functions and Thumb +functions. (The Thumb version of GCC automatically generates these +pseudo ops for any Thumb functions that it generates). + +Calls via function pointers work differently. Whenever the address of +a function is taken, the linker examines the type of the function +being referenced. If the function is a Thumb function, then it sets +the bottom bit of the address. Technically this makes the address +incorrect, since it is now one byte into the start of the function, +but this is never a problem because: + + a. with interworking enabled all calls via function pointer + are done using the BX instruction and this ignores the + bottom bit when computing where to go to. + + b. the linker will always set the bottom bit when the address + of the function is taken, so it is never possible to take + the address of the function in two different places and + then compare them and find that they are not equal. + +As already mentioned any call via a function pointer will use the BX +instruction (provided that interworking is enabled). The only problem +with this is computing the return address for the return from the +called function. For ARM code this can easily be done by the code +sequence: + + mov lr, pc + bx rX + +(where rX is the name of the register containing the function +pointer). This code does not work for the Thumb instruction set, +since the MOV instruction will not set the bottom bit of the LR +register, so that when the called function returns, it will return in +ARM mode not Thumb mode. Instead the compiler generates this +sequence: + + bl _call_via_rX + +(again where rX is the name if the register containing the function +pointer). The special call_via_rX functions look like this: + + .thumb_func +_call_via_r0: + bx r0 + nop + +The BL instruction ensures that the correct return address is stored +in the LR register and then the BX instruction jumps to the address +stored in the function pointer, switch modes if necessary. + + +6. How caller-super-interworking support works +============================================== + +When the -mcaller-super-interworking command line switch is specified +it changes the code produced by the Thumb compiler so that all calls +via function pointers (including virtual function calls) now go via a +different stub function. The code to call via a function pointer now +looks like this: + + bl _interwork_call_via_r0 + +Note: The compiler does not insist that r0 be used to hold the +function address. Any register will do, and there are a suite of stub +functions, one for each possible register. The stub functions look +like this: + + .code 16 + .thumb_func +_interwork_call_via_r0 + bx pc + nop + + .code 32 + tst r0, #1 + stmeqdb r13!, {lr} + adreq lr, _arm_return + bx r0 + +The stub first switches to ARM mode, since it is a lot easier to +perform the necessary operations using ARM instructions. It then +tests the bottom bit of the register containing the address of the +function to be called. If this bottom bit is set then the function +being called uses Thumb instructions and the BX instruction to come +will switch back into Thumb mode before calling this function. (Note +that it does not matter how this called function chooses to return to +its caller, since the both the caller and callee are Thumb functions, +and mode switching is necessary). If the function being called is an +ARM mode function however, the stub pushes the return address (with +its bottom bit set) onto the stack, replaces the return address with +the address of the a piece of code called '_arm_return' and then +performs a BX instruction to call the function. + +The '_arm_return' code looks like this: + + .code 32 +_arm_return: + ldmia r13!, {r12} + bx r12 + .code 16 + + +It simply retrieves the return address from the stack, and then +performs a BX operation to return to the caller and switch back into +Thumb mode. + + +7. How callee-super-interworking support works +============================================== + +When -mcallee-super-interworking is specified on the command line the +Thumb compiler behaves as if every externally visible function that it +compiles has had the (interfacearm) attribute specified for it. What +this attribute does is to put a special, ARM mode header onto the +function 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, it +no 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 start +of the Thumb code. This does have the interesting side effect in that +if this function is now called from a Thumb mode piece of code +outsside of the current file, the linker will generate a calling stub +to switch from Thumb mode into ARM mode, and then this is immediately +overridden by the function's header which switches back into Thumb +mode. + +In addition the (interfacearm) attribute also forces the function to +return by using the BX instruction, even if has not been compiled with +the -mthumb-interwork command line flag, so that the correct mode will +be restored upon exit from the function. + + +8. Some 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 depending upon +the command line options used: + +no options: + + @ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe + .code 16 + .text + .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. In +particular call() uses pop {pc} to return. This would not work if the +caller was in ARM mode. + +If -mthumb-interwork is specified on the command line: + + @ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe + .code 16 + .text + .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. This +means that call() is now two bytes longer and several cycles slower +than the version that is not interworking enabled. + +If -mcaller-super-interworking is specified: + + @ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe + .code 16 + .text + .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 a +different stub is used to call via the function pointer. Note that +the assembly code for call() is not interworking aware, and so should +not be called from ARM code. + +If -mcallee-super-interworking is specified: + + @ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe + .code 16 + .text + .globl _func + .code 32 + _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 + + .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 + +Now both functions have an ARM coded prologue, and both functions +return by using the BX instruction. These functions are interworking +aware therefore and can safely be called from ARM code. The code for +the call() function is now 10 bytes longer than the original, non +interworking aware version, an increase of over 200%. + +If the source code is slightly altered so that only the call function +has an (interfacearm) attribute: + + int func (void) { return 1; } + int call () __attribute__((interfacearm)); + int call (int (* ptr)(void)) { return ptr (); } + int main (void) { return printf ("result: %d\n", call (func)); } + +then this code is produced (with no command line switches): + + @ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe + .code 16 + .text + .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 + + .globl _main + .thumb_func + _main: + push {r4, lr} + bl ___gccmain + ldr r4, .L4 + ldr r0, .L4+4 + bl _call + add r1, r0, #0 + add r0, r4, #0 + bl _printf + pop {r4, pc} + .L4: + .word .LC0 + .word _func + + .section .rdata + .LC0: + .ascii "result: %d\n\000" + +So now only call() can be called via non-interworking aware ARM code. +When this program is assembled, the assembler detects the fact that +main() is calling call() in Thumb mode, and so automatically adjusts +the BL instruction to point to the real start of call(): + + Disassembly of section .text: + + 00000028 <_main>: + 28: b530 b530 push {r4, r5, lr} + 2a: fffef7ff f7ff bl 2a <_main+0x2> + 2e: 4d06 4d06 ldr r5, [pc, #24] (48 <.L7>) + 30: ffe8f7ff f7ff bl 4 <_doit> + 34: 1c04 1c04 add r4, r0, #0 + 36: 4805 4805 ldr r0, [pc, #20] (4c <.L7+0x4>) + 38: fff0f7ff f7ff bl 1c <.real_start_of_call> + 3c: 1824 1824 add r4, r4, r0 + 3e: 1c28 1c28 add r0, r5, #0 + 40: 1c21 1c21 add r1, r4, #0 + 42: fffef7ff f7ff bl 42 <_main+0x1a> + 46: bd30 bd30 pop {r4, r5, pc} + diff --git a/gcc/config/arm/lib1funcs.asm b/gcc/config/arm/lib1funcs.asm index c2db824738f..aac0ce1977f 100644 --- a/gcc/config/arm/lib1funcs.asm +++ b/gcc/config/arm/lib1funcs.asm @@ -402,3 +402,120 @@ SYM (__div0): RET pc, lr #endif /* L_divmodsi_tools */ + +#ifdef L_dvmd_lnx +@ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls + +#include <asm/unistd.h> +#define SIGFPE 8 @ cant use <asm/signal.h> as it + @ contains too much C rubbish + .globl SYM (__div0) + .align 0 +SYM (__div0): + stmfd sp!, {r1, lr} + swi __NR_getpid + cmn r0, #1000 + ldmgefd sp!, {r1, pc}RETCOND @ not much we can do + mov r1, #SIGFPE + swi __NR_kill + ldmfd sp!, {r1, pc}RETCOND + +#endif /* L_dvmd_lnx */ + +/* These next two sections are here despite the fact that they contain Thumb + assembler because their presence allows interworked code to be linked even + when the GCC library is this one. */ + +#ifdef L_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code. + The address of function to be called is loaded into a register and then + one of these labels is called via a BL instruction. This puts the + return address into the link register with the bottom bit set, and the + code here switches to the correct mode before executing the function. */ + + .text + .align 0 + .code 16 +.macro call_via register + .globl SYM (_call_via_\register) + .thumb_func +SYM (_call_via_\register): + bx \register + nop +.endm + + call_via r0 + call_via r1 + call_via r2 + call_via r3 + call_via r4 + call_via r5 + call_via r6 + call_via r7 + call_via r8 + call_via r9 + call_via sl + call_via fp + call_via ip + call_via sp + call_via lr + +#endif /* L_call_via_rX */ + +#ifdef L_interwork_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code, + when the target address is in an unknown instruction set. The address + of function to be called is loaded into a register and then one of these + labels is called via a BL instruction. This puts the return address + into the link register with the bottom bit set, and the code here + switches to the correct mode before executing the function. Unfortunately + the target code cannot be relied upon to return via a BX instruction, so + instead we have to store the resturn address on the stack and allow the + called function to return here instead. Upon return we recover the real + return address and use a BX to get back to Thumb mode. */ + + .text + .align 0 + + .code 32 +_arm_return: + ldmia r13!, {r12} + bx r12 + .code 16 + +.macro interwork register + .code 16 + .globl SYM (_interwork_call_via_\register) + .thumb_func +SYM (_interwork_call_via_\register): + bx pc + nop + + .code 32 + .globl .Lchange_\register +.Lchange_\register: + tst \register, #1 + stmeqdb r13!, {lr} + adreq lr, _arm_return + bx \register +.endm + + interwork r0 + interwork r1 + interwork r2 + interwork r3 + interwork r4 + interwork r5 + interwork r6 + interwork r7 + interwork r8 + interwork r9 + interwork sl + interwork fp + interwork ip + interwork sp + interwork lr + +#endif /* L_interwork_call_via_rX */ diff --git a/gcc/config/arm/lib1thumb.asm b/gcc/config/arm/lib1thumb.asm index 8df1ae79e7d..d50d35d15f1 100644 --- a/gcc/config/arm/lib1thumb.asm +++ b/gcc/config/arm/lib1thumb.asm @@ -605,98 +605,91 @@ SYM (__div0): one of these labels is called via a BL instruction. This puts the return address into the link register with the bottom bit set, and the code here switches to the correct mode before executing the function. */ - + .text .align 0 - - .globl SYM (_call_via_r0) - .thumb_func -SYM (_call_via_r0): - bx r0 - nop - - .globl SYM (_call_via_r1) - .thumb_func -SYM (_call_via_r1): - bx r1 - nop - - .globl SYM (_call_via_r2) - .thumb_func -SYM (_call_via_r2): - bx r2 - nop - - .globl SYM (_call_via_r3) - .thumb_func -SYM (_call_via_r3): - bx r3 - nop - - .globl SYM (_call_via_r4) - .thumb_func -SYM (_call_via_r4): - bx r4 - nop - - .globl SYM (_call_via_r5) - .thumb_func -SYM (_call_via_r5): - bx r5 - nop - - .globl SYM (_call_via_r6) - .thumb_func -SYM (_call_via_r6): - bx r6 - nop - .globl SYM (_call_via_r7) +.macro call_via register + .globl SYM (_call_via_\register) .thumb_func -SYM (_call_via_r7): - bx r7 +SYM (_call_via_\register): + bx \register nop +.endm + + call_via r0 + call_via r1 + call_via r2 + call_via r3 + call_via r4 + call_via r5 + call_via r6 + call_via r7 + call_via r8 + call_via r9 + call_via sl + call_via fp + call_via ip + call_via sp + call_via lr - .globl SYM (_call_via_r8) - .thumb_func -SYM (_call_via_r8): - bx r8 - nop - - .globl SYM (_call_via_r9) - .thumb_func -SYM (_call_via_r9): - bx r9 - nop - - .globl SYM (_call_via_sl) - .thumb_func -SYM (_call_via_sl): - bx sl - nop - - .globl SYM (_call_via_fp) - .thumb_func -SYM (_call_via_fp): - bx fp - nop +#endif /* L_call_via_rX */ - .globl SYM (_call_via_ip) - .thumb_func -SYM (_call_via_ip): - bx ip - nop +#ifdef L_interwork_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code, + when the target address is in an unknown instruction set. The address + of function to be called is loaded into a register and then one of these + labels is called via a BL instruction. This puts the return address + into the link register with the bottom bit set, and the code here + switches to the correct mode before executing the function. Unfortunately + the target code cannot be relied upon to return via a BX instruction, so + instead we have to store the resturn address on the stack and allow the + called function to return here instead. Upon return we recover the real + return address and use a BX to get back to Thumb mode. */ + + .text + .align 0 - .globl SYM (_call_via_sp) - .thumb_func -SYM (_call_via_sp): - bx sp - nop + .code 32 +_arm_return: + ldmia r13!, {r12} + bx r12 + .code 16 - .globl SYM (_call_via_lr) +.macro interwork register + .globl SYM (_interwork_call_via_\register) .thumb_func -SYM (_call_via_lr): - bx lr +SYM (_interwork_call_via_\register): + bx pc nop + + .code 32 + .globl .Lchange_\register +.Lchange_\register: + tst \register, #1 + stmeqdb r13!, {lr} + adreq lr, _arm_return + bx \register + .code 16 +.endm + + interwork r0 + interwork r1 + interwork r2 + interwork r3 + interwork r4 + interwork r5 + interwork r6 + interwork r7 + interwork r8 + interwork r9 + interwork sl + interwork fp + interwork ip + interwork sp + interwork lr + +#endif /* L_interwork_call_via_rX */ -#endif /* L_call_via_rX */ + diff --git a/gcc/config/arm/t-pe b/gcc/config/arm/t-pe new file mode 100644 index 00000000000..e68b3c90e75 --- /dev/null +++ b/gcc/config/arm/t-pe @@ -0,0 +1,31 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1funcs.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +pe.o: $(srcdir)/config/arm/pe.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c + +MULTILIB_OPTIONS = mhard-float +MULTILIB_DIRNAMES = fpu + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc/config/arm/t-pe-thumb b/gcc/config/arm/t-pe-thumb new file mode 100644 index 00000000000..253c814cbaf --- /dev/null +++ b/gcc/config/arm/t-pe-thumb @@ -0,0 +1,37 @@ +# Makefile fragment +# Copyright (c) 1998 Free Software Foundation +# CYGNUS LOCAL (entire file) nickc/thumb-pe + +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1thumb.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +# Rule to build Psion specific GCC functions. +pe.o: $(srcdir)/config/arm/pe.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c + +# Avoid building a duplicate set of libraries for the default endian-ness. +MULTILIB_OPTIONS = mthumb-interwork +MULTILIB_DIRNAMES = interwork + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc/config/arm/t-semi b/gcc/config/arm/t-semi index c14782a6d89..74fdef49920 100644 --- a/gcc/config/arm/t-semi +++ b/gcc/config/arm/t-semi @@ -11,7 +11,7 @@ LIBGCC1_TEST = CROSS_LIBGCC1 = libgcc1-asm.a LIB1ASMSRC = arm/lib1funcs.asm -LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX #Don't try to run fixproto STMP_FIXPROTO = diff --git a/gcc/config/arm/t-thumb b/gcc/config/arm/t-thumb index 1701258e06f..6b349e2fdf0 100644 --- a/gcc/config/arm/t-thumb +++ b/gcc/config/arm/t-thumb @@ -1,6 +1,6 @@ CROSS_LIBGCC1 = libgcc1-asm.a LIB1ASMSRC = arm/lib1thumb.asm -LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX # adddi3/subdi3 added to machine description #LIB1ASMFUNCS = _adddi3 _subdi3 _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls diff --git a/gcc/config/arm/thumb.c b/gcc/config/arm/thumb.c index 1a2eb18ff8d..9f025f8dadc 100644 --- a/gcc/config/arm/thumb.c +++ b/gcc/config/arm/thumb.c @@ -540,6 +540,43 @@ thumb_reload_out_si (operands) abort (); } +#ifdef THUMB_PE /* CYGNUS LOCAL nickc/thumb-pe */ +/* Return non-zero if FUNC is a naked function. */ + +static int +arm_naked_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} +#endif /* END CYGNUS LOCAL nickc/thumb-pe */ + +/* CYGNUS LOCAL nickc/super-interworking */ +/* Return non-zero if FUNC must be entered in ARM mode. */ +int +is_called_in_ARM_mode (func) + tree func; +{ + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + /* Ignore the problem about functions whoes address is taken. */ + if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) + return TRUE; + +#ifdef THUMB_PE + return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; +#else + return FALSE; +#endif +} +/* END CYGNUS LOCAL */ /* Routines for emitting code */ @@ -585,10 +622,9 @@ number_of_first_bit_set (mask) #define LINK_REGISTER 14 #define PROGRAM_COUNTER 15 -/* Generate code to return from a thumb function. - If 'reg_containing_return_addr' is -1, then the - address is actually on the stack, at the stack - pointer. */ +/* Generate code to return from a thumb function. If + 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ static void thumb_exit (f, reg_containing_return_addr) @@ -634,9 +670,15 @@ thumb_exit (f, reg_containing_return_addr) } /* Otherwise if we are not supporting interworking and we have not created - a backtrace structure then just pop the return address straight into the PC. */ + a backtrace structure and the function was not entered in ARM mode then + just pop the return address straight into the PC. */ - else if (! TARGET_THUMB_INTERWORK && ! TARGET_BACKTRACE) + else if ( ! TARGET_THUMB_INTERWORK + && ! TARGET_BACKTRACE +/* CYGNUS LOCAL nickc/super-interworking */ + && ! is_called_in_ARM_mode (current_function_decl) +/* END CYGNUS LOCAL */ + ) { asm_fprintf (f, "\tpop\t{pc}\n" ); @@ -926,7 +968,7 @@ thumb_pushpop (f, mask, push) if (mask & 0xFF) asm_fprintf (f, ", "); - asm_fprintf (f, "%s", reg_names[14]); + asm_fprintf (f, reg_names[14]); } else if (!push && (mask & (1 << 15))) { @@ -948,7 +990,7 @@ thumb_pushpop (f, mask, push) if (mask & 0xFF) asm_fprintf (f, ", "); - asm_fprintf (f, "%s", reg_names[15]); + asm_fprintf (f, reg_names[15]); } } @@ -995,7 +1037,12 @@ output_return () { thumb_exit (asm_out_file, 14); } - else if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) + else if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE +/* CYGNUS LOCAL nickc/super-interworking */ + || is_called_in_ARM_mode (current_function_decl) +/* END CYGNUS LOCAL */ + ) { thumb_exit (asm_out_file, -1); } @@ -1014,7 +1061,12 @@ output_return () asm_fprintf (asm_out_file, ", "); } - if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) + if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE +/* CYGNUS LOCAL nickc/super-interworking */ + || is_called_in_ARM_mode (current_function_decl) +/* END CYGNUS LOCAL */ + ) { asm_fprintf (asm_out_file, "}\n"); thumb_exit (asm_out_file, -1); @@ -1037,6 +1089,43 @@ thumb_function_prologue (f, frame_size) int store_arg_regs = 0; int regno; +#ifdef THUMB_PE /* CYGNUS LOCAL nickc/thumb-pe */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif /* CYGNUS LOCAL nickc/thumb-pe */ + +/* CYGNUS LOCAL nickc/super-interworking */ + if (is_called_in_ARM_mode (current_function_decl)) + { + char * name; + if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) + abort(); + if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) + abort(); + name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + + /* Generate code sequence to switch us into Thumb mode. */ + /* The .code 32 directive has already been emitted by + ASM_DECLARE_FUNCITON_NAME */ + asm_fprintf (f, "\torr\tr12, pc, #1\n"); + asm_fprintf (f, "\tbx\tr12\n"); + + /* Generate a label, so that the debugger will notice the + change in instruction sets. This label is also used by + the assembler to bypass the ARM code when this function + is called from a Thumb encoded function elsewhere in the + same file. Hence the definition of STUB_NAME here must + agree with the definition in gas/config/tc-arm.c */ + +#define STUB_NAME ".real_start_of" + + asm_fprintf (f, "\t.code\t16\n"); + asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); + asm_fprintf (f, "\t.thumb_func\n"); + asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); + } +/* END CYGNUS LOCAL nickc/super-interworking */ + if (current_function_anonymous_args && current_function_pretend_args_size) store_arg_regs = 1; @@ -1318,7 +1407,7 @@ thumb_unexpanded_epilogue () int high_regs_pushed = 0; int leaf_function = leaf_function_p (); int had_to_push_lr; - + if (return_used_this_function) return ""; @@ -1329,7 +1418,7 @@ thumb_unexpanded_epilogue () for (regno = 8; regno < 13; regno++) { if (regs_ever_live[regno] && ! call_used_regs[regno]) - high_regs_pushed++; + high_regs_pushed ++; } /* The prolog may have pushed some high registers to use as @@ -1385,7 +1474,6 @@ thumb_unexpanded_epilogue () while (high_regs_pushed) { /* Find low register(s) into which the high register(s) can be popped. */ - for (regno = 0; regno < 8; regno++) { if (mask & (1 << regno)) @@ -1397,11 +1485,9 @@ thumb_unexpanded_epilogue () mask &= (2 << regno) - 1; /* A noop if regno == 8 */ /* Pop the values into the low register(s). */ - thumb_pushpop (asm_out_file, mask, 0); /* Move the value(s) into the high registers. */ - for (regno = 0; regno < 8; regno++) { if (mask & (1 << regno)) @@ -1419,11 +1505,6 @@ thumb_unexpanded_epilogue () had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); - if (had_to_push_lr) - { - live_regs_mask |= 1 << PROGRAM_COUNTER; - } - if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) { /* The stack backtrace structure creation code had to @@ -1435,6 +1516,13 @@ thumb_unexpanded_epilogue () if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) { + if (had_to_push_lr +/* CYGNUS LOCAL nickc/super-interworking */ + && ! is_called_in_ARM_mode (current_function_decl) +/* END CYGNUS LOCAL nickc/super-interworking */ + ) + live_regs_mask |= 1 << PROGRAM_COUNTER; + /* Either no argument registers were pushed or a backtrace structure was created which includes an adjusted stack pointer, so just pop everything. */ @@ -1443,15 +1531,23 @@ thumb_unexpanded_epilogue () thumb_pushpop (asm_out_file, live_regs_mask, FALSE); /* We have either just popped the return address into the - PC or it is was kept in LR for the entire function. */ + PC or it is was kept in LR for the entire function or + it is still on the stack because we do not want to + return by doing a pop {pc}. */ - if (! had_to_push_lr) - thumb_exit (asm_out_file, LINK_REGISTER); + if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) + thumb_exit (asm_out_file, + ( + had_to_push_lr +/* CYGNUS LOCAL nickc/super-interworking */ + && is_called_in_ARM_mode (current_function_decl) +/* END CYGNUS LOCAL */ + ) ? -1 : LINK_REGISTER + ); } else { /* Pop everything but the return address. */ - live_regs_mask &= ~ (1 << PROGRAM_COUNTER); if (live_regs_mask) @@ -1460,15 +1556,13 @@ thumb_unexpanded_epilogue () if (had_to_push_lr) { /* Get the return address into a temporary register. */ - thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); } /* Remove the argument registers that were pushed onto the stack. */ - asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", - reg_names[STACK_POINTER], - reg_names[STACK_POINTER], + reg_names [STACK_POINTER], + reg_names [STACK_POINTER], current_function_pretend_args_size); thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); @@ -1963,3 +2057,36 @@ void thumb_override_options() warning ("Structure size boundary can only be set to 8 or 32"); } } + +#ifdef THUMB_PE /* CYGNUS LOCAL nickc/thumb-pe */ +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + naked: don't output any prologue or epilogue code, the user is assumed + to do the right thing. + + interfacearm: Always assume that this function will be entered in ARM + mode, not Thumb mode, and that the caller wishes to be returned to in + ARM mode. */ +int +arm_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("naked", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + if (is_attribute_p ("interfacearm", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + return 0; +} +#endif /* END CYGNUS LOCAL nickc/thumb-pe */ diff --git a/gcc/config/arm/thumb.h b/gcc/config/arm/thumb.h index 61218661b7e..a847c5659a4 100644 --- a/gcc/config/arm/thumb.h +++ b/gcc/config/arm/thumb.h @@ -55,36 +55,63 @@ Boston, MA 02111-1307, USA. */ #define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); /* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ -#define THUMB_FLAG_BIG_END (0x0001) -#define THUMB_FLAG_BACKTRACE (0x0002) -#define THUMB_FLAG_LEAF_BACKTRACE (0x0004) -#define ARM_FLAG_THUMB (0x1000) /* same as in arm.h */ +#define THUMB_FLAG_BIG_END 0x0001 +#define THUMB_FLAG_BACKTRACE 0x0002 +#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 +#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ +#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 /* CYGNUS LOCAL nickc */ +#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 /* CYGNUS LOCAL nickc */ + /* Run-time compilation parameters selecting different hardware/software subsets. */ extern int target_flags; #define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ #define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) #define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) -#define TARGET_BACKTRACE (leaf_function_p() \ - ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ +#define TARGET_BACKTRACE (leaf_function_p() \ + ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ : (target_flags & THUMB_FLAG_BACKTRACE)) -#define TARGET_SWITCHES \ -{ \ - {"big-endian", THUMB_FLAG_BIG_END}, \ - {"little-endian", -THUMB_FLAG_BIG_END}, \ - {"thumb-interwork", ARM_FLAG_THUMB}, \ - {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ - {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ - {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ - {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ - {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ - {"", TARGET_DEFAULT} \ +/* CYGNUS LOCAL nickc/super-interworking */ +/* Set if externally visable functions should assume that they + might be called in ARM mode, from a non-thumb aware code. */ +#define TARGET_CALLEE_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) + +/* Set if calls via function pointers should assume that their + destination is non-Thumb aware. */ +#define TARGET_CALLER_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) +/* END CYGNUS LOCAL */ + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"big-endian", THUMB_FLAG_BIG_END}, \ + {"little-endian", -THUMB_FLAG_BIG_END}, \ + {"thumb-interwork", ARM_FLAG_THUMB}, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ + {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ + {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ + {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ + {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ + /* CYGNUS LOCAL nickc/super-interworking */ \ + {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + /* END CYGNUS LOCAL */ \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT} \ } -#define TARGET_OPTIONS \ -{ \ - { "structure-size-boundary=", & structure_size_string }, \ +#define TARGET_OPTIONS \ +{ \ + { "structure-size-boundary=", & structure_size_string }, \ } #define REGISTER_PREFIX "" @@ -1026,7 +1053,12 @@ int thumb_shiftable_const (); /* Emit a special directive when defining a function name. This is used by the assembler to assit with interworking. */ #define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ - fprintf (file, ".thumb_func\n") ; \ +/* CYGNUS LOCAL nickc/supr-interworking */ \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (file, "\t.thumb_func\n") ; \ + else \ + fprintf (file, "\t.code\t32\n") ; \ +/* END CYGNUS LOCAL */ \ ASM_OUTPUT_LABEL (file, name) #define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ @@ -1095,8 +1127,10 @@ int thumb_shiftable_const (); int thumb_trivial_epilogue (); #define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) -extern char *thumb_unexpanded_epilogue (); -extern char *output_move_mem_multiple (); -extern char *thumb_load_double_from_address (); -extern char *output_return (); -extern int far_jump_used_p(); +extern char * thumb_unexpanded_epilogue (); +extern char * output_move_mem_multiple (); +extern char * thumb_load_double_from_address (); +extern char * output_return (); +extern int far_jump_used_p(); +extern int is_called_in_ARM_mode (); /* CYGNUS LOCAL */ + diff --git a/gcc/config/arm/thumb.md b/gcc/config/arm/thumb.md index 1e0ee38051d..2334aa1b10c 100644 --- a/gcc/config/arm/thumb.md +++ b/gcc/config/arm/thumb.md @@ -989,19 +989,20 @@ (define_insn "*call_indirect" [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) (match_operand 1 "" ""))] - "TARGET_THUMB_INTERWORK" + "! TARGET_CALLER_INTERWORKING" "bl\\t__call_via_%0" [(set_attr "length" "4")]) +;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version +;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set +;; the bottom bit of lr so that a function return (using bx) +;; would switch back into ARM mode... - -(define_insn "*call_indirect" +(define_insn "*call_indirect_interwork" [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) (match_operand 1 "" ""))] - "! TARGET_THUMB_INTERWORK" - "bl\\t__call_via_%0" + "TARGET_CALLER_INTERWORKING" + "bl\\t__interwork_call_via_%0" [(set_attr "length" "4")]) -;; used to be: "mov\\tlr,pc\;bx\\t%0" -;; but this does not set bottom bit of lr (define_expand "call_value" [(set (match_operand 0 "" "") @@ -1014,19 +1015,19 @@ [(set (match_operand 0 "" "=l") (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) (match_operand 2 "" "")))] - "TARGET_THUMB_INTERWORK" + "! TARGET_CALLER_INTERWORKING" "bl\\t__call_via_%1" [(set_attr "length" "4")]) +;; See comment for call_indirect pattern -(define_insn "*call_value_indirect" +(define_insn "*call_value_indirect_interwork" [(set (match_operand 0 "" "=l") (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) (match_operand 2 "" "")))] - "! TARGET_THUMB_INTERWORK" - "bl\\t__call_via_%1" + "TARGET_CALLER_INTERWORKING" + "bl\\t__interwork_call_via_%1" [(set_attr "length" "4")]) -;; used to be "mov\\tlr,pc\;bx\\t%1" -;; but this does not set bottom bit of lr + (define_insn "*call_insn" [(call (mem:SI (match_operand:SI 0 "" "i")) diff --git a/gcc/config/arm/tpe.h b/gcc/config/arm/tpe.h new file mode 100644 index 00000000000..375a84c107d --- /dev/null +++ b/gcc/config/arm/tpe.h @@ -0,0 +1,420 @@ +/* CYGNUS LOCAL (entire file) nickc/thumb-pe */ +/* Definitions of target machine for GNU compiler, + for Thumb with PE object format. + Copyright (C) 1998 Free Software Foundation, Inc. + Derived from arm/coff.h and arm/pe.h originally by Doug Evans (evans@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "arm/thumb.h" + +#define THUMB_PE 1 + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (Thumb/pe)", stderr) + +/* Support the __declspec keyword by turning them into attributes. + We currently only support: naked, dllimport, and dllexport. + Note that the current way we do this may result in a collision with + predefined attributes later on. This can be solved by using one attribute, + say __declspec__, and passing args to it. The problem with that approach + is that args are not accumulated: each new appearance would clobber any + existing args. */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "\ +-Dthumb -D__thumb -D__pe__ -Acpu(arm) -Amachine(arm) \ +-D__declspec(x)=__attribute__((x)) \ +" + +/* Experimental addition for pr 7885. + Ignore dllimport for functions. */ +#define ARM_FLAG_NOP_FUN_IMPORT 0x20000 +#define TARGET_NOP_FUN_DLLIMPORT (target_flags & ARM_FLAG_NOP_FUN_IMPORT) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ +{ "nop-fun-dllimport", ARM_FLAG_NOP_FUN_IMPORT }, \ +{ "no-nop-fun-dllimport", -ARM_FLAG_NOP_FUN_IMPORT }, + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT ARM_FLAG_NOP_FUN_IMPORT + +/* Setting this to 32 produces more efficient code, but the value set in previous + versions of this toolchain was 8, which produces more compact structures. The + command line option -mstructure_size_boundary=<n> can be used to change this + value. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary + +extern int arm_structure_size_boundary; + +/* This is COFF, but prefer stabs. */ +#define SDB_DEBUGGING_INFO + +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#include "dbxcoff.h" + +/* Note - it is important that these definitions match those in semi.h for the ARM port. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + +/* A C statement to output assembler commands which will identify the + object file as having been compiled with GNU CC (or another GNU + compiler). */ +#define ASM_IDENTIFY_GCC(STREAM) \ + fprintf (STREAM, "%sgcc2_compiled.:\n%s", LOCAL_LABEL_PREFIX, ASM_APP_OFF ) + +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf ((STREAM), "%s Generated by gcc %s for Thumb/coff\n", \ + ASM_COMMENT_START, version_string); \ + fprintf ((STREAM), ASM_APP_OFF); \ +} while (0) + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#undef INIT_SECTION_ASM_OP + +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. */ +#define JUMP_TABLES_IN_TEXT_SECTION + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION rdata_section +#undef RDATA_SECTION_ASM_OP +#define RDATA_SECTION_ASM_OP "\t.section .rdata" + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"x\"" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"x\"" + +/* A list of other sections which the compiler might be "in" at any + given time. */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors + +#define SUBTARGET_EXTRA_SECTIONS + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + RDATA_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION \ + SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +/* Support the ctors/dtors sections for g++. */ + +#define INT_ASM_OP ".word" + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* __CTOR_LIST__ and __DTOR_LIST__ must be defined by the linker script. */ +#define CTOR_LISTS_DEFINED_EXTERNALLY + +#undef DO_GLOBAL_CTORS_BODY +#undef DO_GLOBAL_DTORS_BODY + +/* The ARM development system has atexit and doesn't have _exit, + so define this for now. */ +#define HAVE_ATEXIT + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain + +/* This is to better conform to the ARM PCS. + Richard Earnshaw hasn't put this into FSF sources yet so it's here. */ +#undef RETURN_IN_MEMORY +#define RETURN_IN_MEMORY(TYPE) \ + ((TYPE_MODE ((TYPE)) == BLKmode && ! TYPE_NO_FORCE_BLK (TYPE)) \ + || (AGGREGATE_TYPE_P ((TYPE)) && arm_pe_return_in_memory ((TYPE)))) + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +extern int arm_pe_valid_machine_decl_attribute (); +extern int arm_valid_machine_decl_attribute (); +#undef VALID_MACHINE_DECL_ATTRIBUTE +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ + arm_pe_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +extern union tree_node * arm_pe_merge_machine_decl_attributes (); +#define MERGE_MACHINE_DECL_ATTRIBUTES(OLD, NEW) \ + arm_pe_merge_machine_decl_attributes ((OLD), (NEW)) + +/* In addition to the stuff done in arm.h, we must mark dll symbols specially. + Definitions of dllexport'd objects install some info in the .drectve + section. References to dllimport'd objects are fetched indirectly via + __imp_. If both are declared, dllexport overrides. + This is also needed to implement one-only vtables: they go into their own + section and we need to set DECL_SECTION_NAME so we do that here. + Note that we can be called twice on the same decl. */ +extern void arm_pe_encode_section_info (); +#undef ENCODE_SECTION_INFO +#define ENCODE_SECTION_INFO(DECL) \ + arm_pe_encode_section_info (DECL) + + /* Utility used only in this file. */ +#define ARM_STRIP_NAME_ENCODING(SYM_NAME) \ +((SYM_NAME) + ((SYM_NAME)[0] == '@' ? 3 : 0)) + +/* Strip any text from SYM_NAME added by ENCODE_SECTION_INFO and store + the result in VAR. */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR, SYM_NAME) \ +(VAR) = ARM_STRIP_NAME_ENCODING (SYM_NAME) + +/* Define this macro if in some cases global symbols from one translation + unit may not be bound to undefined symbols in another translation unit + without user intervention. For instance, under Microsoft Windows + symbols must be explicitly imported from shared libraries (DLLs). */ +#define MULTIPLE_SYMBOL_SPACES + +#define UNIQUE_SECTION_P(DECL) DECL_ONE_ONLY (DECL) +extern void arm_pe_unique_section (); +#define UNIQUE_SECTION(DECL,RELOC) arm_pe_unique_section (DECL, RELOC) + +#define SUPPORTS_ONE_ONLY 1 + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#undef ASM_OUTPUT_SECTION_NAME +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ + /* Functions may have been compiled at various levels of \ + optimization so we can't use `same_size' here. Instead, \ + have the linker pick one. */ \ + if ((DECL) && DECL_ONE_ONLY (DECL)) \ + fprintf (STREAM, "\t.linkonce %s\n", \ + TREE_CODE (DECL) == FUNCTION_DECL \ + ? "discard" : "same_size"); \ +} while (0) + +/* This outputs a lot of .req's to define alias for various registers. + Let's try to avoid this. */ +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf (STREAM, "%s Generated by gcc %s for ARM/pe\n", \ + ASM_COMMENT_START, version_string); \ + output_file_directive ((STREAM), main_input_filename); \ +} while (0) + +/* Output a reference to a label. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ +fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, ARM_STRIP_NAME_ENCODING (NAME)) + +/* Output a function definition label. */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ +do { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ + ARM_STRIP_NAME_ENCODING (NAME)); \ + function_section (DECL); \ + } \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (STREAM, "\t.thumb_func\n") ; \ + else \ + fprintf (STREAM, "\t.code\t32\n") ; \ + ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ +} while (0) + +/* Output a common block. */ +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ +do { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", \ + ARM_STRIP_NAME_ENCODING (NAME)); \ + } \ + if (! arm_dllimport_name_p (NAME)) \ + { \ + fprintf ((STREAM), "\t.comm\t"); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ", %d\t%s %d\n", \ + (ROUNDED), ASM_COMMENT_START, (SIZE)); \ + } \ +} while (0) + +/* Output the label for an initialized variable. */ +#undef ASM_DECLARE_OBJECT_NAME +#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ +do { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + enum in_section save_section = in_section; \ + drectve_section (); \ + fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ + ARM_STRIP_NAME_ENCODING (NAME)); \ + switch_to_section (save_section, (DECL)); \ + } \ + ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#define DRECTVE_SECTION_ASM_OP "\t.section .drectve" + +/* A list of other sections which the compiler might be "in" at any + given time. */ + +#undef SUBTARGET_EXTRA_SECTIONS +#define SUBTARGET_EXTRA_SECTIONS in_drectve, + +/* A list of extra section function definitions. */ + +#undef SUBTARGET_EXTRA_SECTION_FUNCTIONS +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS \ + DRECTVE_SECTION_FUNCTION \ + SWITCH_TO_SECTION_FUNCTION + +#define DRECTVE_SECTION_FUNCTION \ +void \ +drectve_section () \ +{ \ + if (in_section != in_drectve) \ + { \ + fprintf (asm_out_file, "%s\n", DRECTVE_SECTION_ASM_OP); \ + in_section = in_drectve; \ + } \ +} + +/* Switch to SECTION (an `enum in_section'). + + ??? This facility should be provided by GCC proper. + The problem is that we want to temporarily switch sections in + ASM_DECLARE_OBJECT_NAME and then switch back to the original section + afterwards. */ +#define SWITCH_TO_SECTION_FUNCTION \ +void \ +switch_to_section (section, decl) \ + enum in_section section; \ + tree decl; \ +{ \ + switch (section) \ + { \ + case in_text: text_section (); break; \ + case in_data: data_section (); break; \ + case in_named: named_section (decl, NULL, 0); break; \ + case in_rdata: rdata_section (); break; \ + case in_ctors: ctors_section (); break; \ + case in_dtors: dtors_section (); break; \ + case in_drectve: drectve_section (); break; \ + default: abort (); break; \ + } \ +} + + + +extern int thumb_pe_valid_machine_decl_attribute (); diff --git a/gcc/configure b/gcc/configure index 90b43098d62..7b010b5ab09 100755 --- a/gcc/configure +++ b/gcc/configure @@ -4175,6 +4175,16 @@ for machine in $build $host $target; do md_file=arm/thumb.md tmake_file=arm/t-thumb ;; + # CYGNUS LOCAL thumb-pe/nickc + thumb-*-pe) + tm_file=arm/tpe.h + out_file=arm/thumb.c + xm_file=arm/xm-thumb.h + md_file=arm/thumb.md + tmake_file=arm/t-pe-thumb + extra_objs=pe.o + ;; + # END CYGNUS LOCAL # This hasn't been upgraded to GCC 2. # tron-*-*) # cpu_type=gmicro diff --git a/gcc/configure.in b/gcc/configure.in index 0a0fc4100f1..70a13735fbf 100644 --- a/gcc/configure.in +++ b/gcc/configure.in @@ -2492,6 +2492,16 @@ for machine in $build $host $target; do md_file=arm/thumb.md tmake_file=arm/t-thumb ;; + # CYGNUS LOCAL thumb-pe/nickc + thumb-*-pe) + tm_file=arm/tpe.h + out_file=arm/thumb.c + xm_file=arm/xm-thumb.h + md_file=arm/thumb.md + tmake_file=arm/t-pe-thumb + extra_objs=pe.o + ;; + # END CYGNUS LOCAL # This hasn't been upgraded to GCC 2. # tron-*-*) # cpu_type=gmicro |