📄 winnt.c
字号:
/* Subroutines for insn-output.c for Windows NT. Contributed by Douglas Rupp (drupp@cs.washington.edu) Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.This file is part of GCC.GCC is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.GCC is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public Licensealong with GCC; see the file COPYING. If not, write to the FreeSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA02110-1301, USA. */#include "config.h"#include "system.h"#include "coretypes.h"#include "tm.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "output.h"#include "tree.h"#include "flags.h"#include "tm_p.h"#include "toplev.h"#include "hashtab.h"#include "ggc.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.*/static tree associated_type (tree);static tree gen_stdcall_or_fastcall_suffix (tree, bool);static bool i386_pe_dllexport_p (tree);static bool i386_pe_dllimport_p (tree);static void i386_pe_mark_dllexport (tree);static void i386_pe_mark_dllimport (tree);/* This is we how mark internal identifiers with dllimport or dllexport attributes. */#ifndef DLL_IMPORT_PREFIX#define DLL_IMPORT_PREFIX "#i."#endif#ifndef DLL_EXPORT_PREFIX#define DLL_EXPORT_PREFIX "#e."#endif/* Handle a "shared" attribute; arguments as in struct attribute_spec.handler. */treeix86_handle_shared_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, bool *no_add_attrs){ if (TREE_CODE (*node) != VAR_DECL) { warning (OPT_Wattributes, "%qs attribute only applies to variables", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE;}/* Handle a "selectany" attribute; arguments as in struct attribute_spec.handler. */treeix86_handle_selectany_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, bool *no_add_attrs){ /* The attribute applies only to objects that are initialized and have external linkage, */ if (TREE_CODE (*node) == VAR_DECL && TREE_PUBLIC (*node) && (DECL_INITIAL (*node) /* If an object is initialized with a ctor, the static initialization and destruction code for it is present in each unit defining the object. The code that calls the ctor is protected by a link-once guard variable, so that the object still has link-once semantics, */ || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (*node)))) make_decl_one_only (*node); else { error ("%qs attribute applies only to initialized variables" " with external linkage", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE;}/* Return the type that we should use to determine if DECL is imported or exported. */static treeassociated_type (tree decl){ return (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))) ? DECL_CONTEXT (decl) : NULL_TREE;}/* Return true if DECL is a dllexport'd object. */static booli386_pe_dllexport_p (tree decl){ if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return false; if (lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))) return true; /* Also mark class members of exported classes with dllexport. */ if (associated_type (decl) && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (associated_type (decl)))) return i386_pe_type_dllexport_p (decl); return false;}static booli386_pe_dllimport_p (tree decl){ if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return false; /* Lookup the attribute rather than rely on the DECL_DLLIMPORT_P flag. We may need to override an earlier decision. */ if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl))) return true; /* The DECL_DLLIMPORT_P flag was set for decls in the class definition by targetm.cxx.adjust_class_at_definition. Check again to emit warnings if the class attribute has been overriden by an out-of-class definition. */ if (associated_type (decl) && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (associated_type (decl)))) return i386_pe_type_dllimport_p (decl); return false;}/* Handle the -mno-fun-dllimport target switch. */booli386_pe_valid_dllimport_attribute_p (tree decl){ if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_DECL) return false; return true;}/* Return nonzero if SYMBOL is marked as being dllexport'd. */inti386_pe_dllexport_name_p (const char *symbol){ return (strncmp (DLL_EXPORT_PREFIX, symbol, strlen (DLL_EXPORT_PREFIX)) == 0);}/* Return nonzero if SYMBOL is marked as being dllimport'd. */inti386_pe_dllimport_name_p (const char *symbol){ return (strncmp (DLL_IMPORT_PREFIX, symbol, strlen (DLL_IMPORT_PREFIX)) == 0);}/* Mark a DECL as being dllexport'd. Note that we override the previous setting (e.g.: dllimport). */static voidi386_pe_mark_dllexport (tree decl){ const char *oldname; char *newname; rtx rtlname; rtx symref; tree idp; rtlname = XEXP (DECL_RTL (decl), 0); if (GET_CODE (rtlname) == MEM) rtlname = XEXP (rtlname, 0); gcc_assert (GET_CODE (rtlname) == SYMBOL_REF); oldname = XSTR (rtlname, 0); if (i386_pe_dllimport_name_p (oldname)) { warning (0, "inconsistent dll linkage for %q+D, dllexport assumed", decl); /* Remove DLL_IMPORT_PREFIX. */ oldname += strlen (DLL_IMPORT_PREFIX); } else if (i386_pe_dllexport_name_p (oldname)) return; /* already done */ newname = alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1); sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname); /* We pass newname through get_identifier to ensure it has a unique address. RTL processing can sometimes peek inside the symbol ref and compare the string's addresses to see if two symbols are identical. */ idp = get_identifier (newname); symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); SYMBOL_REF_DECL (symref) = decl; XEXP (DECL_RTL (decl), 0) = symref;}/* Mark a DECL as being dllimport'd. */static voidi386_pe_mark_dllimport (tree decl){ const char *oldname; char *newname; tree idp; rtx rtlname, newrtl; rtx symref; rtlname = XEXP (DECL_RTL (decl), 0); if (GET_CODE (rtlname) == MEM) rtlname = XEXP (rtlname, 0); gcc_assert (GET_CODE (rtlname) == SYMBOL_REF); oldname = XSTR (rtlname, 0); if (i386_pe_dllexport_name_p (oldname)) { error ("%qs declared as both exported to and imported from a DLL", IDENTIFIER_POINTER (DECL_NAME (decl))); return; } else if (i386_pe_dllimport_name_p (oldname)) { /* Already done, but do a sanity check to prevent assembler errors. */ gcc_assert (DECL_EXTERNAL (decl) && TREE_PUBLIC (decl) && DECL_DLLIMPORT_P (decl)); return; } newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1); sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname); /* We pass newname through get_identifier to ensure it has a unique address. RTL processing can sometimes peek inside the symbol ref and compare the string's addresses to see if two symbols are identical. */ idp = get_identifier (newname); symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); SYMBOL_REF_DECL (symref) = decl; newrtl = gen_rtx_MEM (Pmode,symref); XEXP (DECL_RTL (decl), 0) = newrtl; DECL_DLLIMPORT_P (decl) = 1;}/* Return string which is the former assembler name modified with a suffix consisting of an atsign (@) followed by the number of bytes of arguments. If FASTCALL is true, also add the FASTCALL_PREFIX. */static treegen_stdcall_or_fastcall_suffix (tree decl, bool fastcall){ int total = 0; /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead of DECL_ASSEMBLER_NAME. */ const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); char *newsym; char *p; tree formal_type; /* Do not change the identifier if a verbatim asmspec or already done. */ if (*asmname == '*' || strchr (asmname, '@')) return DECL_ASSEMBLER_NAME (decl); formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl)); if (formal_type != NULL_TREE) { /* These attributes are ignored for variadic functions in i386.c:ix86_return_pops_args. For compatibility with MS compiler do not add @0 suffix here. */ if (TREE_VALUE (tree_last (formal_type)) != void_type_node) return DECL_ASSEMBLER_NAME (decl); /* Quit if we hit an incomplete type. Error is reported by convert_arguments in c-typeck.c or cp/typeck.c. */ while (TREE_VALUE (formal_type) != void_type_node && COMPLETE_TYPE_P (TREE_VALUE (formal_type))) { int parm_size = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type))); /* Must round up to include padding. This is done the same way as in store_one_arg. */ parm_size = ((parm_size + PARM_BOUNDARY - 1) / PARM_BOUNDARY * PARM_BOUNDARY); total += parm_size; formal_type = TREE_CHAIN (formal_type);\ } } /* Assume max of 8 base 10 digits in the suffix. */ newsym = alloca (1 + strlen (asmname) + 1 + 8 + 1); p = newsym; if (fastcall) *p++ = FASTCALL_PREFIX; sprintf (p, "%s@%d", asmname, total/BITS_PER_UNIT); return get_identifier (newsym);}voidi386_pe_encode_section_info (tree decl, rtx rtl, int first){ default_encode_section_info (decl, rtl, first); if (first && TREE_CODE (decl) == FUNCTION_DECL) { tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl)); tree newid = NULL_TREE; if (lookup_attribute ("stdcall", type_attributes)) newid = gen_stdcall_or_fastcall_suffix (decl, false); else if (lookup_attribute ("fastcall", type_attributes)) newid = gen_stdcall_or_fastcall_suffix (decl, true); if (newid != NULL_TREE) { rtx rtlname = XEXP (rtl, 0); if (GET_CODE (rtlname) == MEM) rtlname = XEXP (rtlname, 0); XSTR (rtlname, 0) = IDENTIFIER_POINTER (newid); /* These attributes must be present on first declaration, change_decl_assembler_name will warn if they are added later and the decl has been referenced, but duplicate_decls
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -