varasm.c (initializer_constant_valid_p): Don't deny DECL_DLLIMPORT_P on functions.

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

From-SVN: r123344
This commit is contained in:
Richard Henderson 2007-03-29 14:54:35 -07:00 committed by Richard Henderson
parent 0c9bce0b5c
commit da489f7340
11 changed files with 386 additions and 362 deletions

View File

@ -1,3 +1,52 @@
2007-03-29 Richard Henderson <rth@redhat.com>
* 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 <zack@mrtock.ucsd.edu>
* gengtype.c (oprintf): Mostly revert changes from 2007-03-26;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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" : ""));
}
}
}

View File

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