diff options
author | Mumit Khan <khan@xraylith.wisc.edu> | 1998-07-07 00:05:27 +0000 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 1998-07-06 18:05:27 -0600 |
commit | 27da1b4d5a1c30a60a38f725f2119fda88854d88 (patch) | |
tree | 75c3f6b8a5b39fd43548abba6d1860adc4b7c3fe | |
parent | bceb30e77bd19db8debc5182b75018c169acd6ff (diff) | |
download | gcc-27da1b4d5a1c30a60a38f725f2119fda88854d88.zip gcc-27da1b4d5a1c30a60a38f725f2119fda88854d88.tar.gz gcc-27da1b4d5a1c30a60a38f725f2119fda88854d88.tar.bz2 |
Support for dllimport and dllexport attributes for i386-pe.
* tree.h (DECL_NON_ADDR_CONST_P): New accessor macro.
(struct tree_decl): Add non_addr_const_p field.
* tree.c (staticp): Use.
* i386/cygwin32.h (CPP_PREDEFINES): Map __declspec(x) to GCC
attributes.
(SUBTARGET_SWITCHES): Switches to turn on/off dllimport|export
attributes. Also accept -mwindows option.
(VALID_MACHINE_DECL_ATTRIBUTE): New macro.
(MERGE_MACHINE_DECL_ATTRIBUTE): New macro.
(REDO_SECTION_INFO_P): New macro.
(DRECTVE_SECTION_FUNCTION): New macro.
(drectve_section): Cover function to implement above.
(SWITCH_TO_SECTION_FUNCTION): New macro.
(switch_to_section): Covert function to implement above.
(EXTRA_SECTIONS): Add in_drectve.
(EXTRA_SECTION_FUNCTIONS): Add in_drectve and switch_to_section.
(ENCODE_SECTION_INFO): Delete old macro and redefine as a function.
(STRIP_NAME_ENCODING): Handle new attributes.
(ASM_OUTPUT_LABELREF): New macro.
(ASM_OUTPUT_FUNCTION_NAME): New macro.
(ASM_OUTPUT_COMMON): New macro.
(ASM_OUTPUT_DECLARE_OBJECT_NAME): New macro.
* i386/mingw32.h (CPP_PREDEFINES): Map __declspec(x) to GCC
attributes.
* i386/winnt.c (i386_pe_valid_decl_attribute_p): New function.
(i386_pe_merge_decl_attributes): New function.
(i386_pe_check_vtable_importexport): New function.
(i386_pe_dllexport_p): New function.
(i386_pe_dllimport_p): New function.
(i386_pe_dllexport_name_p): New function.
(i386_pe_dllimport_name_p): New function.
(i386_pe_mark_dllexport): New function.
(i386_pe_mark_dllimport): New function.
(i386_pe_encode_section_info): New function.
(i386_pe_unique_section): Strip encoding from name first.
From-SVN: r20983
-rw-r--r-- | gcc/ChangeLog | 43 | ||||
-rw-r--r-- | gcc/config/i386/cygwin32.h | 188 | ||||
-rw-r--r-- | gcc/config/i386/mingw32.h | 1 | ||||
-rw-r--r-- | gcc/config/i386/winnt.c | 400 | ||||
-rw-r--r-- | gcc/tree.c | 7 | ||||
-rw-r--r-- | gcc/tree.h | 6 |
6 files changed, 615 insertions, 30 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 01affd1..d258618 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,46 @@ +Tue Jul 7 01:03:03 1998 Mumit Khan <khan@xraylith.wisc.edu> + + Support for dllimport and dllexport attributes for i386-pe. + + * tree.h (DECL_NON_ADDR_CONST_P): New accessor macro. + (struct tree_decl): Add non_addr_const_p field. + * tree.c (staticp): Use. + + * i386/cygwin32.h (CPP_PREDEFINES): Map __declspec(x) to GCC + attributes. + (SUBTARGET_SWITCHES): Switches to turn on/off dllimport|export + attributes. Also accept -mwindows option. + (VALID_MACHINE_DECL_ATTRIBUTE): New macro. + (MERGE_MACHINE_DECL_ATTRIBUTE): New macro. + (REDO_SECTION_INFO_P): New macro. + (DRECTVE_SECTION_FUNCTION): New macro. + (drectve_section): Cover function to implement above. + (SWITCH_TO_SECTION_FUNCTION): New macro. + (switch_to_section): Covert function to implement above. + (EXTRA_SECTIONS): Add in_drectve. + (EXTRA_SECTION_FUNCTIONS): Add in_drectve and switch_to_section. + (ENCODE_SECTION_INFO): Delete old macro and redefine as a function. + (STRIP_NAME_ENCODING): Handle new attributes. + (ASM_OUTPUT_LABELREF): New macro. + (ASM_OUTPUT_FUNCTION_NAME): New macro. + (ASM_OUTPUT_COMMON): New macro. + (ASM_OUTPUT_DECLARE_OBJECT_NAME): New macro. + + * i386/mingw32.h (CPP_PREDEFINES): Map __declspec(x) to GCC + attributes. + + * i386/winnt.c (i386_pe_valid_decl_attribute_p): New function. + (i386_pe_merge_decl_attributes): New function. + (i386_pe_check_vtable_importexport): New function. + (i386_pe_dllexport_p): New function. + (i386_pe_dllimport_p): New function. + (i386_pe_dllexport_name_p): New function. + (i386_pe_dllimport_name_p): New function. + (i386_pe_mark_dllexport): New function. + (i386_pe_mark_dllimport): New function. + (i386_pe_encode_section_info): New function. + (i386_pe_unique_section): Strip encoding from name first. + Tue Jul 7 00:50:17 1998 Manfred Hollstein (manfred@s-direktnet.de) * libgcc2.c (L_exit): Provide a fake for atexit on systems which diff --git a/gcc/config/i386/cygwin32.h b/gcc/config/i386/cygwin32.h index 1677422..f76cd53 100644 --- a/gcc/config/i386/cygwin32.h +++ b/gcc/config/i386/cygwin32.h @@ -30,6 +30,14 @@ Boston, MA 02111-1307, USA. */ #include "i386/gas.h" #include "dbxcoff.h" +/* Support the __declspec keyword by turning them into attributes. + We currently only support: 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. */ + #ifdef CPP_PREDEFINES #undef CPP_PREDEFINES #endif @@ -38,6 +46,7 @@ Boston, MA 02111-1307, USA. */ -D__CYGWIN32__ -DWINNT -D_X86_=1 -D__STDC__=1\ -D__stdcall=__attribute__((__stdcall__)) \ -D__cdecl=__attribute__((__cdecl__)) \ + -D__declspec(x)=__attribute__((x)) \ -Asystem(winnt) -Acpu(i386) -Amachine(i386)" #undef CPP_SPEC @@ -69,13 +78,51 @@ Boston, MA 02111-1307, USA. */ #define WCHAR_TYPE "short unsigned int" #define HAVE_ATEXIT 1 + +/* Ignore dllimport for functions. */ +#define TARGET_NOP_FUN_DLLIMPORT (target_flags & 0x20000) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ + { "nop-fun-dllimport", 0x20000 }, \ + { "no-nop-fun-dllimport", -0x20000 }, \ + { "windows", 0x0 }, + +/* 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 i386_pe_valid_decl_attribute_p (); + +#undef VALID_MACHINE_DECL_ATTRIBUTE +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ + i386_pe_valid_decl_attribute_p (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +extern union tree_node *i386_pe_merge_decl_attributes (); +#define MERGE_MACHINE_DECL_ATTRIBUTES(OLD, NEW) \ + i386_pe_merge_decl_attributes ((OLD), (NEW)) + +/* 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 i386_pe_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 + + #undef EXTRA_SECTIONS -#define EXTRA_SECTIONS in_ctor, in_dtor +#define EXTRA_SECTIONS in_ctor, in_dtor, in_drectve #undef EXTRA_SECTION_FUNCTIONS #define EXTRA_SECTION_FUNCTIONS \ CTOR_SECTION_FUNCTION \ - DTOR_SECTION_FUNCTION + DTOR_SECTION_FUNCTION \ + DRECTVE_SECTION_FUNCTION \ + SWITCH_TO_SECTION_FUNCTION #define CTOR_SECTION_FUNCTION \ void \ @@ -99,6 +146,41 @@ dtor_section () \ } \ } +#define DRECTVE_SECTION_FUNCTION \ +void \ +drectve_section () \ +{ \ + if (in_section != in_drectve) \ + { \ + fprintf (asm_out_file, "%s\n", "\t.section .drectve\n"); \ + 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_ctor: ctor_section (); break; \ + case in_dtor: dtor_section (); break; \ + case in_drectve: drectve_section (); break; \ + default: abort (); break; \ + } \ +} + #define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ do { \ ctor_section (); \ @@ -111,7 +193,7 @@ dtor_section () \ do { \ dtor_section (); \ fprintf (FILE, "%s\t", ASM_LONG); \ - assemble_name (FILE, NAME); \ + assemble_name (FILE, NAME); \ fprintf (FILE, "\n"); \ } while (0) @@ -119,44 +201,38 @@ dtor_section () \ differently depending on something about the variable or function named by the symbol (such as what section it is in). - On i386, if using PIC, mark a SYMBOL_REF for a non-global symbol - so that we may access it directly in the GOT. - On i386 running Windows NT, modify the assembler name with a suffix consisting of an atsign (@) followed by string of digits that represents the number of bytes of arguments passed to the function, if it has the - attribute STDCALL. */ + attribute STDCALL. + + In addition, 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 i386_pe_encode_section_info (); #ifdef ENCODE_SECTION_INFO #undef ENCODE_SECTION_INFO -#define ENCODE_SECTION_INFO(DECL) \ -do \ - { \ - if (flag_pic) \ - { \ - rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ - ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \ - SYMBOL_REF_FLAG (XEXP (rtl, 0)) \ - = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ - || ! TREE_PUBLIC (DECL)); \ - } \ - if (TREE_CODE (DECL) == FUNCTION_DECL) \ - if (lookup_attribute ("stdcall", \ - TYPE_ATTRIBUTES (TREE_TYPE (DECL)))) \ - XEXP (DECL_RTL (DECL), 0) = \ - gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (DECL)); \ - } \ -while (0) #endif +#define ENCODE_SECTION_INFO(DECL) i386_pe_encode_section_info (DECL) -/* This macro gets just the user-specified name out of the string in a - SYMBOL_REF. Discard trailing @[NUM] encoded by ENCODE_SECTION_INFO. */ +/* Utility used only in this file. */ +#define I386_PE_STRIP_ENCODING(SYM_NAME) \ + ((SYM_NAME) + ((SYM_NAME)[0] == '@' ? 3 : 0)) +/* This macro gets just the user-specified name + out of the string in a SYMBOL_REF. Discard + trailing @[NUM] encoded by ENCODE_SECTION_INFO. */ #undef STRIP_NAME_ENCODING #define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \ do { \ char *_p; \ - char *_name = ((SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*')); \ + char *_name = I386_PE_STRIP_ENCODING (SYMBOL_NAME); \ for (_p = _name; *_p && *_p != '@'; ++_p) \ ; \ if (*_p == '@') \ @@ -170,6 +246,62 @@ do { \ (VAR) = _name; \ } 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, \ + I386_PE_STRIP_ENCODING (NAME)) \ + +/* Output a function definition label. */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ +do { \ + if (i386_pe_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", \ + I386_PE_STRIP_ENCODING (NAME)); \ + function_section (DECL); \ + } \ + 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 (i386_pe_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", \ + I386_PE_STRIP_ENCODING (NAME)); \ + } \ + if (! i386_pe_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 (i386_pe_dllexport_name_p (NAME)) \ + { \ + enum in_section save_section = in_section; \ + drectve_section (); \ + fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", \ + I386_PE_STRIP_ENCODING (NAME)); \ + switch_to_section (save_section, (DECL)); \ + } \ + ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ +} while (0) + + /* Emit code to check the stack when allocating more that 4000 bytes in one go. */ diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h index 7c7a3bb..1929962 100644 --- a/gcc/config/i386/mingw32.h +++ b/gcc/config/i386/mingw32.h @@ -31,6 +31,7 @@ Boston, MA 02111-1307, USA. */ -D__MINGW32__ -DWINNT -D_X86_=1 -D__STDC__=1\ -D__stdcall=__attribute__((__stdcall__)) \ -D__cdecl=__attribute__((__cdecl__)) \ + -D__declspec(x)=__attribute__((x)) \ -Asystem(winnt) -Acpu(i386) -Amachine(i386)" /* Specific a different directory for the standard include files. */ diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c index 2f4cc88..95daf14 100644 --- a/gcc/config/i386/winnt.c +++ b/gcc/config/i386/winnt.c @@ -28,6 +28,351 @@ Boston, MA 02111-1307, USA. */ #include "tree.h" #include "flags.h" +/* i386/PE specific attribute support. + + i386/PE has two new attributes: + 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 +i386_pe_valid_decl_attribute_p (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 i386_valid_decl_attribute_p (decl, attributes, 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 +i386_pe_merge_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 +i386_pe_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. */ + +#if 0 +tree current_class_type; /* FIXME */ +#endif + +int +i386_pe_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) + ? i386_pe_check_vtable_importexport (DECL_CONTEXT (decl)) + : current_class_type + ? i386_pe_check_vtable_importexport (current_class_type) + : 0) + ) + return 1; + } +#endif + + return 0; +} + +/* Return non-zero if DECL is a dllimport'd object. */ + +int +i386_pe_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) + ? i386_pe_check_vtable_importexport (DECL_CONTEXT (decl)) + : current_class_type + ? i386_pe_check_vtable_importexport (current_class_type) + : 0) + ) + return 1; + } +#endif + + return 0; +} + +/* Return non-zero if SYMBOL is marked as being dllexport'd. */ + +int +i386_pe_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 +i386_pe_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 +i386_pe_mark_dllexport (decl) + tree decl; +{ + char *oldname, *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 (i386_pe_dllimport_name_p (oldname)) + oldname += 9; + else if (i386_pe_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. */ + 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 +i386_pe_mark_dllimport (decl) + tree decl; +{ + char *oldname, *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 (i386_pe_dllexport_name_p (oldname)) + { + error ("`%s' 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 force correct linkage since the redeclaration + might have omitted explicit extern. 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; + } + return; + } + + /* ??? One can well ask why we're making these checks here, + and that would be a good question. */ + + /* Imported variables can't be initialized. Note that C++ classes + are marked initial, so we need to check. */ + if (TREE_CODE (decl) == VAR_DECL + && !DECL_VIRTUAL_P (decl) + && (DECL_INITIAL (decl) + && ! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (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. */ + idp = get_identifier (newname); + + newrtl = gen_rtx (MEM, Pmode, + gen_rtx (SYMBOL_REF, Pmode, + IDENTIFIER_POINTER (idp))); + XEXP (DECL_RTL (decl), 0) = newrtl; + + /* Can't treat a pointer to this as a constant address */ + DECL_NON_ADDR_CONST_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 */ @@ -66,6 +411,59 @@ gen_stdcall_suffix (decl) return IDENTIFIER_POINTER (get_identifier (newsym)); } +/* Cover function to implement ENCODE_SECTION_INFO. */ + +void +i386_pe_encode_section_info (decl) + tree decl; +{ + /* This bit is copied from i386.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; + } + + if (TREE_CODE (decl) == FUNCTION_DECL) + if (lookup_attribute ("stdcall", + TYPE_ATTRIBUTES (TREE_TYPE (decl)))) + XEXP (DECL_RTL (decl), 0) = + gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl)); + + /* Mark the decl so we can tell from the rtl whether the object is + dllexport'd or dllimport'd. */ + + 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 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. Ditto + for the DECL_NON_ADDR_CONST_P flag. */ + 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 + && 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); + tree idp = get_identifier (oldname + 9); + rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp)); + + XEXP (DECL_RTL (decl), 0) = newrtl; + + DECL_NON_ADDR_CONST_P (decl) = 0; + + /* We previously set TREE_PUBLIC and DECL_EXTERNAL. + We leave these alone for now. */ + } +} + /* Cover function for UNIQUE_SECTION. */ void @@ -77,6 +475,8 @@ i386_pe_unique_section (decl, reloc) char *name,*string,*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 @@ -2265,9 +2265,12 @@ staticp (arg) case FUNCTION_DECL: /* Nested functions aren't static, since taking their address involves a trampoline. */ - return decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg); + return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg)) + && ! DECL_NON_ADDR_CONST_P (arg); + case VAR_DECL: - return TREE_STATIC (arg) || DECL_EXTERNAL (arg); + return (TREE_STATIC (arg) || DECL_EXTERNAL (arg)) + && ! DECL_NON_ADDR_CONST_P (arg); case CONSTRUCTOR: return TREE_STATIC (arg); @@ -1201,6 +1201,10 @@ struct tree_type #define DECL_LANG_FLAG_6(NODE) (DECL_CHECK (NODE)->decl.lang_flag_6) #define DECL_LANG_FLAG_7(NODE) (DECL_CHECK (NODE)->decl.lang_flag_7) +/* Used to indicate that the pointer to this DECL cannot be treated as + an address constant. */ +#define DECL_NON_ADDR_CONST_P(NODE) (DECL_CHECK (NODE)->decl.non_addr_const_p) + struct tree_decl { char common[sizeof (struct tree_common)]; @@ -1242,6 +1246,8 @@ struct tree_decl unsigned lang_flag_6 : 1; unsigned lang_flag_7 : 1; + unsigned non_addr_const_p : 1; + /* For a FUNCTION_DECL, if inline, this is the size of frame needed. If built-in, this is the code for which built-in function. For other kinds of decls, this is DECL_ALIGN. */ |