diff options
Diffstat (limited to 'contrib/gcc/config/i386/winnt.c')
-rw-r--r-- | contrib/gcc/config/i386/winnt.c | 297 |
1 files changed, 187 insertions, 110 deletions
diff --git a/contrib/gcc/config/i386/winnt.c b/contrib/gcc/config/i386/winnt.c index 24d8617f8dfa..9d955df2f48e 100644 --- a/contrib/gcc/config/i386/winnt.c +++ b/contrib/gcc/config/i386/winnt.c @@ -1,6 +1,6 @@ /* Subroutines for insn-output.c for Windows NT. Contributed by Douglas Rupp (drupp@cs.washington.edu) - Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -27,6 +27,9 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "tree.h" #include "flags.h" +#include "tm_p.h" +#include "toplev.h" +#include "hashtab.h" /* i386/PE specific attribute support. @@ -39,102 +42,61 @@ Boston, MA 02111-1307, USA. */ 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. */ +static tree associated_type PARAMS ((tree)); +const char * gen_stdcall_suffix PARAMS ((tree)); +int i386_pe_dllexport_p PARAMS ((tree)); +int i386_pe_dllimport_p PARAMS ((tree)); +void i386_pe_mark_dllexport PARAMS ((tree)); +void i386_pe_mark_dllimport PARAMS ((tree)); -int -i386_pe_valid_decl_attribute_p (decl, attributes, attr, args) - tree decl; - tree attributes; - tree attr; - tree args; -{ - if (args == NULL_TREE) - { - if (is_attribute_p ("dllexport", attr)) - return 1; - if (is_attribute_p ("dllimport", attr)) - return 1; - } - - return i386_valid_decl_attribute_p (decl, attributes, attr, args); -} - -/* Return nonzero if ATTR is a valid attribute for TYPE. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. */ - -int -i386_pe_valid_type_attribute_p (type, attributes, attr, args) - tree type; - tree attributes; - tree attr; +/* Handle a "dllimport" or "dllexport" attribute; + arguments as in struct attribute_spec.handler. */ +tree +ix86_handle_dll_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; tree args; + int flags; + bool *no_add_attrs; { - if (args == NULL_TREE - && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE)) + /* These attributes may apply to structure and union types being created, + but otherwise should pass to the declaration involved. */ + if (!DECL_P (*node)) { - if (is_attribute_p ("dllexport", attr)) - return 1; - if (is_attribute_p ("dllimport", attr)) - return 1; + if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_ARRAY_NEXT)) + { + *no_add_attrs = true; + return tree_cons (name, args, NULL_TREE); + } + if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE) + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } } - return i386_valid_type_attribute_p (type, attributes, attr, args); + return NULL_TREE; } -/* 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. */ - +/* Handle a "shared" attribute; + arguments as in struct attribute_spec.handler. */ tree -i386_pe_merge_decl_attributes (old, new) - tree old, new; +ix86_handle_shared_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; { - 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) + if (TREE_CODE (*node) != VAR_DECL) { - 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; - } - } + warning ("`%s' attribute only applies to variables", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - return a; + return NULL_TREE; } /* Return the type that we should use to determine if DECL is @@ -173,7 +135,7 @@ i386_pe_dllexport_p (decl) if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return 0; - exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)); + exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)); if (exp) return 1; @@ -204,7 +166,7 @@ i386_pe_dllimport_p (decl) if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return 0; - imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)); + imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)); if (imp) return 1; @@ -224,7 +186,7 @@ i386_pe_dllimport_p (decl) int i386_pe_dllexport_name_p (symbol) - char *symbol; + const char *symbol; { return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.'; } @@ -233,7 +195,7 @@ i386_pe_dllexport_name_p (symbol) int i386_pe_dllimport_name_p (symbol) - char *symbol; + const char *symbol; { return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.'; } @@ -245,7 +207,8 @@ void i386_pe_mark_dllexport (decl) tree decl; { - char *oldname, *newname; + const char *oldname; + char *newname; rtx rtlname; tree idp; @@ -281,7 +244,8 @@ void i386_pe_mark_dllimport (decl) tree decl; { - char *oldname, *newname; + const char *oldname; + char *newname; tree idp; rtx rtlname, newrtl; @@ -295,7 +259,7 @@ i386_pe_mark_dllimport (decl) abort (); if (i386_pe_dllexport_name_p (oldname)) { - error ("`%s' declared as both exported to and imported from a DLL.", + error ("`%s' declared as both exported to and imported from a DLL", IDENTIFIER_POINTER (DECL_NAME (decl))); return; } @@ -368,14 +332,14 @@ i386_pe_mark_dllimport (decl) suffix consisting of an atsign (@) followed by the number of bytes of arguments */ -char * +const char * gen_stdcall_suffix (decl) tree decl; { int total = 0; /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead of DECL_ASSEMBLER_NAME. */ - char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); char *newsym; if (TYPE_ARG_TYPES (TREE_TYPE (decl))) @@ -442,7 +406,7 @@ i386_pe_encode_section_info (decl) && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0))) { - char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0); + const 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)); @@ -463,7 +427,8 @@ i386_pe_unique_section (decl, reloc) int reloc; { int len; - char *name,*string,*prefix; + const char *name, *prefix; + char *string; name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); /* Strip off any encoding in fnname. */ @@ -477,6 +442,9 @@ i386_pe_unique_section (decl, reloc) without a .rdata section. */ if (TREE_CODE (decl) == FUNCTION_DECL) prefix = ".text$"; +/* else if (DECL_INITIAL (decl) == 0 + || DECL_INITIAL (decl) == error_mark_node) + prefix = ".bss"; */ else if (DECL_READONLY_SECTION (decl, reloc)) #ifdef READONLY_DATA_SECTION prefix = ".rdata$"; @@ -491,6 +459,98 @@ i386_pe_unique_section (decl, reloc) DECL_SECTION_NAME (decl) = build_string (len, string); } + +/* Select a set of attributes for section NAME based on the properties + of DECL and whether or not RELOC indicates that DECL's initializer + might contain runtime relocations. + + We make the section read-only and executable for a function decl, + read-only for a const data decl, and writable for a non-const data decl. + + If the section has already been defined, to not allow it to have + different attributes, as (1) this is ambiguous since we're not seeing + all the declarations up front and (2) some assemblers (e.g. SVR4) + do not recoginize section redefinitions. */ +/* ??? This differs from the "standard" PE implementation in that we + handle the SHARED variable attribute. Should this be done for all + PE targets? */ + +#define SECTION_PE_SHARED SECTION_MACH_DEP + +unsigned int +i386_pe_section_type_flags (decl, name, reloc) + tree decl; + const char *name; + int reloc; +{ + static htab_t htab; + unsigned int flags; + unsigned int **slot; + + /* The names we put in the hashtable will always be the unique + versions gived to us by the stringtable, so we can just use + their addresses as the keys. */ + if (!htab) + htab = htab_create (31, htab_hash_pointer, htab_eq_pointer, NULL); + + if (decl && TREE_CODE (decl) == FUNCTION_DECL) + flags = SECTION_CODE; + else if (decl && DECL_READONLY_SECTION (decl, reloc)) + flags = 0; + else + { + flags = SECTION_WRITE; + + if (decl && TREE_CODE (decl) == VAR_DECL + && lookup_attribute ("shared", DECL_ATTRIBUTES (decl))) + flags |= SECTION_PE_SHARED; + } + + if (decl && DECL_ONE_ONLY (decl)) + flags |= SECTION_LINKONCE; + + /* See if we already have an entry for this section. */ + slot = (unsigned int **) htab_find_slot (htab, name, INSERT); + if (!*slot) + { + *slot = (unsigned int *) xmalloc (sizeof (unsigned int)); + **slot = flags; + } + else + { + if (decl && **slot != flags) + error_with_decl (decl, "%s causes a section type conflict"); + } + + return flags; +} + +void +i386_pe_asm_named_section (name, flags) + const char *name; + unsigned int flags; +{ + char flagchars[8], *f = flagchars; + + if (flags & SECTION_CODE) + *f++ = 'x'; + if (flags & SECTION_WRITE) + *f++ = 'w'; + if (flags & SECTION_PE_SHARED) + *f++ = 's'; + *f = '\0'; + + fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars); + + if (flags & SECTION_LINKONCE) + { + /* Functions may have been compiled at various levels of + optimization so we can't use `same_size' here. + Instead, have the linker pick one. */ + fprintf (asm_out_file, "\t.linkonce %s\n", + (flags & SECTION_CODE ? "discard" : "same_size")); + } +} /* The Microsoft linker requires that every function be marked as DT_FCN. When using gas on cygwin, we must emit appropriate .type @@ -507,7 +567,7 @@ i386_pe_unique_section (decl, reloc) void i386_pe_declare_function_type (file, name, public) FILE *file; - char *name; + const char *name; int public; { fprintf (file, "\t.def\t"); @@ -522,7 +582,7 @@ i386_pe_declare_function_type (file, name, public) struct extern_list { struct extern_list *next; - char *name; + const char *name; }; static struct extern_list *extern_head; @@ -535,7 +595,7 @@ static struct extern_list *extern_head; void i386_pe_record_external_function (name) - char *name; + const char *name; { struct extern_list *p; @@ -545,7 +605,16 @@ i386_pe_record_external_function (name) extern_head = p; } -static struct extern_list *exports_head; +/* Keep a list of exported symbols. */ + +struct export_list +{ + struct export_list *next; + const char *name; + int is_data; /* used to type tag exported symbols. */ +}; + +static struct export_list *export_head; /* Assemble an export symbol entry. We need to keep a list of these, so that we can output the export list at the end of the @@ -554,15 +623,17 @@ static struct extern_list *exports_head; linkonce. */ void -i386_pe_record_exported_symbol (name) - char *name; +i386_pe_record_exported_symbol (name, is_data) + const char *name; + int is_data; { - struct extern_list *p; + struct export_list *p; - p = (struct extern_list *) permalloc (sizeof *p); - p->next = exports_head; + p = (struct export_list *) permalloc (sizeof *p); + p->next = export_head; p->name = name; - exports_head = p; + p->is_data = is_data; + export_head = p; } /* This is called at the end of assembly. For each external function @@ -575,6 +646,8 @@ i386_pe_asm_file_end (file) { struct extern_list *p; + ix86_asm_file_end (file); + for (p = extern_head; p != NULL; p = p->next) { tree decl; @@ -589,12 +662,16 @@ i386_pe_asm_file_end (file) } } - if (exports_head) - drectve_section (); - for (p = exports_head; p != NULL; p = p->next) + if (export_head) { - fprintf (file, "\t.ascii \" -export:%s\"\n", - I386_PE_STRIP_ENCODING (p->name)); + struct export_list *q; + drectve_section (); + for (q = export_head; q != NULL; q = q->next) + { + fprintf (file, "\t.ascii \" -export:%s%s\"\n", + I386_PE_STRIP_ENCODING (q->name), + (q->is_data) ? ",data" : ""); + } } } |