📄 symbian.c
字号:
/* 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 treesh_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. */boolsh_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 boolsh_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. */boolsh_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. */boolsh_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 (e.g.: dllimport). */static voidsh_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 definition to be marked as dllexport. The prototypes are in headers used everywhere and the definition 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 voidsh_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 ("%qs 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; }}voidsh_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 intsh_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 voidsymbian_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. */treesh_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 ("%qs 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 ("%qs 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 %qD 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -