summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog17
-rwxr-xr-xgcc/config.sub4
-rw-r--r--gcc/config/arm/README-interworking553
-rw-r--r--gcc/config/arm/lib1funcs.asm117
-rw-r--r--gcc/config/arm/lib1thumb.asm159
-rw-r--r--gcc/config/arm/t-pe31
-rw-r--r--gcc/config/arm/t-pe-thumb37
-rw-r--r--gcc/config/arm/t-semi2
-rw-r--r--gcc/config/arm/t-thumb2
-rw-r--r--gcc/config/arm/thumb.c183
-rw-r--r--gcc/config/arm/thumb.h86
-rw-r--r--gcc/config/arm/thumb.md27
-rw-r--r--gcc/config/arm/tpe.h420
-rwxr-xr-xgcc/configure10
-rw-r--r--gcc/configure.in10
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