diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5b568a75b37..dc59fd773b0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,52 @@ +2007-03-29 Richard Henderson + + * varasm.c (initializer_constant_valid_p): Don't deny + DECL_DLLIMPORT_P on functions. + + * config/i386/cygming.h: Remove function declarations. + (SUBTARGET_ENCODE_SECTION_INFO): Don't undef first. + (ASM_OUTPUT_LABELREF): Remove. + (COMMON_ASM_OP): Remove. + (ASM_OUTPUT_COMMON): Remove. + (ASM_OUTPUT_ALIGNED_DECL_COMMON): New. + (ASM_DECLARE_OBJECT_NAME): Use i386_pe_maybe_record_exported_symbol. + (ASM_DECLARE_FUNCTION_NAME): Likewise. + * config/i386/i386-interix.h (SUBTARGET_ENCODE_SECTION_INFO): + Rename from TARGET_ENCODE_SECTION_INFO. + * config/i386/netware.h: Likewise. + * config/i386/i386-protos.h: Update. + * config/i386/i386.c (ix86_function_ok_for_sibcall): Turn ifdef + of TARGET_DLLIMPORT_DECL_ATTRIBUTES into straight if. + (legitimate_constant_p): Reject dllimports. + (dllimport_map, get_dllimport_decl): New. + (legitimize_dllimport_symbol): New. + (legitimize_address, ix86_expand_move): Use it. + (TARGET_BINDS_LOCAL_P): Redefine for TARGET_DLLIMPORT_DECL_ATTRIBUTES. + * config/i386/i386.h (DLL_IMPORT_EXPORT_PREFIX): Remove. + (SYMBOL_FLAG_DLLIMPORT, SYMBOL_REF_DLLIMPORT_P): New. + (SYMBOL_FLAG_DLLEXPORT, SYMBOL_REF_DLLEXPORT_P): New. + * config/i386/predicates.md (constant_call_address_operand): Only + accept symbols; reject dllimport_p symbols. + * config/i386/uwin.h (ASM_DECLARE_FUNCTION_NAME): Use + i386_pe_maybe_record_exported_symbol. + * config/i386/winnt.c (DLL_IMPORT_PREFIX, DLL_EXPORT_PREFIX): Remove. + (i386_pe_determine_dllexport_p): Rename from i386_pe_dllexport_p. + (i386_pe_determine_dllimport_p): Rename from i386_pe_dllimport_p; + trust the setting of DECL_DLLIMPORT_P. + (i386_pe_dllexport_name_p, i386_pe_dllimport_name_p): Remove. + (i386_pe_mark_dllexport, i386_pe_mark_dllimport): Remove. + (gen_stdcall_or_fastcall_suffix): Return NULL if no change required; + tidy the argument scanning loop. + (i386_pe_encode_section_info): Set SYMBOL_FLAG_DLLIMPORT and + SYMBOL_FLAG_DLLEXPORT in SYMBOL_REF_FLAGS. + (i386_pe_strip_name_encoding): Remove. + (i386_pe_binds_local_p): New. + (i386_pe_strip_name_encoding_full): Use default_strip_name_encoding. + (i386_pe_output_labelref): Remove. + (i386_pe_asm_output_aligned_decl_common): New. + (i386_pe_maybe_record_exported_symbol): Rename from + i386_pe_record_exported_symbol; check for dllexported symbols. + 2007-03-29 Zack Weinberg * gengtype.c (oprintf): Mostly revert changes from 2007-03-26; diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h index 9b0cd7f0c79..aa4ca2a925d 100644 --- a/gcc/config/i386/cygming.h +++ b/gcc/config/i386/cygming.h @@ -148,39 +148,20 @@ do { \ 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. */ -#undef SUBTARGET_ENCODE_SECTION_INFO #define SUBTARGET_ENCODE_SECTION_INFO i386_pe_encode_section_info #undef TARGET_STRIP_NAME_ENCODING #define TARGET_STRIP_NAME_ENCODING i386_pe_strip_name_encoding_full - -/* Output a reference to a label. */ -#undef ASM_OUTPUT_LABELREF -#define ASM_OUTPUT_LABELREF i386_pe_output_labelref - -#undef COMMON_ASM_OP -#define COMMON_ASM_OP "\t.comm\t" /* Output a common block. */ -#undef ASM_OUTPUT_COMMON -#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ -do { \ - if (i386_pe_dllexport_name_p (NAME)) \ - i386_pe_record_exported_symbol (NAME, 1); \ - if (! i386_pe_dllimport_name_p (NAME)) \ - { \ - fprintf ((STREAM), "\t.comm\t"); \ - assemble_name ((STREAM), (NAME)); \ - fprintf ((STREAM), ", %d\t%s %d\n", \ - (int)(ROUNDED), ASM_COMMENT_START, (int)(SIZE)); \ - } \ -} while (0) +#undef ASM_OUTPUT_ALIGNED_DECL_COMMON +#define ASM_OUTPUT_ALIGNED_DECL_COMMON \ + i386_pe_asm_output_aligned_decl_common /* Output the label for an initialized variable. */ #undef ASM_DECLARE_OBJECT_NAME #define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ do { \ - if (i386_pe_dllexport_name_p (NAME)) \ - i386_pe_record_exported_symbol (NAME, 1); \ + i386_pe_maybe_record_exported_symbol (DECL, NAME, 1); \ ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ } while (0) @@ -210,7 +191,6 @@ do { \ /* Windows uses explicit import from shared libraries. */ #define MULTIPLE_SYMBOL_SPACES 1 -extern void i386_pe_unique_section (TREE, int); #define TARGET_ASM_UNIQUE_SECTION i386_pe_unique_section #define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section @@ -229,8 +209,7 @@ extern void i386_pe_unique_section (TREE, int); #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ do \ { \ - if (i386_pe_dllexport_name_p (NAME)) \ - i386_pe_record_exported_symbol (NAME, 0); \ + i386_pe_maybe_record_exported_symbol (DECL, NAME, 0); \ if (write_symbols != SDB_DEBUG) \ i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL)); \ ASM_OUTPUT_LABEL (FILE, NAME); \ @@ -289,15 +268,6 @@ extern void i386_pe_unique_section (TREE, int); build_tree_list (get_identifier ("stdcall"), \ NULL)) -/* External function declarations. */ - -extern void i386_pe_record_external_function (tree, const char *); -extern void i386_pe_declare_function_type (FILE *, const char *, int); -extern void i386_pe_record_exported_symbol (const char *, int); -extern void i386_pe_file_end (void); -extern int i386_pe_dllexport_name_p (const char *); -extern int i386_pe_dllimport_name_p (const char *); - /* For Win32 ABI compatibility */ #undef DEFAULT_PCC_STRUCT_RETURN #define DEFAULT_PCC_STRUCT_RETURN 0 @@ -315,10 +285,10 @@ extern int i386_pe_dllimport_name_p (const char *); machine. Use this macro to limit the alignment which can be specified using the `__attribute__ ((aligned (N)))' construct. If not defined, the default value is `BIGGEST_ALIGNMENT'. */ -#undef MAX_OFILE_ALIGNMENT /* IMAGE_SCN_ALIGN_8192BYTES is the largest section alignment flag specified in the PECOFF60 spec. Native MS compiler also limits user-specified alignment to 8192 bytes. */ +#undef MAX_OFILE_ALIGNMENT #define MAX_OFILE_ALIGNMENT (8192 * 8) /* Native complier aligns internal doubles in structures on dword boundaries. */ @@ -334,6 +304,7 @@ extern int i386_pe_dllimport_name_p (const char *); #ifndef SET_ASM_OP #define SET_ASM_OP "\t.set\t" #endif + /* This implements the `alias' attribute, keeping any stdcall or fastcall decoration. */ #undef ASM_OUTPUT_DEF_FROM_DECLS diff --git a/gcc/config/i386/i386-interix.h b/gcc/config/i386/i386-interix.h index 5e9f7dadbc1..fa753767687 100644 --- a/gcc/config/i386/i386-interix.h +++ b/gcc/config/i386/i386-interix.h @@ -326,8 +326,7 @@ while (0) differently depending on something about the variable or function named by the symbol (such as what section it is in). */ -#undef TARGET_ENCODE_SECTION_INFO -#define TARGET_ENCODE_SECTION_INFO i386_pe_encode_section_info +#define SUBTARGET_ENCODE_SECTION_INFO i386_pe_encode_section_info #undef TARGET_STRIP_NAME_ENCODING #define TARGET_STRIP_NAME_ENCODING i386_pe_strip_name_encoding_full diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index aad472439bd..a37901156c7 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -191,9 +191,6 @@ extern int ix86_local_alignment (tree, int); extern int ix86_constant_alignment (tree, int); extern tree ix86_handle_shared_attribute (tree *, tree, tree, int, bool *); extern tree ix86_handle_selectany_attribute (tree *, tree, tree, int, bool *); - -extern unsigned int i386_pe_section_type_flags (tree, const char *, int); -extern void i386_pe_asm_named_section (const char *, unsigned int, tree); extern int x86_field_alignment (tree, int); #endif @@ -206,18 +203,22 @@ extern void ix86_expand_vector_extract (bool, rtx, rtx, int); extern void ix86_expand_reduc_v4sf (rtx (*)(rtx, rtx, rtx), rtx, rtx); /* In winnt.c */ -extern int i386_pe_dllexport_name_p (const char *); -extern int i386_pe_dllimport_name_p (const char *); extern void i386_pe_unique_section (tree, int); extern void i386_pe_declare_function_type (FILE *, const char *, int); extern void i386_pe_record_external_function (tree, const char *); -extern void i386_pe_record_exported_symbol (const char *, int); +extern void i386_pe_maybe_record_exported_symbol (tree, const char *, int); extern void i386_pe_asm_file_end (FILE *); extern void i386_pe_encode_section_info (tree, rtx, int); -extern const char *i386_pe_strip_name_encoding (const char *); +extern bool i386_pe_binds_local_p (tree); extern const char *i386_pe_strip_name_encoding_full (const char *); -extern void i386_pe_output_labelref (FILE *, const char *); extern bool i386_pe_valid_dllimport_attribute_p (tree); +extern unsigned int i386_pe_section_type_flags (tree, const char *, int); +extern void i386_pe_asm_named_section (const char *, unsigned int, tree); +extern void i386_pe_asm_output_aligned_decl_common (FILE *, tree, + const char *, + HOST_WIDE_INT, + HOST_WIDE_INT); +extern void i386_pe_file_end (void); /* In winnt-cxx.c and winnt-stubs.c */ extern void i386_pe_adjust_class_at_definition (tree); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 40ffcc87507..ed25402476a 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -2569,12 +2569,11 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) } } -#if TARGET_DLLIMPORT_DECL_ATTRIBUTES /* Dllimport'd functions are also called indirectly. */ - if (decl && DECL_DLLIMPORT_P (decl) + if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && decl && DECL_DLLIMPORT_P (decl) && ix86_function_regparm (TREE_TYPE (decl), NULL) >= 3) return false; -#endif /* If we forced aligned the stack, then sibcalling would unalign the stack, which may break the called function. */ @@ -6332,6 +6331,11 @@ legitimate_constant_p (rtx x) /* TLS symbols are never valid. */ if (SYMBOL_REF_TLS_MODEL (x)) return false; + + /* DLLIMPORT symbols are never valid. */ + if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && SYMBOL_REF_DLLIMPORT_P (x)) + return false; break; case CONST_DOUBLE: @@ -7189,6 +7193,90 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) return dest; } +/* Create or return the unique __imp_DECL dllimport symbol corresponding + to symbol DECL. */ + +static GTY((if_marked ("tree_map_marked_p"), param_is (struct tree_map))) + htab_t dllimport_map; + +static tree +get_dllimport_decl (tree decl) +{ + struct tree_map *h, in; + void **loc; + const char *name; + const char *prefix; + size_t namelen, prefixlen; + char *imp_name; + tree to; + rtx rtl; + + if (!dllimport_map) + dllimport_map = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0); + + in.hash = htab_hash_pointer (decl); + in.base.from = decl; + loc = htab_find_slot_with_hash (dllimport_map, &in, in.hash, INSERT); + h = *loc; + if (h) + return h->to; + + *loc = h = ggc_alloc (sizeof (struct tree_map)); + h->hash = in.hash; + h->base.from = decl; + h->to = to = build_decl (VAR_DECL, NULL, ptr_type_node); + DECL_ARTIFICIAL (to) = 1; + DECL_IGNORED_P (to) = 1; + DECL_EXTERNAL (to) = 1; + TREE_READONLY (to) = 1; + + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + name = targetm.strip_name_encoding (name); + if (name[0] == FASTCALL_PREFIX) + { + name++; + prefix = "*__imp_"; + } + else + prefix = "*__imp__"; + + namelen = strlen (name); + prefixlen = strlen (prefix); + imp_name = alloca (namelen + prefixlen + 1); + memcpy (imp_name, prefix, prefixlen); + memcpy (imp_name + prefixlen, name, namelen + 1); + + name = ggc_alloc_string (imp_name, namelen + prefixlen); + rtl = gen_rtx_SYMBOL_REF (Pmode, name); + SET_SYMBOL_REF_DECL (rtl, to); + SYMBOL_REF_FLAGS (rtl) = SYMBOL_FLAG_LOCAL; + + rtl = gen_const_mem (Pmode, rtl); + set_mem_alias_set (rtl, ix86_GOT_alias_set ()); + + SET_DECL_RTL (to, rtl); + + return to; +} + +/* Expand SYMBOL into its corresponding dllimport symbol. WANT_REG is + true if we require the result be a register. */ + +static rtx +legitimize_dllimport_symbol (rtx symbol, bool want_reg) +{ + tree imp_decl; + rtx x; + + gcc_assert (SYMBOL_REF_DECL (symbol)); + imp_decl = get_dllimport_decl (SYMBOL_REF_DECL (symbol)); + + x = DECL_RTL (imp_decl); + if (want_reg) + x = force_reg (Pmode, x); + return x; +} + /* Try machine-dependent ways of modifying an illegitimate address to be legitimate. If we find one, return the new, valid address. This macro is used in only one place: `memory_address' in explow.c. @@ -7231,6 +7319,20 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode) if (flag_pic && SYMBOLIC_CONST (x)) return legitimize_pic_address (x, 0); + if (TARGET_DLLIMPORT_DECL_ATTRIBUTES) + { + if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_DLLIMPORT_P (x)) + return legitimize_dllimport_symbol (x, true); + if (GET_CODE (x) == CONST + && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF + && SYMBOL_REF_DLLIMPORT_P (XEXP (XEXP (x, 0), 0))) + { + rtx t = legitimize_dllimport_symbol (XEXP (XEXP (x, 0), 0), true); + return gen_rtx_PLUS (Pmode, t, XEXP (XEXP (x, 0), 1)); + } + } + /* Canonicalize shifts by 0, 1, 2, 3 into multiply */ if (GET_CODE (x) == ASHIFT && CONST_INT_P (XEXP (x, 1)) @@ -9236,20 +9338,31 @@ ix86_expand_move (enum machine_mode mode, rtx operands[]) if (op1 == op0) return; } + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && SYMBOL_REF_DLLIMPORT_P (op1)) + op1 = legitimize_dllimport_symbol (op1, false); } else if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1, 0)) == PLUS && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SYMBOL_REF) { - model = SYMBOL_REF_TLS_MODEL (XEXP (XEXP (op1, 0), 0)); + rtx addend = XEXP (XEXP (op1, 0), 1); + rtx symbol = XEXP (XEXP (op1, 0), 0); + rtx tmp = NULL; + + model = SYMBOL_REF_TLS_MODEL (symbol); if (model) + tmp = legitimize_tls_address (symbol, model, true); + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && SYMBOL_REF_DLLIMPORT_P (symbol)) + tmp = legitimize_dllimport_symbol (symbol, true); + + if (tmp) { - rtx addend = XEXP (XEXP (op1, 0), 1); - op1 = legitimize_tls_address (XEXP (XEXP (op1, 0), 0), model, true); - op1 = force_operand (op1, NULL); - op1 = expand_simple_binop (Pmode, PLUS, op1, addend, + tmp = force_operand (tmp, NULL); + tmp = expand_simple_binop (Pmode, PLUS, tmp, addend, op0, 1, OPTAB_DIRECT); - if (op1 == op0) + if (tmp == op0) return; } } @@ -21648,6 +21761,10 @@ static const struct attribute_spec ix86_attribute_table[] = #undef TARGET_BINDS_LOCAL_P #define TARGET_BINDS_LOCAL_P darwin_binds_local_p #endif +#if TARGET_DLLIMPORT_DECL_ATTRIBUTES +#undef TARGET_BINDS_LOCAL_P +#define TARGET_BINDS_LOCAL_P i386_pe_binds_local_p +#endif #undef TARGET_ASM_OUTPUT_MI_THUNK #define TARGET_ASM_OUTPUT_MI_THUNK x86_output_mi_thunk diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 4c62ce54a63..045741b4c4f 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2347,8 +2347,6 @@ enum ix86_stack_slot (! IN_RANGE ((SRC), FIRST_STACK_REG, LAST_STACK_REG)) -#define DLL_IMPORT_EXPORT_PREFIX '#' - #define FASTCALL_PREFIX '@' struct machine_function GTY(()) @@ -2398,6 +2396,17 @@ struct machine_function GTY(()) #define SYMBOL_FLAG_FAR_ADDR (SYMBOL_FLAG_MACH_DEP << 0) #define SYMBOL_REF_FAR_ADDR_P(X) \ ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_FAR_ADDR) != 0) + +/* Flags to mark dllimport/dllexport. Used by PE ports, but handy to + have defined always, to avoid ifdefing. */ +#define SYMBOL_FLAG_DLLIMPORT (SYMBOL_FLAG_MACH_DEP << 1) +#define SYMBOL_REF_DLLIMPORT_P(X) \ + ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_DLLIMPORT) != 0) + +#define SYMBOL_FLAG_DLLEXPORT (SYMBOL_FLAG_MACH_DEP << 2) +#define SYMBOL_REF_DLLEXPORT_P(X) \ + ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_DLLEXPORT) != 0) + /* Local variables: version-control: t diff --git a/gcc/config/i386/netware.h b/gcc/config/i386/netware.h index 3630765c7aa..ed3ab3cd6a7 100644 --- a/gcc/config/i386/netware.h +++ b/gcc/config/i386/netware.h @@ -150,7 +150,6 @@ Boston, MA 02110-1301, USA. */ the number of registers used, and an atsign (@). */ void i386_nlm_encode_section_info (tree, rtx, int); const char *i386_nlm_strip_name_encoding (const char *); -#undef TARGET_ENCODE_SECTION_INFO -#define TARGET_ENCODE_SECTION_INFO i386_nlm_encode_section_info +#define SUBTARGET_ENCODE_SECTION_INFO i386_nlm_encode_section_info #undef TARGET_STRIP_NAME_ENCODING #define TARGET_STRIP_NAME_ENCODING i386_nlm_strip_name_encoding diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 97deda6cb01..efa5c98ee79 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -484,9 +484,14 @@ ;; Test for a pc-relative call operand (define_predicate "constant_call_address_operand" - (and (ior (match_code "symbol_ref") - (match_operand 0 "local_symbolic_operand")) - (match_test "ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC"))) + (match_code "symbol_ref") +{ + if (ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC) + return false; + if (TARGET_DLLIMPORT_DECL_ATTRIBUTES && SYMBOL_REF_DLLIMPORT_P (op)) + return false; + return true; +}) ;; True for any non-virtual or eliminable register. Used in places where ;; instantiation of such a register may cause the pattern to not be recognized. diff --git a/gcc/config/i386/uwin.h b/gcc/config/i386/uwin.h index 38d218ef6e6..a87d1e7ec8c 100644 --- a/gcc/config/i386/uwin.h +++ b/gcc/config/i386/uwin.h @@ -77,8 +77,7 @@ Boston, MA 02110-1301, USA. */ #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ do \ { \ - if (i386_pe_dllexport_name_p (NAME)) \ - i386_pe_record_exported_symbol (NAME, 0); \ + i386_pe_maybe_record_exported_symbol (DECL, NAME, 0); \ /* UWIN binutils bug workaround. */ \ if (0 && write_symbols != SDB_DEBUG) \ i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL)); \ diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c index a46fc5b2b02..a36fd08399d 100644 --- a/gcc/config/i386/winnt.c +++ b/gcc/config/i386/winnt.c @@ -34,6 +34,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "toplev.h" #include "hashtab.h" #include "ggc.h" +#include "target.h" /* i386/PE specific attribute support. @@ -46,22 +47,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA multiple times. */ -static tree associated_type (tree); -static tree gen_stdcall_or_fastcall_suffix (tree, bool); -static bool i386_pe_dllexport_p (tree); -static bool i386_pe_dllimport_p (tree); -static void i386_pe_mark_dllexport (tree); -static void i386_pe_mark_dllimport (tree); - -/* This is we how mark internal identifiers with dllimport or dllexport - attributes. */ -#ifndef DLL_IMPORT_PREFIX -#define DLL_IMPORT_PREFIX "#i." -#endif -#ifndef DLL_EXPORT_PREFIX -#define DLL_EXPORT_PREFIX "#e." -#endif - /* Handle a "shared" attribute; arguments as in struct attribute_spec.handler. */ tree @@ -108,67 +93,59 @@ ix86_handle_selectany_attribute (tree *node, tree name, static tree associated_type (tree decl) { - return (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))) - ? DECL_CONTEXT (decl) : NULL_TREE; + return (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)) + ? DECL_CONTEXT (decl) : NULL_TREE); } - -/* Return true if DECL is a dllexport'd object. */ +/* Return true if DECL should be a dllexport'd object. */ static bool -i386_pe_dllexport_p (tree decl) +i386_pe_determine_dllexport_p (tree decl) { - if (TREE_CODE (decl) != VAR_DECL - && TREE_CODE (decl) != FUNCTION_DECL) + tree assoc; + + if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return false; if (lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))) return true; /* Also mark class members of exported classes with dllexport. */ - if (associated_type (decl) - && lookup_attribute ("dllexport", - TYPE_ATTRIBUTES (associated_type (decl)))) + assoc = associated_type (decl); + if (assoc && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (assoc))) return i386_pe_type_dllexport_p (decl); return false; } +/* Return true if DECL should be a dllimport'd object. */ + static bool -i386_pe_dllimport_p (tree decl) +i386_pe_determine_dllimport_p (tree decl) { - if (TREE_CODE (decl) != VAR_DECL - && TREE_CODE (decl) != FUNCTION_DECL) + tree assoc; + + if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return false; /* Lookup the attribute in addition to checking the DECL_DLLIMPORT_P flag. We may need to override an earlier decision. */ - if (DECL_DLLIMPORT_P (decl) - && lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl))) - { - /* Make a final check to see if this is a definition before we generate - RTL for an indirect reference. */ - if (!DECL_EXTERNAL (decl)) - { - error ("%q+D: definition is marked as dllimport", decl); - DECL_DLLIMPORT_P (decl) = 0; - return false; - } - return true; - } + if (DECL_DLLIMPORT_P (decl)) + return true; + /* The DECL_DLLIMPORT_P flag was set for decls in the class definition by targetm.cxx.adjust_class_at_definition. Check again to emit warnings if the class attribute has been overridden by an out-of-class definition. */ - else if (associated_type (decl) - && lookup_attribute ("dllimport", - TYPE_ATTRIBUTES (associated_type (decl)))) + assoc = associated_type (decl); + if (assoc && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (assoc))) return i386_pe_type_dllimport_p (decl); return false; } /* Handle the -mno-fun-dllimport target switch. */ + bool i386_pe_valid_dllimport_attribute_p (tree decl) { @@ -177,247 +154,157 @@ i386_pe_valid_dllimport_attribute_p (tree decl) return true; } -/* Return nonzero if SYMBOL is marked as being dllexport'd. */ - -int -i386_pe_dllexport_name_p (const char *symbol) -{ - return (strncmp (DLL_EXPORT_PREFIX, symbol, - strlen (DLL_EXPORT_PREFIX)) == 0); -} - -/* Return nonzero if SYMBOL is marked as being dllimport'd. */ - -int -i386_pe_dllimport_name_p (const char *symbol) -{ - return (strncmp (DLL_IMPORT_PREFIX, symbol, - strlen (DLL_IMPORT_PREFIX)) == 0); -} - -/* Mark a DECL as being dllexport'd. - Note that we override the previous setting (e.g.: dllimport). */ - -static void -i386_pe_mark_dllexport (tree decl) -{ - const char *oldname; - char *newname; - rtx rtlname; - rtx symref; - tree idp; - - rtlname = XEXP (DECL_RTL (decl), 0); - if (GET_CODE (rtlname) == MEM) - rtlname = XEXP (rtlname, 0); - gcc_assert (GET_CODE (rtlname) == SYMBOL_REF); - oldname = XSTR (rtlname, 0); - if (i386_pe_dllimport_name_p (oldname)) - { - warning (0, "inconsistent dll linkage for %q+D, dllexport assumed", - decl); - /* Remove DLL_IMPORT_PREFIX. */ - oldname += strlen (DLL_IMPORT_PREFIX); - } - else if (i386_pe_dllexport_name_p (oldname)) - return; /* already done */ - - newname = alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1); - sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, 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. */ - idp = get_identifier (newname); - - symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); - SET_SYMBOL_REF_DECL (symref, decl); - XEXP (DECL_RTL (decl), 0) = symref; -} - -/* Mark a DECL as being dllimport'd. */ - -static void -i386_pe_mark_dllimport (tree decl) -{ - const char *oldname; - char *newname; - tree idp; - rtx rtlname, newrtl; - rtx symref; - - rtlname = XEXP (DECL_RTL (decl), 0); - if (GET_CODE (rtlname) == MEM) - rtlname = XEXP (rtlname, 0); - gcc_assert (GET_CODE (rtlname) == SYMBOL_REF); - oldname = XSTR (rtlname, 0); - if (i386_pe_dllexport_name_p (oldname)) - { - error ("%qs declared as both exported to and imported from a DLL", - IDENTIFIER_POINTER (DECL_NAME (decl))); - return; - } - else if (i386_pe_dllimport_name_p (oldname)) - { - /* Already done, but do a sanity check to prevent assembler - errors. */ - gcc_assert (DECL_EXTERNAL (decl) && TREE_PUBLIC (decl) - && DECL_DLLIMPORT_P (decl)); - return; - } - - newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1); - sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, 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. */ - idp = get_identifier (newname); - - symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); - SET_SYMBOL_REF_DECL (symref, decl); - newrtl = gen_rtx_MEM (Pmode,symref); - XEXP (DECL_RTL (decl), 0) = newrtl; - - DECL_DLLIMPORT_P (decl) = 1; -} - /* Return string which is the former assembler name modified with a suffix consisting of an atsign (@) followed by the number of bytes of - arguments. If FASTCALL is true, also add the FASTCALL_PREFIX. */ + arguments. If FASTCALL is true, also add the FASTCALL_PREFIX. + Return NULL if no change required. */ static tree gen_stdcall_or_fastcall_suffix (tree decl, bool fastcall) { - int total = 0; - /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead - of DECL_ASSEMBLER_NAME. */ - const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - char *newsym; - char *p; + HOST_WIDE_INT total = 0; + const char *asm_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + char *new_str, *p; tree formal_type; /* Do not change the identifier if a verbatim asmspec or already done. */ - if (*asmname == '*' || strchr (asmname, '@')) - return DECL_ASSEMBLER_NAME (decl); + if (*asm_str == '*' || strchr (asm_str, '@')) + return NULL_TREE; formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl)); if (formal_type != NULL_TREE) - { - /* These attributes are ignored for variadic functions in - i386.c:ix86_return_pops_args. For compatibility with MS - compiler do not add @0 suffix here. */ - if (TREE_VALUE (tree_last (formal_type)) != void_type_node) - return DECL_ASSEMBLER_NAME (decl); + while (1) + { + HOST_WIDE_INT parm_size; + HOST_WIDE_INT parm_boundary_bytes = PARM_BOUNDARY / BITS_PER_UNIT; - /* Quit if we hit an incomplete type. Error is reported - by convert_arguments in c-typeck.c or cp/typeck.c. */ - while (TREE_VALUE (formal_type) != void_type_node - && COMPLETE_TYPE_P (TREE_VALUE (formal_type))) - { - int parm_size - = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type))); - /* Must round up to include padding. This is done the same - way as in store_one_arg. */ - parm_size = ((parm_size + PARM_BOUNDARY - 1) - / PARM_BOUNDARY * PARM_BOUNDARY); - total += parm_size; - formal_type = TREE_CHAIN (formal_type);\ - } - } + /* We got to the end of the list without seeing void_list_node, + which means the function is variadic. The suffix is to be + ignored in that case. */ + if (formal_type == NULL_TREE) + return NULL_TREE; + + /* End of arguments, non-varargs marker. */ + if (formal_type == void_list_node) + break; + + /* Quit if we hit an incomplete type. Error is reported + by convert_arguments in c-typeck.c or cp/typeck.c. */ + parm_size = int_size_in_bytes (TREE_VALUE (formal_type)); + if (parm_size < 0) + break; + + /* Must round up to include padding. This is done the same + way as in store_one_arg. */ + parm_size = ((parm_size + parm_boundary_bytes - 1) + / parm_boundary_bytes * parm_boundary_bytes); + total += parm_size; + + formal_type = TREE_CHAIN (formal_type); + } /* Assume max of 8 base 10 digits in the suffix. */ - newsym = alloca (1 + strlen (asmname) + 1 + 8 + 1); - p = newsym; + p = new_str = alloca (1 + strlen (asm_str) + 1 + 8 + 1); if (fastcall) *p++ = FASTCALL_PREFIX; - sprintf (p, "%s@%d", asmname, total/BITS_PER_UNIT); - return get_identifier (newsym); + sprintf (p, "%s@" HOST_WIDE_INT_PRINT_DEC, asm_str, total); + + return get_identifier (new_str); } void i386_pe_encode_section_info (tree decl, rtx rtl, int first) { + rtx symbol; + int flags; + + /* Do this last, due to our frobbing of DECL_DLLIMPORT_P above. */ default_encode_section_info (decl, rtl, first); - if (first && TREE_CODE (decl) == FUNCTION_DECL) - { - tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl)); - tree newid = NULL_TREE; + /* Careful not to prod global register variables. */ + if (!MEM_P (rtl)) + return; - if (lookup_attribute ("stdcall", type_attributes)) - newid = gen_stdcall_or_fastcall_suffix (decl, false); - else if (lookup_attribute ("fastcall", type_attributes)) - newid = gen_stdcall_or_fastcall_suffix (decl, true); - if (newid != NULL_TREE) + symbol = XEXP (rtl, 0); + gcc_assert (GET_CODE (symbol) == SYMBOL_REF); + + switch (TREE_CODE (decl)) + { + case FUNCTION_DECL: + if (first) { - rtx rtlname = XEXP (rtl, 0); - if (GET_CODE (rtlname) == MEM) - rtlname = XEXP (rtlname, 0); - XSTR (rtlname, 0) = IDENTIFIER_POINTER (newid); - /* These attributes must be present on first declaration, - change_decl_assembler_name will warn if they are added - later and the decl has been referenced, but duplicate_decls - should catch the mismatch before this is called. */ - change_decl_assembler_name (decl, newid); - } - } + tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl)); + tree newid = NULL_TREE; - else if (TREE_CODE (decl) == VAR_DECL - && lookup_attribute ("selectany", DECL_ATTRIBUTES (decl))) - { - if (DECL_INITIAL (decl) - /* If an object is initialized with a ctor, the static - initialization and destruction code for it is present in - each unit defining the object. The code that calls the - ctor is protected by a link-once guard variable, so that - the object still has link-once semantics, */ - || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) - make_decl_one_only (decl); - else - error ("%q+D:'selectany' attribute applies only to initialized objects", - decl); + if (lookup_attribute ("stdcall", type_attributes)) + newid = gen_stdcall_or_fastcall_suffix (decl, false); + else if (lookup_attribute ("fastcall", type_attributes)) + newid = gen_stdcall_or_fastcall_suffix (decl, true); + if (newid != NULL_TREE) + { + XSTR (symbol, 0) = IDENTIFIER_POINTER (newid); + /* These attributes must be present on first declaration, + change_decl_assembler_name will warn if they are added + later and the decl has been referenced, but duplicate_decls + should catch the mismatch before this is called. */ + change_decl_assembler_name (decl, newid); + } + } + break; + + case VAR_DECL: + if (lookup_attribute ("selectany", DECL_ATTRIBUTES (decl))) + { + if (DECL_INITIAL (decl) + /* If an object is initialized with a ctor, the static + initialization and destruction code for it is present in + each unit defining the object. The code that calls the + ctor is protected by a link-once guard variable, so that + the object still has link-once semantics, */ + || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) + make_decl_one_only (decl); + else + error ("%q+D:'selectany' attribute applies only to " + "initialized objects", decl); + } + break; + + default: + return; } /* Mark the decl so we can tell from the rtl whether the object is dllexport'd or dllimport'd. tree.c: merge_dllimport_decl_attributes handles dllexport/dllimport override semantics. */ - - if (i386_pe_dllexport_p (decl)) - i386_pe_mark_dllexport (decl); - else if (i386_pe_dllimport_p (decl)) - i386_pe_mark_dllimport (decl); - /* It might be that DECL has been declared as dllimport, but a - subsequent definition nullified that. Assert that - tree.c: merge_dllimport_decl_attributes has removed the attribute - before the RTL name was marked with the DLL_IMPORT_PREFIX. */ - else - gcc_assert (!((TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == VAR_DECL) - && rtl != NULL_RTX - && GET_CODE (rtl) == MEM - && GET_CODE (XEXP (rtl, 0)) == MEM - && GET_CODE (XEXP (XEXP (rtl, 0), 0)) == SYMBOL_REF - && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (rtl, 0), 0), 0)))); + flags = (SYMBOL_REF_FLAGS (symbol) & + ~(SYMBOL_FLAG_DLLIMPORT | SYMBOL_FLAG_DLLEXPORT)); + if (i386_pe_determine_dllexport_p (decl)) + flags |= SYMBOL_FLAG_DLLEXPORT; + else if (i386_pe_determine_dllimport_p (decl)) + { + flags |= SYMBOL_FLAG_DLLIMPORT; + /* If we went through the associated_type path, this won't already + be set. Though, frankly, this seems wrong, and should be fixed + elsewhere. */ + if (!DECL_DLLIMPORT_P (decl)) + { + DECL_DLLIMPORT_P (decl) = 1; + flags &= ~SYMBOL_FLAG_LOCAL; + } + } + SYMBOL_REF_FLAGS (symbol) = flags; } -/* Strip only the leading encoding, leaving the stdcall suffix and fastcall - prefix if it exists. */ - -const char * -i386_pe_strip_name_encoding (const char *str) +bool +i386_pe_binds_local_p (tree exp) { - if (strncmp (str, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX)) - == 0) - str += strlen (DLL_IMPORT_PREFIX); - else if (strncmp (str, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX)) - == 0) - str += strlen (DLL_EXPORT_PREFIX); - if (*str == '*') - str += 1; - return str; + /* PE does not do dynamic binding. Indeed, the only kind of + non-local reference comes from a dllimport'd symbol. */ + if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == FUNCTION_DECL) + && DECL_DLLIMPORT_P (exp)) + return false; + + return true; } /* Also strip the fastcall prefix and stdcall suffix. */ @@ -426,7 +313,7 @@ const char * i386_pe_strip_name_encoding_full (const char *str) { const char *p; - const char *name = i386_pe_strip_name_encoding (str); + const char *name = default_strip_name_encoding (str); /* Strip leading '@' on fastcall symbols. */ if (*name == '@') @@ -440,46 +327,6 @@ i386_pe_strip_name_encoding_full (const char *str) return name; } -/* Output a reference to a label. Fastcall symbols are prefixed with @, - whereas symbols for functions using other calling conventions don't - have a prefix (unless they are marked dllimport or dllexport). */ - -void i386_pe_output_labelref (FILE *stream, const char *name) -{ - if (strncmp (name, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX)) - == 0) - /* A dll import */ - { - if (name[strlen (DLL_IMPORT_PREFIX)] == FASTCALL_PREFIX) - /* A dllimport fastcall symbol. */ - { - fprintf (stream, "__imp_%s", - i386_pe_strip_name_encoding (name)); - } - else - /* A dllimport non-fastcall symbol. */ - { - fprintf (stream, "__imp__%s", - i386_pe_strip_name_encoding (name)); - } - } - else if ((name[0] == FASTCALL_PREFIX) - || (strncmp (name, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX)) - == 0 - && name[strlen (DLL_EXPORT_PREFIX)] == FASTCALL_PREFIX)) - /* A fastcall symbol. */ - { - fprintf (stream, "%s", - i386_pe_strip_name_encoding (name)); - } - else - /* Everything else. */ - { - fprintf (stream, "%s%s", USER_LABEL_PREFIX, - i386_pe_strip_name_encoding (name)); - } -} - void i386_pe_unique_section (tree decl, int reloc) { @@ -612,6 +459,29 @@ i386_pe_asm_named_section (const char *name, unsigned int flags, (discard ? "discard" : "same_size")); } } + +void +i386_pe_asm_output_aligned_decl_common (FILE *stream, tree decl, + const char *name, HOST_WIDE_INT size, + HOST_WIDE_INT align ATTRIBUTE_UNUSED) +{ + HOST_WIDE_INT rounded; + + /* Compute as in assemble_noswitch_variable, since we don't actually + support aligned common. */ + rounded = size ? size : 1; + rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1; + rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) + * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); + + i386_pe_maybe_record_exported_symbol (decl, name, 1); + + fprintf (stream, "\t.comm\t"); + assemble_name (stream, name); + fprintf (stream, ", " HOST_WIDE_INT_PRINT_DEC "\t" ASM_COMMENT_START + " " HOST_WIDE_INT_PRINT_DEC "\n", + rounded, size); +} /* The Microsoft linker requires that every function be marked as DT_FCN. When using gas on cygwin, we must emit appropriate .type @@ -682,10 +552,16 @@ static GTY(()) struct export_list *export_head; linkonce. */ void -i386_pe_record_exported_symbol (const char *name, int is_data) +i386_pe_maybe_record_exported_symbol (tree decl, const char *name, int is_data) { + rtx symbol; struct export_list *p; + symbol = XEXP (DECL_RTL (decl), 0); + gcc_assert (GET_CODE (symbol) == SYMBOL_REF); + if (!SYMBOL_REF_DLLEXPORT_P (symbol)) + return; + p = (struct export_list *) ggc_alloc (sizeof *p); p->next = export_head; p->name = name; @@ -727,8 +603,8 @@ i386_pe_file_end (void) for (q = export_head; q != NULL; q = q->next) { fprintf (asm_out_file, "\t.ascii \" -export:%s%s\"\n", - i386_pe_strip_name_encoding (q->name), - (q->is_data) ? ",data" : ""); + targetm.strip_name_encoding (q->name), + (q->is_data ? ",data" : "")); } } } diff --git a/gcc/varasm.c b/gcc/varasm.c index cf880e83b16..1adc4923481 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -4063,9 +4063,8 @@ initializer_constant_valid_p (tree value, tree endtype) return null_pointer_node; /* Taking the address of a nested function involves a trampoline. */ if (TREE_CODE (value) == FUNCTION_DECL - && ((decl_function_context (value) - && !DECL_NO_STATIC_CHAIN (value)) - || DECL_DLLIMPORT_P (value))) + && decl_function_context (value) + && !DECL_NO_STATIC_CHAIN (value)) return NULL_TREE; /* "&{...}" requires a temporary to hold the constructed object. */