Add thumb-pe support.

Add super interworking.

From-SVN: r18935
This commit is contained in:
Nick Clifton 1998-04-01 17:19:01 +00:00 committed by Nick Clifton
parent 7c76b292a2
commit 75d3a15b4d
15 changed files with 1510 additions and 156 deletions

View file

@ -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/.

4
gcc/config.sub vendored
View file

@ -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.

View file

@ -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}

View file

@ -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 */

View file

@ -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)
.macro call_via register
.globl SYM (_call_via_\register)
.thumb_func
SYM (_call_via_r1):
bx r1
SYM (_call_via_\register):
bx \register
nop
.endm
.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)
.thumb_func
SYM (_call_via_r7):
bx r7
nop
.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
.globl SYM (_call_via_ip)
.thumb_func
SYM (_call_via_ip):
bx ip
nop
.globl SYM (_call_via_sp)
.thumb_func
SYM (_call_via_sp):
bx sp
nop
.globl SYM (_call_via_lr)
.thumb_func
SYM (_call_via_lr):
bx lr
nop
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
.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
.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 */

31
gcc/config/arm/t-pe Normal file
View file

@ -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

37
gcc/config/arm/t-pe-thumb Normal file
View file

@ -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

View file

@ -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 =

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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"))

420
gcc/config/arm/tpe.h Normal file
View file

@ -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 ();

10
gcc/configure vendored
View file

@ -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

View file

@ -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