diff options
author | Nick Clifton <nickc@cygnus.com> | 1999-07-01 01:18:36 +0000 |
---|---|---|
committer | Nick Clifton <nickc@gcc.gnu.org> | 1999-07-01 01:18:36 +0000 |
commit | cb805c2ddff216a64ea3a57e03d3a30b76c06c89 (patch) | |
tree | 4d8a64c7c1a483849032bb7d9b656f996c94ec39 /gcc | |
parent | 5e13e04f6ab20f5e347c74f4bb3812b42a9db8f8 (diff) | |
download | gcc-cb805c2ddff216a64ea3a57e03d3a30b76c06c89.zip gcc-cb805c2ddff216a64ea3a57e03d3a30b76c06c89.tar.gz gcc-cb805c2ddff216a64ea3a57e03d3a30b76c06c89.tar.bz2 |
Add support for arm-pe and thumb-pe
From-SVN: r27871
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/config/arm/pe.c | 501 | ||||
-rw-r--r-- | gcc/config/arm/pe.h | 296 | ||||
-rw-r--r-- | gcc/config/arm/t-pe-thumb | 36 | ||||
-rw-r--r-- | gcc/config/arm/thumb.c | 87 | ||||
-rw-r--r-- | gcc/config/arm/tpe.h | 425 | ||||
-rwxr-xr-x | gcc/configure | 13 | ||||
-rw-r--r-- | gcc/configure.in | 13 |
8 files changed, 1396 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 97a1675..c971886 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +Wed Jun 30 16:51:41 1999 Nick Clifton <nickc@cygnus.com> + + * configure.in: Add arm-pe and thumb-pe targets. + * configure: Regenerate. + + * thumb.c (arm_naked_function_p): New function: Determines if + a function is naked (has no gcc generated prologue/epilogue). + (is_called_in_ARM_mode): Return true if the func has the + interfacearm attribute. + (output_return): Do not generate a return for naked functions. + (thumb_function_prologue): Do not generate a prologue for + naked functions. + (thumb_expand_prologue): Do not generate a prologue for naked + functions. + (thumb_expand_epilogue): Do not generate an epilogue for naked + functions. + (arm_valid_machine_decl_attribute): New function, copied from + arm.c: Permit naked and interfacearm attributes. + + * config/arm/pe.c: New file: Support code for arm-pe target. + * config/arm/pe.h: New file: Header file for arm-pe target. + * config/arm/tpe.h: New file: Header file for thumb-pe target. + * config/arm/t-thumb-pe: New file: Makefile fragment for + thumb-pe target. + 1999-07-01 Mark Kettenis <kettenis@gnu.org> * config/i386/gnu.h (CPP_SPEC): Define __PIC__ and __pic__ if diff --git a/gcc/config/arm/pe.c b/gcc/config/arm/pe.c new file mode 100644 index 0000000..60d6c4b --- /dev/null +++ b/gcc/config/arm/pe.c @@ -0,0 +1,501 @@ +/* Routines for GCC for ARM/pe. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Contributed by Doug Evans (dje@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 <stdio.h> +#include <string.h> +#include "config.h" +#include "rtl.h" +#include "output.h" +#include "flags.h" +#include "tree.h" +#include "expr.h" + +extern int current_function_anonymous_args; + +/* ARM/PE specific attribute support. + + ARM/PE has three new attributes: + naked - for interrupt functions + dllexport - for exporting a function/variable that will live in a dll + dllimport - for importing a function/variable from a dll + + Microsoft allows multiple declspecs in one __declspec, separating + them with spaces. We do NOT support this. Instead, use __declspec + multiple times. +*/ + +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. */ + +int +arm_pe_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 ("dllexport", attr)) + return 1; + if (is_attribute_p ("dllimport", attr)) + return 1; + + return arm_valid_machine_decl_attribute (decl, attr, args); +} + +/* Merge attributes in decls OLD and NEW. + + This handles the following situation: + + __declspec (dllimport) int foo; + int foo; + + The second instance of `foo' nullifies the dllimport. */ + +tree +arm_pe_merge_machine_decl_attributes (old, new) + tree old, new; +{ + tree a; + int delete_dllimport_p; + + old = DECL_MACHINE_ATTRIBUTES (old); + new = DECL_MACHINE_ATTRIBUTES (new); + + /* What we need to do here is remove from `old' dllimport if it doesn't + appear in `new'. dllimport behaves like extern: if a declaration is + marked dllimport and a definition appears later, then the object + is not dllimport'd. */ + + if (lookup_attribute ("dllimport", old) != NULL_TREE + && lookup_attribute ("dllimport", new) == NULL_TREE) + delete_dllimport_p = 1; + else + delete_dllimport_p = 0; + + a = merge_attributes (old, new); + + if (delete_dllimport_p) + { + tree prev,t; + + /* Scan the list for dllimport and delete it. */ + for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t)) + { + if (is_attribute_p ("dllimport", TREE_PURPOSE (t))) + { + if (prev == NULL_TREE) + a = TREE_CHAIN (a); + else + TREE_CHAIN (prev) = TREE_CHAIN (t); + break; + } + } + } + + return a; +} + +/* Check a type that has a virtual table, and see if any virtual methods are + marked for import or export, and if so, arrange for the vtable to + be imported or exported. */ + +static int +arm_check_vtable_importexport (type) + tree type; +{ + tree methods = TYPE_METHODS (type); + tree fndecl; + + if (TREE_CODE (methods) == FUNCTION_DECL) + fndecl = methods; + else if (TREE_VEC_ELT (methods, 0) != NULL_TREE) + fndecl = TREE_VEC_ELT (methods, 0); + else + fndecl = TREE_VEC_ELT (methods, 1); + + while (fndecl) + { + if (DECL_VIRTUAL_P (fndecl) || DECL_VINDEX (fndecl) != NULL_TREE) + { + tree exp = lookup_attribute ("dllimport", + DECL_MACHINE_ATTRIBUTES (fndecl)); + if (exp == 0) + exp = lookup_attribute ("dllexport", + DECL_MACHINE_ATTRIBUTES (fndecl)); + if (exp) + return 1; + } + + fndecl = TREE_CHAIN (fndecl); + } + + return 0; +} + +/* Return non-zero if DECL is a dllexport'd object. */ + +tree current_class_type; /* FIXME */ + +int +arm_dllexport_p (decl) + tree decl; +{ + tree exp; + + if (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FUNCTION_DECL) + return 0; + exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)); + if (exp) + return 1; + +#if 0 /* This was a hack to get vtable's exported or imported since only one + copy of them is ever output. Disabled pending better solution. */ + /* For C++, the vtables might have to be marked. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl)) + { + if (TREE_PUBLIC (decl) + && DECL_EXTERNAL (decl) == 0 + && (DECL_CONTEXT (decl) + ? arm_check_vtable_importexport (DECL_CONTEXT (decl)) + : current_class_type + ? arm_check_vtable_importexport (current_class_type) + : 0) + ) + return 1; + } +#endif + + return 0; +} + +/* Return non-zero if DECL is a dllimport'd object. */ + +int +arm_dllimport_p (decl) + tree decl; +{ + tree imp; + + if (TREE_CODE (decl) == FUNCTION_DECL + && TARGET_NOP_FUN_DLLIMPORT) + return 0; + + if (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FUNCTION_DECL) + return 0; + imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)); + if (imp) + return 1; + +#if 0 /* This was a hack to get vtable's exported or imported since only one + copy of them is ever output. Disabled pending better solution. */ + /* For C++, the vtables might have to be marked. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl)) + { + if (TREE_PUBLIC (decl) + && DECL_EXTERNAL (decl) + && (DECL_CONTEXT (decl) + ? arm_check_vtable_importexport (DECL_CONTEXT (decl)) + : current_class_type + ? arm_check_vtable_importexport (current_class_type) + : 0) + ) + return 1; + } +#endif + + return 0; +} + +/* Return non-zero if SYMBOL is marked as being dllexport'd. */ + +int +arm_dllexport_name_p (symbol) + char * symbol; +{ + return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.'; +} + +/* Return non-zero if SYMBOL is marked as being dllimport'd. */ + +int +arm_dllimport_name_p (symbol) + char * symbol; +{ + return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.'; +} + +/* Mark a DECL as being dllexport'd. + Note that we override the previous setting (eg: dllimport). */ + +void +arm_mark_dllexport (decl) + tree decl; +{ + char * oldname; + char * newname; + rtx rtlname; + tree idp; + + rtlname = XEXP (DECL_RTL (decl), 0); + if (GET_CODE (rtlname) == SYMBOL_REF) + oldname = XSTR (rtlname, 0); + else if (GET_CODE (rtlname) == MEM + && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) + oldname = XSTR (XEXP (rtlname, 0), 0); + else + abort (); + if (arm_dllimport_name_p (oldname)) + oldname += 9; + else if (arm_dllexport_name_p (oldname)) + return; /* already done */ + + newname = alloca (strlen (oldname) + 4); + sprintf (newname, "@e.%s", oldname); + + /* We pass newname through get_identifier to ensure it has a unique + address. RTL processing can sometimes peek inside the symbol ref + and compare the string's addresses to see if two symbols are + identical. */ + /* ??? At least I think that's why we do this. */ + idp = get_identifier (newname); + + XEXP (DECL_RTL (decl), 0) = + gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp)); +} + +/* Mark a DECL as being dllimport'd. */ + +void +arm_mark_dllimport (decl) + tree decl; +{ + char * oldname; + char * newname; + tree idp; + rtx rtlname, newrtl; + + rtlname = XEXP (DECL_RTL (decl), 0); + + if (GET_CODE (rtlname) == SYMBOL_REF) + oldname = XSTR (rtlname, 0); + else if (GET_CODE (rtlname) == MEM + && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) + oldname = XSTR (XEXP (rtlname, 0), 0); + else + abort (); + + if (arm_dllexport_name_p (oldname)) + abort (); /* this shouldn't happen */ + else if (arm_dllimport_name_p (oldname)) + return; /* already done */ + + /* ??? One can well ask why we're making these checks here, + and that would be a good question. */ + + /* Imported variables can't be initialized. */ + if (TREE_CODE (decl) == VAR_DECL + && !DECL_VIRTUAL_P (decl) + && DECL_INITIAL (decl)) + { + error_with_decl (decl, "initialized variable `%s' is marked dllimport"); + return; + } + /* Nor can they be static. */ + if (TREE_CODE (decl) == VAR_DECL + /* ??? Is this test for vtables needed? */ + && !DECL_VIRTUAL_P (decl) + && 0 /*???*/) + { + error_with_decl (decl, "static variable `%s' is marked dllimport"); + return; + } + + /* `extern' needn't be specified with dllimport. + Specify `extern' now and hope for the best. Sigh. */ + if (TREE_CODE (decl) == VAR_DECL + /* ??? Is this test for vtables needed? */ + && !DECL_VIRTUAL_P (decl)) + { + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + } + + newname = alloca (strlen (oldname) + 11); + sprintf (newname, "@i.__imp_%s", oldname); + + /* We pass newname through get_identifier to ensure it has a unique + address. RTL processing can sometimes peek inside the symbol ref + and compare the string's addresses to see if two symbols are + identical. */ + /* ??? At least I think that's why we do this. */ + idp = get_identifier (newname); + + newrtl = gen_rtx (MEM, Pmode, + gen_rtx (SYMBOL_REF, Pmode, + IDENTIFIER_POINTER (idp))); + XEXP (DECL_RTL (decl), 0) = newrtl; +} + +/* Cover function to implement ENCODE_SECTION_INFO. */ + +void +arm_pe_encode_section_info (decl) + tree decl; +{ + /* This bit is copied from arm.h. */ + if (optimize > 0 && TREE_CONSTANT (decl) + && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) + { + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' + ? TREE_CST_RTL (decl) : DECL_RTL (decl)); + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; + } + + /* Mark the decl so we can tell from the rtl whether the object is + dllexport'd or dllimport'd. */ + if (arm_dllexport_p (decl)) + arm_mark_dllexport (decl); + else if (arm_dllimport_p (decl)) + arm_mark_dllimport (decl); + /* It might be that DECL has already been marked as dllimport, but a + subsequent definition nullified that. The attribute is gone but + DECL_RTL still has @i.__imp_foo. We need to remove that. */ + else if ((TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == VAR_DECL) + && DECL_RTL (decl) != NULL_RTX + && GET_CODE (DECL_RTL (decl)) == MEM + && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM + && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF + && arm_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0))) + { + char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0); + tree idp = get_identifier (oldname + 9); + rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp)); + + XEXP (DECL_RTL (decl), 0) = newrtl; + + /* We previously set TREE_PUBLIC and DECL_EXTERNAL. + ??? We leave these alone for now. */ + } +} + +/* Cover function for UNIQUE_SECTION. */ + +void +arm_pe_unique_section (decl, reloc) + tree decl; + int reloc; +{ + int len; + char * name; + char * string; + char * prefix; + + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + /* Strip off any encoding in fnname. */ + STRIP_NAME_ENCODING (name, name); + + /* The object is put in, for example, section .text$foo. + The linker will then ultimately place them in .text + (everything from the $ on is stripped). */ + if (TREE_CODE (decl) == FUNCTION_DECL) + prefix = ".text$"; + else if (DECL_READONLY_SECTION (decl, reloc)) + prefix = ".rdata$"; + else + prefix = ".data$"; + len = strlen (name) + strlen (prefix); + string = alloca (len + 1); + sprintf (string, "%s%s", prefix, name); + + DECL_SECTION_NAME (decl) = build_string (len, string); +} + +/* This is to better conform to the ARM PCS. + Richard Earnshaw hasn't put this into FSF sources yet so it's here. */ + +int +arm_pe_return_in_memory (type) + tree type; +{ + if (TREE_CODE (type) == RECORD_TYPE) + { + tree field; + int num_fields = 0; + + /* For a record containing just a single element, we can be a little + less restrictive. */ + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL && ! TREE_STATIC (field)) + { + if ((AGGREGATE_TYPE_P (TREE_TYPE (field)) + && RETURN_IN_MEMORY (TREE_TYPE (field))) + || FLOAT_TYPE_P (TREE_TYPE (field))) + return 1; + num_fields++; + } + } + + if (num_fields == 1) + return 0; + + /* For a struct, we can return in a register if every element was a + bit-field and it all fits in one word. */ + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL + && ! TREE_STATIC (field) + && (! DECL_BIT_FIELD_TYPE (field) + || (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)) + + TREE_INT_CST_LOW (DECL_SIZE (field))) > 32)) + return 1; + } + return 0; + } + else if (TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + { + tree field; + + /* Unions can be returned in registers if every element is + integral, or can be returned in an integer register. */ + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL + && ! TREE_STATIC (field) + && ((AGGREGATE_TYPE_P (TREE_TYPE (field)) + && RETURN_IN_MEMORY (TREE_TYPE (field))) + || FLOAT_TYPE_P (TREE_TYPE (field)))) + return 1; + } + return 0; + } + /* XXX Not sure what should be done for other aggregates, so put them in + memory. */ + return 1; +} diff --git a/gcc/config/arm/pe.h b/gcc/config/arm/pe.h new file mode 100644 index 0000000..18281cd --- /dev/null +++ b/gcc/config/arm/pe.h @@ -0,0 +1,296 @@ +/* Definitions of target machine for GNU compiler, for ARM with PE obj format. + Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc. + Contributed by Doug Evans (dje@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/coff.h" + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (ARM/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 "\ +-Darm -D__pe__ -Acpu(arm) -Amachine(arm) \ +-D__declspec(x)=__attribute__((x)) \ +" + +/* Experimental addition for pr 7885. + Ignore dllimport for functions. */ +#define TARGET_NOP_FUN_DLLIMPORT (target_flags & 0x20000) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ +{ "nop-fun-dllimport", 0x20000, "Ignore dllimport attribute for functions" }, \ +{ "no-nop-fun-dllimport", -0x20000, "" }, + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT + 0x20000) + +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +/* Same as arm.h except r10 is call-saved, not fixed. */ +#undef FIXED_REGISTERS +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,1,0,1,0,1, \ + 0,0,0,0,0,0,0,0, \ + 1,1,1 \ +} + +/* Same as arm.h except r10 is call-saved, not fixed. */ +#undef CALL_USED_REGISTERS +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1,0,0,0,0, \ + 0,0,0,1,1,1,1,1, \ + 1,1,1,1,0,0,0,0, \ + 1,1,1 \ +} + +/* 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 (); +#undef VALID_MACHINE_DECL_ATTRIBUTE +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +arm_pe_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +#if 0 /* Needed when we tried type attributes. */ +/* A C expression whose value is zero if the attributes on + TYPE1 and TYPE2 are incompatible, one if they are compatible, + and two if they are nearly compatible (which causes a warning to be + generated). */ +extern int arm_pe_comp_type_attributes (); +#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \ +arm_pe_comp_type_attributes ((TYPE1), (TYPE2)) +#endif + +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) + +/* Used to implement dllexport overriding dllimport semantics. It's also used + to handle vtables - the first pass won't do anything because + DECL_CONTEXT (DECL) will be 0 so arm_dll{ex,im}port_p will return 0. + It's also used to handle dllimport override semantics. */ +#if 0 +#define REDO_SECTION_INFO_P(DECL) \ +((DECL_MACHINE_ATTRIBUTES (DECL) != NULL_TREE) \ + || (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL))) +#else +#define REDO_SECTION_INFO_P(DECL) 1 +#endif + +/* 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 (TARGET_POKE_FUNCTION_NAME) \ + arm_poke_function_name ((STREAM), (NAME)); \ + 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; \ + } \ +} diff --git a/gcc/config/arm/t-pe-thumb b/gcc/config/arm/t-pe-thumb new file mode 100644 index 0000000..c75930c --- /dev/null +++ b/gcc/config/arm/t-pe-thumb @@ -0,0 +1,36 @@ +# Makefile fragment +# Copyright (c) 1998 Free Software Foundation + +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/thumb.c b/gcc/config/arm/thumb.c index 43082bb..9048a34 100644 --- a/gcc/config/arm/thumb.c +++ b/gcc/config/arm/thumb.c @@ -398,6 +398,7 @@ thumb_reorg (first) rtx first; { rtx insn; + for (insn = first; insn; insn = NEXT_INSN (insn)) { if (broken_move (insn)) @@ -540,6 +541,24 @@ thumb_reload_out_si (operands) abort (); } + +#ifdef 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 + /* Return non-zero if FUNC must be entered in ARM mode. */ int is_called_in_ARM_mode (func) @@ -552,7 +571,11 @@ is_called_in_ARM_mode (func) 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 } @@ -968,6 +991,12 @@ output_return () int regno; int live_regs_mask = 0; +#ifdef THUMB_PE + /* If a function is naked, don't use the "return" insn. */ + if (arm_naked_function_p (current_function_decl)) + return ""; +#endif + return_used_this_function = 1; for (regno = 0; regno < 8; regno++) @@ -1026,9 +1055,15 @@ thumb_function_prologue (f, frame_size) int store_arg_regs = 0; int regno; +#ifdef THUMB_PE + if (arm_naked_function_p (current_function_decl)) + return; +#endif + 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) @@ -1051,6 +1086,12 @@ thumb_function_prologue (f, frame_size) #define STUB_NAME ".real_start_of" asm_fprintf (f, "\t.code\t16\n"); + +#ifdef THUMB_PE + if (arm_dllexport_name_p (name)) + name = ARM_STRIP_NAME_ENCODING (name); +#endif + 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); @@ -1234,6 +1275,12 @@ thumb_expand_prologue () int regno; int live_regs_mask; +#ifdef THUMB_PE + /* Naked functions don't have prologues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + if (amount) { live_regs_mask = 0; @@ -1297,6 +1344,12 @@ thumb_expand_epilogue () + current_function_outgoing_args_size); int regno; +#ifdef THUMB_PE + /* Naked functions don't have epilogues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + if (amount) { if (amount < 512) @@ -1991,3 +2044,37 @@ thumb_override_options () flag_pic = 0; } } + +#ifdef 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, attr, args) + tree decl; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("naked", attr)) + if (TREE_CODE (decl) == FUNCTION_DECL) + return 1; + + if (is_attribute_p ("interfacearm", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + return 0; +} +#endif /* THUMB_PE */ + diff --git a/gcc/config/arm/tpe.h b/gcc/config/arm/tpe.h new file mode 100644 index 0000000..50e33a0 --- /dev/null +++ b/gcc/config/arm/tpe.h @@ -0,0 +1,425 @@ +/* Definitions of target machine for GNU compiler, + for Thumb with PE object format. + Copyright (C) 1998, 1999 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, "Ignore dllimport attribute for functions" }, \ +{ "no-nop-fun-dllimport", -ARM_FLAG_NOP_FUN_IMPORT, "" }, + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT ARM_FLAG_NOP_FUN_IMPORT + +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +/* 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 1 + +#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 (); +#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) + +#define REDO_SECTION_INFO_P(DECL) 1 + + /* 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 edfc670..6d406f4 100755 --- a/gcc/configure +++ b/gcc/configure @@ -3215,6 +3215,11 @@ for machine in $build $host $target; do tm_file=arm/unknown-elf-oabi.h tmake_file=arm/t-arm-elf ;; + arm-*-pe*) + tm_file=arm/pe.h + tmake_file=arm/t-pe + extra_objs=pe.o + ;; c1-convex-*) # Convex C1 target_cpu_default=1 use_collect2=yes @@ -5578,6 +5583,14 @@ for machine in $build $host $target; do tmake_file=arm/t-thumb thread_file='vxworks' ;; + 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 + ;; # This hasn't been upgraded to GCC 2. # tron-*-*) # cpu_type=gmicro diff --git a/gcc/configure.in b/gcc/configure.in index c74469c..5c2a631 100644 --- a/gcc/configure.in +++ b/gcc/configure.in @@ -788,6 +788,11 @@ changequote([,])dnl tm_file=arm/unknown-elf-oabi.h tmake_file=arm/t-arm-elf ;; + arm-*-pe*) + tm_file=arm/pe.h + tmake_file=arm/t-pe + extra_objs=pe.o + ;; c1-convex-*) # Convex C1 target_cpu_default=1 use_collect2=yes @@ -3275,6 +3280,14 @@ changequote([,])dnl tmake_file=arm/t-thumb thread_file='vxworks' ;; + 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 + ;; # This hasn't been upgraded to GCC 2. # tron-*-*) # cpu_type=gmicro |