This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Updated] dllimport/dllexport attributes for Win32/BeOS
- To: egcs-patches at cygnus dot com
- Subject: [Updated] dllimport/dllexport attributes for Win32/BeOS
- From: Mumit Khan <khan at xraylith dot wisc dot edu>
- Date: Mon, 22 Jun 1998 19:21:31 -0500
Updates since last posting (14-May-1998)
========================================
- Successfully used by BeOS folks. Needed this in order to have a self-
hosting GCC. Fred Fish has more info on this.
- C++ front-end problem fixed (cf: gcc/tree.c(staticp)).
- Few cleanups. Closely follows Microsoft redeclaration rules now.
- DLL magic prefix changed from __imp_ to _imp__ to conform to MS
standard. New'ish dlltool creates both, so nobody should suffer
because of it.
dllimport and dllexport attributes for i386/pe
===============================================
This patch implements two new attributes, dllimport and dllexport, for
i386-cygwin32, i386-mingw32* and i386-beos targets, which greatly simplify
the process of using and creating DLLs. The attributes are specified using
the usual __attribute__((dllimport)) and __attribute__((dllexport)), or
via CPP macros __declspec(dllimport) and __declspec(dllexport).
This work is largely due to Doug Evans' work on ARM/PE at Cygnus.
The meat of this patch is about 4 lines of code, and the rest is really
support stuff. See i386_pe_mark_dll{import,export} for RTL mucking.
These patches do not affect code not using the new attributes, and even
when used, can be reverted to old behavior with -fnop-fun-dllimport.
Patches are against egcs-19980622 CVS tree. No testsuite regressions for
i386-cygwin32 and i386-mingw32.
What works (or doesn't)?
============================
The C front has gone through limited testing and apparently stable/usable.
The C++ global pointer initialization problem (to variables or functions
imported from a DLL) is now *fixed* (see the change to gcc/tree.c). The
last time around, the following did not work:
// file scope
__attribute__((dllimport) int imported_var;
int *localvar_p = &imported_var;
nor did this:
// file scope
__attribute__((dllimport) int imported_func();
int (*localfunc_p) = &imported_func;
Since the C++ front-end will parse '&imported_var' as a "static"
ADDR_EXPR (cf: gcc/cp/typeck.c(build_unary_op), case ADDR_EXPR) and
backend gets very confused. Both of these need initialization, and
can't treated as "static" as defined by staticp().
Specifying __attribute__((dllexport)) will do the right thing; however,
binutils does not yet take advantage of this information when building
DLLs.
What doesn't work? I wouldn't know unless this gets integrated and people
start using it on real code and file bug reports.
Regards,
Mumit -- khan@xraylith.wisc.edu
=========================================================================
Mon Jun 22 18:35:56 1998 Mumit Khan <khan@xraylith.wisc.edu>
Support for dllimport and dllexport attributes for i386-pe.
* 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.
* tree.c (staticp): Don't treat DLL imported functions and variables
at global scope as static.
Index: gcc/tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.c,v
retrieving revision 1.33
diff -u -3 -p -r1.33 tree.c
--- tree.c 1998/06/20 00:35:42 1.33
+++ tree.c 1998/06/22 23:48:53
@@ -2256,10 +2256,26 @@ staticp (arg)
switch (TREE_CODE (arg))
{
case FUNCTION_DECL:
+ /* Don't treat global scope DLL imported functions as static since
+ taking their address involves initialization. */
+ if (global_bindings_p ()
+ && lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES(arg))
+ != NULL_TREE)
+ {
+ return 0;
+ }
/* Nested functions aren't static, since taking their address
involves a trampoline. */
return decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg);
case VAR_DECL:
+ /* Don't treat global scope DLL imported variables as static since
+ taking their address involves initialization. */
+ if (global_bindings_p ()
+ && lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES(arg))
+ != NULL_TREE)
+ {
+ return 0;
+ }
return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
case CONSTRUCTOR:
Index: gcc/config/i386/cygwin32.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/i386/cygwin32.h,v
retrieving revision 1.7
diff -u -3 -p -r1.7 cygwin32.h
--- cygwin32.h 1998/04/04 17:38:55 1.7
+++ cygwin32.h 1998/06/22 23:48:53
@@ -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,65 @@ 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)
+
+#undef ASM_COMMENT_START
+#define ASM_COMMENT_START " #"
+
+/* 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. */
@@ -224,11 +359,9 @@ do { \
? "discard" : "same_size"); \
} while (0)
-#undef ASM_COMMENT_START
-#define ASM_COMMENT_START " #"
-
/* DWARF2 Unwinding doesn't work with exception handling yet. */
#define DWARF2_UNWIND_INFO 0
/* Don't assume anything about the header files. */
#define NO_IMPLICIT_EXTERN_C
+
Index: gcc/config/i386/mingw32.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/i386/mingw32.h,v
retrieving revision 1.3
diff -u -3 -p -r1.3 mingw32.h
--- mingw32.h 1998/04/04 17:38:59 1.3
+++ mingw32.h 1998/06/22 23:48:53
@@ -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. */
Index: gcc/config/i386/winnt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/i386/winnt.c,v
retrieving revision 1.3
diff -u -3 -p -r1.3 winnt.c
--- winnt.c 1998/05/13 14:04:08 1.3
+++ winnt.c 1998/06/22 23:48:54
@@ -28,6 +28,346 @@ 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. */
+ /* ??? At least I think that's why we do this. */
+ idp = get_identifier (newname);
+
+ XEXP (DECL_RTL (decl), 0) =
+ gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
+}
+
+/* Mark a DECL as being dllimport'd. */
+
+void
+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 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. */
+ if (TREE_CODE (decl) == VAR_DECL
+ && !DECL_VIRTUAL_P (decl)
+ && DECL_INITIAL (decl))
+ {
+ error_with_decl (decl, "initialized variable `%s' is marked dllimport");
+ return;
+ }
+ /* Nor can they be static. */
+ if (TREE_CODE (decl) == VAR_DECL
+ /* ??? Is this test for vtables needed? */
+ && !DECL_VIRTUAL_P (decl)
+ && 0 /*???*/)
+ {
+ error_with_decl (decl, "static variable `%s' is marked dllimport");
+ return;
+ }
+
+ /* `extern' needn't be specified with dllimport.
+ Specify `extern' now and hope for the best. Sigh. */
+ if (TREE_CODE (decl) == VAR_DECL
+ /* ??? Is this test for vtables needed? */
+ && !DECL_VIRTUAL_P (decl))
+ {
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ }
+
+ newname = alloca (strlen (oldname) + 11);
+ sprintf (newname, "@i._imp__%s", oldname);
+
+ /* We pass newname through get_identifier to ensure it has a unique
+ address. RTL processing can sometimes peek inside the symbol ref
+ and compare the string's addresses to see if two symbols are
+ identical. */
+ /* ??? At least I think that's why we do this. */
+ idp = get_identifier (newname);
+
+ newrtl = gen_rtx (MEM, Pmode,
+ gen_rtx (SYMBOL_REF, Pmode,
+ IDENTIFIER_POINTER (idp)));
+ XEXP (DECL_RTL (decl), 0) = newrtl;
+}
+
/* 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 +406,56 @@ 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. */
+ 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;
+
+ /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
+ ??? We leave these alone for now. */
+ }
+}
+
/* Cover function for UNIQUE_SECTION. */
void
@@ -77,6 +467,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