diff options
author | Nick Clifton <nickc@gcc.gnu.org> | 2004-07-12 08:45:00 +0000 |
---|---|---|
committer | Nick Clifton <nickc@gcc.gnu.org> | 2004-07-12 08:45:00 +0000 |
commit | b55e3aad633bd6e8de2b41b1a6ce41e5241878ac (patch) | |
tree | 35b091528607aff8382046cbeb9d46bb0dde23d4 /gcc | |
parent | 55e99d5226d32dc4e78fa96375034dda4fbbfcb9 (diff) | |
download | gcc-b55e3aad633bd6e8de2b41b1a6ce41e5241878ac.zip gcc-b55e3aad633bd6e8de2b41b1a6ce41e5241878ac.tar.gz gcc-b55e3aad633bd6e8de2b41b1a6ce41e5241878ac.tar.bz2 |
config.gcc: Add sh-*-symbianelf target.
* config.gcc: Add sh-*-symbianelf target.
* config/sh/sh.c: Add new target macros:
TARGET_ENCODE_SECTION_INFO, TARGET_STRIP_NAME_ENCODING,
TARGET_CXX_IMPORT_EXPORT_CLASS.
(sh_file_start): Create a definition of the .directive section.
(sh_attribute): Add dllimport and dllexport attributes.
* config/sh/symbian-pre.h: New file.
* config/sh/symbian-post.h: New file.
* config/sh/symbian.c: New file. Contains Symbian specific functions.
* config/sh/sh-protos.h: Add prototypes for new functions provided by symbian.c.
* config/sh/t-symbian: New file.
* doc/extend.texi: Document support for dllimport and dllexport attributes by
the sh-symbianelf target.
From-SVN: r84551
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config.gcc | 7 | ||||
-rw-r--r-- | gcc/config/sh/sh-protos.h | 14 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 28 | ||||
-rw-r--r-- | gcc/config/sh/symbian-post.h | 89 | ||||
-rw-r--r-- | gcc/config/sh/symbian-pre.h | 48 | ||||
-rw-r--r-- | gcc/config/sh/symbian.c | 906 | ||||
-rw-r--r-- | gcc/config/sh/t-symbian | 35 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 60 |
8 files changed, 1164 insertions, 23 deletions
diff --git a/gcc/config.gcc b/gcc/config.gcc index bc8fa23..26b4897 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -1671,6 +1671,7 @@ s390x-ibm-tpf*) tmake_file="t-slibgcc-elf-ver s390/t-crtstuff s390/t-tpf" ;; sh-*-elf* | sh[12346l]*-*-elf* | sh*-*-kaos* | \ +sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \ sh-*-linux* | sh[346lbe]*-*-linux* | \ sh-*-netbsdelf* | shl*-*-netbsdelf* | sh5-*-netbsd* | sh5l*-*-netbsd* | \ sh64-*-netbsd* | sh64l*-*-netbsd*) @@ -1730,6 +1731,12 @@ sh-*-elf* | sh[12346l]*-*-elf* | sh*-*-kaos* | \ tm_file="${tm_file} sh/sh64.h" extra_headers="shmedia.h ushmedia.h sshmedia.h" ;; + *-*-symbianelf*) + tmake_file="sh/t-symbian" + tm_file="sh/symbian-pre.h sh/little.h ${tm_file} sh/symbian-post.h" + extra_objs="symbian.o" + extra_parts="crt1.o crti.o crtn.o crtbegin.o crtend.o crtbeginS.o crtendS.o" + ;; esac # sed el/eb endian suffixes away to avoid confusion with sh[23]e case `echo ${target} | sed 's/e[lb]-/-/'` in diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index 05d694d..0d1733c 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -143,3 +143,17 @@ extern const char *sh_pch_valid_p (const void *data_p, size_t sz); extern bool sh_promote_prototypes (tree); #endif /* ! GCC_SH_PROTOS_H */ + +#ifdef SYMBIAN +extern bool sh_symbian_dllimport_name_p (const char *); +extern const char * sh_symbian_strip_name_encoding (const char *); +extern bool sh_symbian_dllexport_name_p (const char *); +extern int symbian_import_export_class (tree, int); +#ifdef TREE_CODE +extern bool sh_symbian_dllexport_p (tree); +extern tree sh_symbian_handle_dll_attribute (tree *, tree, tree, int, bool *); +#ifdef RTX_CODE +extern void sh_symbian_encode_section_info (tree, rtx, int); +#endif +#endif +#endif /* SYMBIAN */ diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 11882dd..dc16c61 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -451,6 +451,17 @@ static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *); /* Return current register pressure for regmode. */ #define CURR_REGMODE_PRESSURE(MODE) curr_regmode_pressure[((MODE) == SImode) ? 0 : 1] +#ifdef SYMBIAN + +#undef TARGET_ENCODE_SECTION_INFO +#define TARGET_ENCODE_SECTION_INFO sh_symbian_encode_section_info +#undef TARGET_STRIP_NAME_ENCODING +#define TARGET_STRIP_NAME_ENCODING sh_symbian_strip_name_encoding +#undef TARGET_CXX_IMPORT_EXPORT_CLASS +#define TARGET_CXX_IMPORT_EXPORT_CLASS symbian_import_export_class + +#endif /* SYMBIAN */ + struct gcc_target targetm = TARGET_INITIALIZER; /* Print the operand address in x to the stream. */ @@ -1431,6 +1442,12 @@ sh_file_start (void) { default_file_start (); +#ifdef SYMBIAN + /* Declare the .directive section before it is used. */ + fputs ("\t.section .directive, \"SM\", @progbits, 1\n", asm_out_file); + fputs ("\t.asciz \"#<SYMEDIT>#\\n\"\n", asm_out_file); +#endif + if (TARGET_ELF) /* We need to show the text section with the proper attributes as in TEXT_SECTION_ASM_OP, before dwarf2out @@ -6950,6 +6967,17 @@ const struct attribute_spec sh_attribute_table[] = { "sp_switch", 1, 1, true, false, false, sh_handle_sp_switch_attribute }, { "trap_exit", 1, 1, true, false, false, sh_handle_trap_exit_attribute }, { "renesas", 0, 0, false, true, false, sh_handle_renesas_attribute }, +#ifdef SYMBIAN + /* Symbian support adds three 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. */ + { "dllimport", 0, 0, true, false, false, sh_symbian_handle_dll_attribute }, + { "dllexport", 0, 0, true, false, false, sh_symbian_handle_dll_attribute }, +#endif { NULL, 0, 0, false, false, false, NULL } }; diff --git a/gcc/config/sh/symbian-post.h b/gcc/config/sh/symbian-post.h new file mode 100644 index 0000000..b39262d --- /dev/null +++ b/gcc/config/sh/symbian-post.h @@ -0,0 +1,89 @@ +/* Definitions for the Symbian OS running on an SH part. + This file is included after all the other target specific headers. + + Copyright (C) 2004 Free Software Foundation, Inc. + Contributed by Red Hat. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#undef TARGET_VERSION +#define TARGET_VERSION \ + fputs (" (Renesas SH for Symbian OS)", stderr); + +#undef LINK_EMUL_PREFIX +#define LINK_EMUL_PREFIX "shlsymbian" + + +#define SYMBIAN_EXPORT_NAME(NAME,FILE,DECL) \ + do \ + { \ + if ((DECL && sh_symbian_dllexport_p (DECL)) \ + || sh_symbian_dllexport_name_p (NAME)) \ + { \ + fprintf ((FILE), "\t.pushsection .directive\n"); \ + fprintf ((FILE), "\t.asciz \"EXPORT %s\\n\"\n", \ + sh_symbian_strip_name_encoding (NAME)); \ + fprintf ((FILE), "\t.popsection\n"); \ + } \ + } \ + while (0) + +/* Output a function definition label. */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + do \ + { \ + SYMBIAN_EXPORT_NAME ((NAME), (FILE), (DECL)); \ + ASM_OUTPUT_TYPE_DIRECTIVE ((FILE), (NAME), "function"); \ + ASM_DECLARE_RESULT ((FILE), DECL_RESULT (DECL)); \ + ASM_OUTPUT_LABEL ((FILE), (NAME)); \ + } \ + while (0) + +/* Output the label for an initialized variable. */ +#undef ASM_DECLARE_OBJECT_NAME +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ + do \ + { \ + HOST_WIDE_INT size; \ + \ + SYMBIAN_EXPORT_NAME ((NAME), (FILE), (DECL)); \ + ASM_OUTPUT_TYPE_DIRECTIVE ((FILE), (NAME), "object"); \ + \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive \ + && (DECL) \ + && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + size = int_size_in_bytes (TREE_TYPE (DECL)); \ + ASM_OUTPUT_SIZE_DIRECTIVE ((FILE), (NAME), size); \ + } \ + \ + ASM_OUTPUT_LABEL ((FILE), (NAME)); \ + } \ + while (0) + +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE, NAME) \ + do \ + { \ + asm_fprintf ((FILE), "%U%s", \ + sh_symbian_strip_name_encoding (NAME)); \ + } \ + while (0) diff --git a/gcc/config/sh/symbian-pre.h b/gcc/config/sh/symbian-pre.h new file mode 100644 index 0000000..aa23535 --- /dev/null +++ b/gcc/config/sh/symbian-pre.h @@ -0,0 +1,48 @@ +/* Definitions for the Symbian OS running on an SH part. + This file is included before any other target specific headers. + + Copyright (C) 2004 Free Software Foundation, Inc. + Contributed by Red Hat. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Enable Symbian specific code. */ +#define SYMBIAN 1 + +/* Default to using the Renesas ABI. */ +#define TARGET_ABI_DEFAULT RENESAS_BIT + +/* Support the __declspec keyword by turning them into attributes. + We currently only support: naked, 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. */ +#define SUBTARGET_CPP_SPEC "-D__declspec(x)=__attribute__((x))" + +/* Get tree.c to declare merge_dllimport_decl_attributes(). */ +#define TARGET_DLLIMPORT_DECL_ATTRIBUTES + +/* The Symbian OS currently does not support exception handling. */ +#define SUBTARGET_CC1PLUS_SPEC "-fno-exceptions" + +/* Create constructor/destructor sections without the writable flag. + Symbian puts them into the text segment and munges them later on. */ +#define CTORS_SECTION_ASM_OP "\t.section\t.ctors,\"ax\",@progbits" +#define DTORS_SECTION_ASM_OP "\t.section\t.dtors,\"ax\",@progbits" diff --git a/gcc/config/sh/symbian.c b/gcc/config/sh/symbian.c new file mode 100644 index 0000000..33ab711 --- /dev/null +++ b/gcc/config/sh/symbian.c @@ -0,0 +1,906 @@ +/* Routines for GCC for a Symbian OS targeted SH backend. + Copyright (C) 2004 Free Software Foundation, Inc. + Contributed by RedHat. + Most of this code is stolen from i386/winnt.c. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "output.h" +#include "flags.h" +#include "tree.h" +#include "expr.h" +#include "tm_p.h" +#include "cp/cp-tree.h" /* We need access to the OVL_... macros. */ +#include "toplev.h" + +/* Select the level of debugging information to display. + 0 for no debugging. + 1 for informative messages about decisions to add attributes + 2 for verbose information about what is being done. */ +#define SYMBIAN_DEBUG 0 +//#define SYMBIAN_DEBUG 1 +//#define SYMBIAN_DEBUG 2 + +/* A unique character to encode declspec encoded objects. */ +#define SH_SYMBIAN_FLAG_CHAR "$" + +/* Unique strings to prefix exported and imported objects. */ +#define DLL_IMPORT_PREFIX SH_SYMBIAN_FLAG_CHAR "i." +#define DLL_EXPORT_PREFIX SH_SYMBIAN_FLAG_CHAR "e." + + +/* Return the type that we should use to determine if DECL is + imported or exported. */ + +static tree +sh_symbian_associated_type (tree decl) +{ + tree t = NULL_TREE; + + if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) + /* Methods now inherit their dllimport/dllexport attributes correctly + so there is no need to check their class. In fact it is wrong to + check their class since a method can remain unexported from an + exported class. */ + return t; + + /* Otherwise we can just take the DECL_CONTEXT as normal. */ + if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))) + t = DECL_CONTEXT (decl); + + return t; +} + +/* Return nonzero if DECL is a dllexport'd object. */ + +bool +sh_symbian_dllexport_p (tree decl) +{ + tree exp; + + if ( TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FUNCTION_DECL) + return false; + + exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)); + + /* Class members get the dllexport status of their class. */ + if (exp == NULL) + { + tree class = sh_symbian_associated_type (decl); + + if (class) + exp = lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class)); + } +#if SYMBIAN_DEBUG + if (exp) + { + print_node_brief (stderr, "dllexport:", decl, 0); + fprintf (stderr, "\n"); + } + else +#if SYMBIAN_DEBUG < 2 + if (TREE_CODE (decl) != FUNCTION_DECL) +#endif + { + print_node_brief (stderr, "no dllexport:", decl, 0); + fprintf (stderr, "\n"); + } +#endif + return exp ? true : false; +} + +/* Return nonzero if DECL is a dllimport'd object. */ + +static bool +sh_symbian_dllimport_p (tree decl) +{ + tree imp; + + if ( TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FUNCTION_DECL) + return false; + + imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)); + if (imp) + return true; + + /* Class members get the dllimport status of their class. */ + imp = sh_symbian_associated_type (decl); + if (! imp) + return false; + + imp = lookup_attribute ("dllimport", TYPE_ATTRIBUTES (imp)); + if (!imp) + return false; + + /* Don't mark defined functions as dllimport. If the definition itself + was marked with dllimport, then sh_symbian_handle_dll_attribute reports + an error. This handles the case when the definition overrides an + earlier declaration. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl) + && !DECL_INLINE (decl)) + { + /* Don't warn about artificial methods. */ + if (!DECL_ARTIFICIAL (decl)) + warning ("%H function '%D' is defined after prior declaration as dllimport: attribute ignored", + & DECL_SOURCE_LOCATION (decl), decl); + return false; + } + + /* We ignore the dllimport attribute for inline member functions. + This differs from MSVC behavior which treats it like GNUC + 'extern inline' extension. */ + else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl)) + { + if (extra_warnings) + warning ("%Hinline function '%D' is declared as dllimport: attribute ignored.", + & DECL_SOURCE_LOCATION (decl), decl); + return false; + } + + /* Don't allow definitions of static data members in dllimport + class. Just ignore the attribute for vtable data. */ + else if (TREE_CODE (decl) == VAR_DECL + && TREE_STATIC (decl) + && TREE_PUBLIC (decl) + && !DECL_EXTERNAL (decl)) + { + if (!DECL_VIRTUAL_P (decl)) + error ("%Hdefinition of static data member '%D' of dllimport'd class.", + & DECL_SOURCE_LOCATION (decl), decl); + return false; + } + + /* Since we can't treat a pointer to a dllimport'd symbol as a + constant address, we turn off the attribute on C++ virtual + methods to allow creation of vtables using thunks. Don't mark + artificial methods either (in sh_symbian_associated_type, only + COMDAT artificial method get import status from class context). */ + else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE + && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl))) + return false; + + return true; +} + +/* Return nonzero if SYMBOL is marked as being dllexport'd. */ + +bool +sh_symbian_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. */ + + +bool +sh_symbian_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 (eg: dllimport). */ + +static void +sh_symbian_mark_dllexport (tree decl) +{ + const char *oldname; + char *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 (sh_symbian_dllimport_name_p (oldname)) + { + /* Remove DLL_IMPORT_PREFIX. + Note - we do not issue a warning here. In Symbian's environment it + is legitimate for a prototype to be marked as dllimport and the + corresponding defintion to be marked as dllexport. The prototypes + are in headers used everywhere and the defintion is in a translation + unit which has included the header in order to ensure argument + correctness. */ + oldname += strlen (DLL_IMPORT_PREFIX); + DECL_NON_ADDR_CONST_P (decl) = 0; + } + else if (sh_symbian_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); + + XEXP (DECL_RTL (decl), 0) = + gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); +} + +/* Mark a DECL as being dllimport'd. */ + +static void +sh_symbian_mark_dllimport (tree decl) +{ + const char *oldname; + char *newname; + tree idp; + rtx rtlname; + rtx 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 (sh_symbian_dllexport_name_p (oldname)) + { + error ("`%s' declared as both exported to and imported from a DLL", + IDENTIFIER_POINTER (DECL_NAME (decl))); + } + else if (sh_symbian_dllimport_name_p (oldname)) + { + /* Already done, but do a sanity check to prevent assembler errors. */ + if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl)) + error ("%Hfailure in redeclaration of '%D': dllimport'd symbol lacks external linkage.", + &DECL_SOURCE_LOCATION (decl), decl); + } + else + { + 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); + newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); + XEXP (DECL_RTL (decl), 0) = newrtl; + } +} + +void +sh_symbian_encode_section_info (tree decl, rtx rtl, int first) +{ + default_encode_section_info (decl, rtl, first); + + /* Mark the decl so we can tell from the rtl whether + the object is dllexport'd or dllimport'd. */ + if (sh_symbian_dllexport_p (decl)) + sh_symbian_mark_dllexport (decl); + else if (sh_symbian_dllimport_p (decl)) + sh_symbian_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 (DLL_IMPORT_PREFIX) prefixed. 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 + && sh_symbian_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0))) + { + const char * oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0); + /* Remove DLL_IMPORT_PREFIX. */ + tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX)); + rtx newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); + + warning ("%H%s '%D' %s after being referenced with dllimport linkage.", + & DECL_SOURCE_LOCATION (decl), + TREE_CODE (decl) == VAR_DECL ? "variable" : "function", + decl, (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl)) + ? "defined locally" : "redeclared without dllimport attribute"); + + XEXP (DECL_RTL (decl), 0) = newrtl; + + DECL_NON_ADDR_CONST_P (decl) = 0; + } +} + + +/* Return the length of a function name prefix + that starts with the character 'c'. */ + +static int +sh_symbian_get_strip_length (int c) +{ + /* XXX Assumes strlen (DLL_EXPORT_PREFIX) == strlen (DLL_IMPORT_PREFIX). */ + return (c == SH_SYMBIAN_FLAG_CHAR[0]) ? strlen (DLL_EXPORT_PREFIX) : 0; +} + +/* Return a pointer to a function's name with any + and all prefix encodings stripped from it. */ + +const char * +sh_symbian_strip_name_encoding (const char *name) +{ + int skip; + + while ((skip = sh_symbian_get_strip_length (*name))) + name += skip; + + return name; +} + +/* Add the named attribute to the given node. Copes with both DECLs and + TYPEs. Will only add the attribute if it is not already present. */ + +static void +symbian_add_attribute (tree node, const char *attr_name) +{ + tree attrs; + tree attr; + + attrs = DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node); + + if (lookup_attribute (attr_name, attrs) != NULL_TREE) + return; + + attr = get_identifier (attr_name); + + (DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node)) + = tree_cons (attr, NULL_TREE, attrs); + +#if SYMBIAN_DEBUG + fprintf (stderr, "propogate %s attribute", attr_name); + print_node_brief (stderr, " to", node, 0); + fprintf (stderr, "\n"); +#endif +} + +/* Handle a "dllimport" or "dllexport" attribute; + arguments as in struct attribute_spec.handler. */ + +tree +sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args, + int flags, bool *no_add_attrs) +{ + tree thunk; + tree node = *pnode; + const char *attr = IDENTIFIER_POINTER (name); + + /* These attributes may apply to structure and union types being + created, but otherwise should pass to the declaration involved. */ + if (!DECL_P (node)) + { + if (flags & ((int) ATTR_FLAG_DECL_NEXT + | (int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_ARRAY_NEXT)) + { + warning ("`%s' attribute ignored", attr); + *no_add_attrs = true; + return tree_cons (name, args, NULL_TREE); + } + + if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE) + { + warning ("`%s' attribute ignored", attr); + *no_add_attrs = true; + } + + return NULL_TREE; + } + + /* Report error on dllimport ambiguities + seen now before they cause any damage. */ + else if (is_attribute_p ("dllimport", name)) + { + if (TREE_CODE (node) == VAR_DECL) + { + if (DECL_INITIAL (node)) + { + error ("%Hvariable `%D' definition is marked dllimport.", + & DECL_SOURCE_LOCATION (node), node); + *no_add_attrs = true; + } + + /* `extern' needn't be specified with dllimport. + Specify `extern' now and hope for the best. Sigh. */ + DECL_EXTERNAL (node) = 1; + /* Also, implicitly give dllimport'd variables declared within + a function global scope, unless declared static. */ + if (current_function_decl != NULL_TREE && ! TREE_STATIC (node)) + TREE_PUBLIC (node) = 1; + } + } + + /* If the node is an overloaded constructor or desctructor, then we must + make sure that the attribute is propogated along the overload chain, + as it is these overloaded functions which will be emitted, rather than + the user declared constructor itself. */ + if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE + && (DECL_CONSTRUCTOR_P (node) || DECL_DESTRUCTOR_P (node))) + { + tree overload; + + for (overload = OVL_CHAIN (node); overload; overload = OVL_CHAIN (overload)) + { + tree node_args; + tree func_args; + tree function = OVL_CURRENT (overload); + + if (! function + || ! DECL_P (function) + || (DECL_CONSTRUCTOR_P (node) && ! DECL_CONSTRUCTOR_P (function)) + || (DECL_DESTRUCTOR_P (node) && ! DECL_DESTRUCTOR_P (function))) + continue; + + /* The arguments must match as well. */ + for (node_args = DECL_ARGUMENTS (node), func_args = DECL_ARGUMENTS (function); + node_args && func_args; + node_args = TREE_CHAIN (node_args), func_args = TREE_CHAIN (func_args)) + if (TREE_TYPE (node_args) != TREE_TYPE (func_args)) + break; + + if (node_args || func_args) + { + /* We can ignore an extraneous __in_chrg arguments in the node. + GCC generated destructors, for example, will have this. */ + if ((node_args == NULL_TREE + || func_args != NULL_TREE) + && strcmp (IDENTIFIER_POINTER (DECL_NAME (node)), "__in_chrg") != 0) + continue; + } + + symbian_add_attribute (function, attr); + + /* Propogate the attribute to any function thunks as well. */ + for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk)) + if (TREE_CODE (thunk) == FUNCTION_DECL) + symbian_add_attribute (thunk, attr); + } + } + + if (TREE_CODE (node) == FUNCTION_DECL && DECL_VIRTUAL_P (node)) + { + /* Propogate the attribute to any thunks of this function. */ + for (thunk = DECL_THUNKS (node); thunk; thunk = TREE_CHAIN (thunk)) + if (TREE_CODE (thunk) == FUNCTION_DECL) + symbian_add_attribute (thunk, attr); + } + + /* Report error if symbol is not accessible at global scope. */ + if (!TREE_PUBLIC (node) + && ( TREE_CODE (node) == VAR_DECL + || TREE_CODE (node) == FUNCTION_DECL)) + { + error ("%Hexternal linkage required for symbol '%D' because of '%s' attribute.", + & DECL_SOURCE_LOCATION (node), node, IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + +#if SYMBIAN_DEBUG + print_node_brief (stderr, "mark node", node, 0); + fprintf (stderr, " as %s\n", attr); +#endif + + return NULL_TREE; +} + +/* This code implements a specification for exporting the vtable and rtti of + classes that have members with the dllexport or dllexport attributes. + This specification is defined here: + + http://www.armdevzone.com/EABI/exported_class.txt + + Basically it says that a class's vtable and rtti should be exported if + the following rules apply: + + - If it has any non-inline non-pure virtual functions, + at least one of these need to be declared dllimport + OR any of the constructors is declared dllimport. + + AND + + - The class has an inline constructor/destructor and + a key-function (placement of vtable uniquely defined) that + is defined in this translation unit. + + The specification also says that for classes which will have their + vtables and rtti exported that their base class(es) might also need a + similar exporting if: + + - Every base class needs to have its vtable & rtti exported + as well, if the following the conditions hold true: + + The base class has a non-inline declared non-pure virtual function + + The base class is polymorphic (has or inherits any virtual functions) + or the base class has any virtual base classes. */ + +/* Decide if a base class of a class should + also have its vtable and rtti exported. */ + +static void +symbian_possibly_export_base_class (tree base_class) +{ + tree methods; + int len; + + if (! (TYPE_POLYMORPHIC_P (base_class) + || TYPE_USES_VIRTUAL_BASECLASSES (base_class))) + return; + + methods = CLASSTYPE_METHOD_VEC (base_class); + len = methods ? TREE_VEC_LENGTH (methods) : 0; + + for (;len --;) + { + tree member = TREE_VEC_ELT (methods, len); + + if (! member) + continue; + + for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member)) + { + if (TREE_CODE (member) != FUNCTION_DECL) + continue; + + if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member)) + continue; + + if (! DECL_VIRTUAL_P (member)) + continue; + + if (DECL_PURE_VIRTUAL_P (member)) + continue; + + if (DECL_INLINE (member)) + continue; + + break; + } + + if (member) + break; + } + + if (len < 0) + return; + + /* FIXME: According to the spec this base class should be exported, but + a) how do we do this ? and + b) it does not appear to be necessary for compliance with the Symbian + OS which so far is the only consumer of this code. */ +#if SYMBIAN_DEBUG + print_node_brief (stderr, "", base_class, 0); + fprintf (stderr, " EXPORTed [base class of exported class]\n"); +#endif +} + +/* Decide if a class needs its vtable and rtti exporting. */ + +static bool +symbian_export_vtable_and_rtti_p (tree ctype) +{ + bool inline_ctor_dtor; + bool dllimport_ctor_dtor; + bool dllimport_member; + tree binfos; + tree methods; + tree key; + int len; + + /* Make sure that we are examining a class... */ + if (TREE_CODE (ctype) != RECORD_TYPE) + { +#if SYMBIAN_DEBUG + print_node_brief (stderr, "", ctype, 0); + fprintf (stderr, " does NOT need to be EXPORTed [not a class]\n"); +#endif + return false; + } + + /* If the class does not have a key function it + does not need to have its vtable exported. */ + if ((key = CLASSTYPE_KEY_METHOD (ctype)) == NULL_TREE) + { +#if SYMBIAN_DEBUG + print_node_brief (stderr, "", ctype, 0); + fprintf (stderr, " does NOT need to be EXPORTed [no key function]\n"); +#endif + return false; + } + + /* If the key fn has not been defined + then the class should not be exported. */ + if (! TREE_ASM_WRITTEN (key)) + { +#if SYMBIAN_DEBUG + print_node_brief (stderr, "", ctype, 0); + fprintf (stderr, " does NOT need to be EXPORTed [key function not defined]\n"); +#endif + return false; + } + + /* Check the class's member functions. */ + inline_ctor_dtor = false; + dllimport_ctor_dtor = false; + dllimport_member = false; + + methods = CLASSTYPE_METHOD_VEC (ctype); + len = methods ? TREE_VEC_LENGTH (methods) : 0; + + for (;len --;) + { + tree member = TREE_VEC_ELT (methods, len); + + if (! member) + continue; + + for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member)) + { + if (TREE_CODE (member) != FUNCTION_DECL) + continue; + + if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member)) + { + if (DECL_INLINE (member) + /* Ignore C++ backend created inline ctors/dtors. */ + && ( DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (member) + || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (member))) + inline_ctor_dtor = true; + + if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member))) + dllimport_ctor_dtor = true; + } + else + { + if (DECL_PURE_VIRTUAL_P (member)) + continue; + + if (! DECL_VIRTUAL_P (member)) + continue; + + if (DECL_INLINE (member)) + continue; + + if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member))) + dllimport_member = true; + } + } + } + + if (! dllimport_member && ! dllimport_ctor_dtor) + { +#if SYMBIAN_DEBUG + print_node_brief (stderr, "", ctype, 0); + fprintf (stderr, + " does NOT need to be EXPORTed [no non-pure virtuals or ctors/dtors with dllimport]\n"); +#endif + return false; + } + + if (! inline_ctor_dtor) + { +#if SYMBIAN_DEBUG + print_node_brief (stderr, "", ctype, 0); + fprintf (stderr, + " does NOT need to be EXPORTed [no inline ctor/dtor]\n"); +#endif + return false; + } + +#if SYMBIAN_DEBUG + print_node_brief (stderr, "", ctype, 0); + fprintf (stderr, " DOES need to be EXPORTed\n"); +#endif + + /* Now we must check and possibly export the base classes. */ + binfos = BINFO_BASE_BINFOS (TYPE_BINFO (ctype)); + len = BINFO_N_BASE_BINFOS (TYPE_BINFO (ctype)); + + for (; len --;) + { + tree base_binfo; + tree basetype; + + /* Figure out which base we're looking at. */ + base_binfo = TREE_VEC_ELT (binfos, len); + basetype = TREE_TYPE (base_binfo); + + symbian_possibly_export_base_class (basetype); + } + + return true; +} + +/* Add the named attribute to a class and its vtable and rtti. */ + +static void +symbian_add_attribute_to_class_vtable_and_rtti (tree ctype, const char *attr_name) +{ + symbian_add_attribute (ctype, attr_name); + + /* If the vtable exists then they need annotating as well. */ + if (CLASSTYPE_VTABLES (ctype)) + /* XXX - Do we need to annotate any vtables other than the primary ? */ + symbian_add_attribute (CLASSTYPE_VTABLES (ctype), attr_name); + + /* If the rtti exists then it needs annotating as well. */ + if (TYPE_MAIN_VARIANT (ctype) + && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype))) + symbian_add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)), + attr_name); +} + +/* Decide if a class needs to have an attribute because + one of its member functions has the attribute. */ + +static bool +symbian_class_needs_attribute_p (tree ctype, const char *attribute_name) +{ + /* If the key function has the attribute then the class needs it too. */ + if (TYPE_POLYMORPHIC_P (ctype) + && CLASSTYPE_KEY_METHOD (ctype) + && lookup_attribute (attribute_name, + DECL_ATTRIBUTES (CLASSTYPE_KEY_METHOD (ctype)))) + return true; + + /* Check the class's member functions. */ + if (TREE_CODE (ctype) == RECORD_TYPE) + { + tree methods = CLASSTYPE_METHOD_VEC (ctype); + unsigned int len = methods ? TREE_VEC_LENGTH (methods) : 0; + + for (;len --;) + { + tree member = TREE_VEC_ELT (methods, len); + + if (! member) + continue; + + for (member = OVL_CURRENT (member); + member; + member = OVL_NEXT (member)) + { + if (TREE_CODE (member) != FUNCTION_DECL) + continue; + + if (DECL_PURE_VIRTUAL_P (member)) + continue; + + if (! DECL_VIRTUAL_P (member)) + continue; + + if (lookup_attribute (attribute_name, DECL_ATTRIBUTES (member))) + { +#if SYMBIAN_DEBUG + print_node_brief (stderr, "", ctype, 0); + fprintf (stderr, " inherits %s because", attribute_name); + print_node_brief (stderr, "", member, 0); + fprintf (stderr, " has it.\n"); +#endif + return true; + } + } + } + } + +#if SYMBIAN_DEBUG + print_node_brief (stderr, "", ctype, 0); + fprintf (stderr, " does not inherit %s\n", attribute_name); +#endif + return false; +} + +int +symbian_import_export_class (tree ctype, int import_export) +{ + const char *attr_name = NULL; + + /* If we are exporting the class but it does not have the dllexport + attribute then we may need to add it. Similarly imported classes + may need the dllimport attribute. */ + switch (import_export) + { + case 1: attr_name = "dllexport"; break; + case -1: attr_name = "dllimport"; break; + default: break; + } + + if (attr_name + && ! lookup_attribute (attr_name, TYPE_ATTRIBUTES (ctype))) + { + if (symbian_class_needs_attribute_p (ctype, attr_name)) + symbian_add_attribute_to_class_vtable_and_rtti (ctype, attr_name); + + /* Classes can be forced to export their + vtable and rtti under certain conditions. */ + if (symbian_export_vtable_and_rtti_p (ctype)) + { + symbian_add_attribute_to_class_vtable_and_rtti (ctype, "dllexport"); + + /* Make sure that the class and its vtable are exported. */ + import_export = 1; + + if (CLASSTYPE_VTABLES (ctype)) + DECL_EXTERNAL (CLASSTYPE_VTABLES (ctype)) = 1; + + /* Check to make sure that if the class has a key method that + it is now on the list of keyed classes. That way its vtable + will be emitted. */ + if (CLASSTYPE_KEY_METHOD (ctype)) + { + tree class; + + for (class = keyed_classes; class; class = TREE_CHAIN (class)) + if (class == ctype) + break; + + if (class == NULL_TREE) + { +#if SYMBIAN_DEBUG + print_node_brief (stderr, "Add node", ctype, 0); + fprintf (stderr, " to the keyed classes list\n"); +#endif + keyed_classes = tree_cons (NULL_TREE, ctype, keyed_classes); + } + } + + /* Make sure that the typeinfo will be emitted as well. */ + if (CLASS_TYPE_P (ctype)) + TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))) = 1; + } + } + + return import_export; +} + +/* Dummy defintion of this array for cc1 building purposes. */ +tree cp_global_trees[CPTI_MAX] __attribute__((weak)); + +#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007) + +/* Dummy version of this G++ function for building cc1. */ +void lang_check_failed (const char *, int, const char *) __attribute__((weak)); + +void +lang_check_failed (const char *file, int line, const char *function) +{ + internal_error ("lang_* check: failed in %s, at %s:%d", + function, trim_filename (file), line); +} +#endif /* ENABLE_TREE_CHECKING */ diff --git a/gcc/config/sh/t-symbian b/gcc/config/sh/t-symbian new file mode 100644 index 0000000..494029f --- /dev/null +++ b/gcc/config/sh/t-symbian @@ -0,0 +1,35 @@ +LIB1ASMSRC = sh/lib1funcs.asm +LIB1ASMFUNCS = _ashiftrt _ashiftrt_n _ashiftlt _lshiftrt _movstr \ + _movstr_i4 _mulsi3 _sdivsi3 _sdivsi3_i4 _udivsi3 _udivsi3_i4 _set_fpscr \ + $(LIB1ASMFUNCS_CACHE) + +# We want fine grained libraries, so use the new code to build the +# floating point emulation libraries. +FPBIT = fp-bit.c +DPBIT = dp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +$(T)crt1.o: $(srcdir)/config/sh/crt1.asm $(GCC_PASSES) + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crt1.o -x assembler-with-cpp $(srcdir)/config/sh/crt1.asm +$(T)crti.o: $(srcdir)/config/sh/crti.asm $(GCC_PASSES) + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/sh/crti.asm +$(T)crtn.o: $(srcdir)/config/sh/crtn.asm $(GCC_PASSES) + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/sh/crtn.asm + +$(out_object_file): gt-sh.h +gt-sh.h : s-gtype ; @true + +symbian.o: $(srcdir)/config/sh/symbian.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) output.h flags.h $(TREE_H) expr.h toplev.h $(TM_P_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/sh/symbian.c + + +# Local Variables: +# mode: Makefile +# End: diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4f9b9d9..1df0221 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2009,10 +2009,11 @@ types (@pxref{Variable Attributes}, @pxref{Type Attributes}.) @item dllexport @cindex @code{__declspec(dllexport)} -On Microsoft Windows targets the @code{dllexport} attribute causes the -compiler to provide a global pointer to a pointer in a dll, so that it -can be referenced with the @code{dllimport} attribute. The pointer name -is formed by combining @code{_imp__} and the function or variable name. +On Microsoft Windows targets and Symbian targets the @code{dllexport} +attribute causes the compiler to provide a global pointer to a pointer +in a dll, so that it can be referenced with the @code{dllimport} +attribute. The pointer name is formed by combining @code{_imp__} and +the function or variable name. Currently, the @code{dllexport}attribute is ignored for inlined functions, but export can be forced by using the @@ -2024,21 +2025,24 @@ member functions and static data members as exports. Static consts initialized in-class are not marked unless they are also defined out-of-class. -On cygwin, mingw and arm-pe targets, @code{__declspec(dllexport)} is -recognized as a synonym for @code{__attribute__ ((dllexport))} for -compatibility with other Microsoft Windows compilers. +On cygwin, mingw, arm-pe and sh-symbianelf targets, +@code{__declspec(dllexport)} is recognized as a synonym for +@code{__attribute__ ((dllexport))} for compatibility with other +Microsoft Windows and Symbian compilers. -Alternative methods for including the symbol in the dll's export table -are to use a .def file with an @code{EXPORTS} section or, with GNU ld, -using the @option{--export-all} linker flag. +For Microsoft Windows targets there are alternative methods for +including the symbol in the dll's export table such as using a +@file{.def} file with an @code{EXPORTS} section or, with GNU ld, using +the @option{--export-all} linker flag. @item dllimport @cindex @code{__declspec(dllimport)} -On Microsoft Windows targets, the @code{dllimport} attribute causes the -compiler to reference a function or variable via a global pointer to a -pointer that is set up by the Microsoft Windows dll library. The pointer -name is formed by combining @code{_imp__} and the function or variable -name. The attribute implies @code{extern} storage. +On Microsoft Windows and Symbian targets, the @code{dllimport} +attribute causes the compiler to reference a function or variable via +a global pointer to a pointer that is set up by the Microsoft Windows +dll library. The pointer name is formed by combining @code{_imp__} and +the function or variable name. The attribute implies @code{extern} +storage. Currently, the attribute is ignored for inlined functions. If the attribute is applied to a symbol @emph{definition}, an error is reported. @@ -2052,15 +2056,25 @@ member functions and static data members as imports. However, the attribute is ignored for virtual methods to allow creation of vtables using thunks. -On cygwin, mingw and arm-pe targets, @code{__declspec(dllimport)} is -recognized as a synonym for @code{__attribute__ ((dllimport))} for -compatibility with other Microsoft Windows compilers. +For Symbian targets the @code{dllimport} attribute also has another +affect - it can cause the vtable and run-time type information for a +class to be exported. This happens when the class has a dllimport'ed +constructor or a non-inline, non-pure virtual function and, for either +of those two conditions, the class also has a inline constructor or +destructor and has a key function that is defined in the current +translation unit. -The use of the @code{dllimport} attribute on functions is not necessary, -but provides a small performance benefit by eliminating a thunk in the -dll. The use of the @code{dllimport} attribute on imported variables was -required on older versions of GNU ld, but can now be avoided by passing -the @option{--enable-auto-import} switch to ld. As with functions, using +On cygwin, mingw, arm-pe sh-symbianelf targets, +@code{__declspec(dllimport)} is recognized as a synonym for +@code{__attribute__ ((dllimport))} for compatibility with other +Microsoft Windows and Symbian compilers. + +For Microsoft Windows based targets the use of the @code{dllimport} +attribute on functions is not necessary, but provides a small +performance benefit by eliminating a thunk in the dll. The use of the +@code{dllimport} attribute on imported variables was required on older +versions of GNU ld, but can now be avoided by passing the +@option{--enable-auto-import} switch to ld. As with functions, using the attribute for a variable eliminates a thunk in the dll. One drawback to using this attribute is that a pointer to a function or |