pe.c revision 132718
190075Sobrien/* Routines for GCC for ARM/pe.
2117395Skan   Copyright (C) 1995, 1996, 2000, 2001, 2002 Free Software Foundation, Inc.
390075Sobrien   Contributed by Doug Evans (dje@cygnus.com).
490075Sobrien
5132718Skan   This file is part of GCC.
690075Sobrien
7132718Skan   GCC is free software; you can redistribute it and/or modify it
8132718Skan   under the terms of the GNU General Public License as published
9132718Skan   by the Free Software Foundation; either version 2, or (at your
10132718Skan   option) any later version.
1190075Sobrien
12132718Skan   GCC is distributed in the hope that it will be useful, but WITHOUT
13132718Skan   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14132718Skan   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15132718Skan   License for more details.
1690075Sobrien
17132718Skan   You should have received a copy of the GNU General Public License
18132718Skan   along with GCC; see the file COPYING.  If not, write to
19132718Skan   the Free Software Foundation, 59 Temple Place - Suite 330,
20132718Skan   Boston, MA 02111-1307, USA.  */
2190075Sobrien
2290075Sobrien#include "config.h"
2390075Sobrien#include "system.h"
24132718Skan#include "coretypes.h"
25132718Skan#include "tm.h"
2690075Sobrien#include "rtl.h"
2790075Sobrien#include "output.h"
2890075Sobrien#include "flags.h"
2990075Sobrien#include "tree.h"
3090075Sobrien#include "expr.h"
3190075Sobrien#include "toplev.h"
3290075Sobrien#include "tm_p.h"
3390075Sobrien
3490075Sobrienextern int current_function_anonymous_args;
3590075Sobrien
3690075Sobrien
37117395Skan/* Return nonzero if DECL is a dllexport'd object.  */
3890075Sobrien
3990075Sobrientree current_class_type; /* FIXME */
4090075Sobrien
4190075Sobrienint
4290075Sobrienarm_dllexport_p (decl)
4390075Sobrien     tree decl;
4490075Sobrien{
4590075Sobrien  tree exp;
4690075Sobrien
4790075Sobrien  if (TREE_CODE (decl) != VAR_DECL
4890075Sobrien      && TREE_CODE (decl) != FUNCTION_DECL)
4990075Sobrien    return 0;
5090075Sobrien  exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
5190075Sobrien  if (exp)
5290075Sobrien    return 1;
5390075Sobrien
5490075Sobrien  return 0;
5590075Sobrien}
5690075Sobrien
57117395Skan/* Return nonzero if DECL is a dllimport'd object.  */
5890075Sobrien
5990075Sobrienint
6090075Sobrienarm_dllimport_p (decl)
6190075Sobrien     tree decl;
6290075Sobrien{
6390075Sobrien  tree imp;
6490075Sobrien
6590075Sobrien  if (TREE_CODE (decl) == FUNCTION_DECL
6690075Sobrien      && TARGET_NOP_FUN_DLLIMPORT)
6790075Sobrien    return 0;
6890075Sobrien
6990075Sobrien  if (TREE_CODE (decl) != VAR_DECL
7090075Sobrien      && TREE_CODE (decl) != FUNCTION_DECL)
7190075Sobrien    return 0;
7290075Sobrien  imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
7390075Sobrien  if (imp)
7490075Sobrien    return 1;
7590075Sobrien
7690075Sobrien  return 0;
7790075Sobrien}
7890075Sobrien
79117395Skan/* Return nonzero if SYMBOL is marked as being dllexport'd.  */
8090075Sobrien
8190075Sobrienint
8290075Sobrienarm_dllexport_name_p (symbol)
8390075Sobrien     const char * symbol;
8490075Sobrien{
8590075Sobrien  return symbol[0] == ARM_PE_FLAG_CHAR && symbol[1] == 'e' && symbol[2] == '.';
8690075Sobrien}
8790075Sobrien
88117395Skan/* Return nonzero if SYMBOL is marked as being dllimport'd.  */
8990075Sobrien
9090075Sobrienint
9190075Sobrienarm_dllimport_name_p (symbol)
9290075Sobrien     const char * symbol;
9390075Sobrien{
9490075Sobrien  return symbol[0] == ARM_PE_FLAG_CHAR && symbol[1] == 'i' && symbol[2] == '.';
9590075Sobrien}
9690075Sobrien
9790075Sobrien/* Mark a DECL as being dllexport'd.
9890075Sobrien   Note that we override the previous setting (eg: dllimport).  */
9990075Sobrien
10090075Sobrienvoid
10190075Sobrienarm_mark_dllexport (decl)
10290075Sobrien     tree decl;
10390075Sobrien{
10490075Sobrien  const char * oldname;
10590075Sobrien  char * newname;
10690075Sobrien  rtx rtlname;
10790075Sobrien  tree idp;
10890075Sobrien
10990075Sobrien  rtlname = XEXP (DECL_RTL (decl), 0);
11090075Sobrien  if (GET_CODE (rtlname) == SYMBOL_REF)
11190075Sobrien    oldname = XSTR (rtlname, 0);
11290075Sobrien  else if (GET_CODE (rtlname) == MEM
11390075Sobrien	   && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
11490075Sobrien    oldname = XSTR (XEXP (rtlname, 0), 0);
11590075Sobrien  else
11690075Sobrien    abort ();
11790075Sobrien  if (arm_dllimport_name_p (oldname))
11890075Sobrien    oldname += 9;
11990075Sobrien  else if (arm_dllexport_name_p (oldname))
12090075Sobrien    return; /* already done */
12190075Sobrien
12290075Sobrien  newname = alloca (strlen (oldname) + 4);
12390075Sobrien  sprintf (newname, "%ce.%s", ARM_PE_FLAG_CHAR, oldname);
12490075Sobrien
12590075Sobrien  /* We pass newname through get_identifier to ensure it has a unique
12690075Sobrien     address.  RTL processing can sometimes peek inside the symbol ref
12790075Sobrien     and compare the string's addresses to see if two symbols are
12890075Sobrien     identical.  */
12990075Sobrien  /* ??? At least I think that's why we do this.  */
13090075Sobrien  idp = get_identifier (newname);
13190075Sobrien
13290075Sobrien  XEXP (DECL_RTL (decl), 0) =
13390075Sobrien    gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
13490075Sobrien}
13590075Sobrien
13690075Sobrien/* Mark a DECL as being dllimport'd.  */
13790075Sobrien
13890075Sobrienvoid
13990075Sobrienarm_mark_dllimport (decl)
14090075Sobrien     tree decl;
14190075Sobrien{
14290075Sobrien  const char * oldname;
14390075Sobrien  char * newname;
14490075Sobrien  tree idp;
14590075Sobrien  rtx rtlname, newrtl;
14690075Sobrien
14790075Sobrien  rtlname = XEXP (DECL_RTL (decl), 0);
14890075Sobrien
14990075Sobrien  if (GET_CODE (rtlname) == SYMBOL_REF)
15090075Sobrien    oldname = XSTR (rtlname, 0);
15190075Sobrien  else if (GET_CODE (rtlname) == MEM
15290075Sobrien	   && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
15390075Sobrien    oldname = XSTR (XEXP (rtlname, 0), 0);
15490075Sobrien  else
15590075Sobrien    abort ();
15690075Sobrien
15790075Sobrien  if (arm_dllexport_name_p (oldname))
15890075Sobrien    abort (); /* this shouldn't happen */
15990075Sobrien  else if (arm_dllimport_name_p (oldname))
16090075Sobrien    return; /* already done */
16190075Sobrien
16290075Sobrien  /* ??? One can well ask why we're making these checks here,
16390075Sobrien     and that would be a good question.  */
16490075Sobrien
16590075Sobrien  /* Imported variables can't be initialized.  */
16690075Sobrien  if (TREE_CODE (decl) == VAR_DECL
16790075Sobrien      && !DECL_VIRTUAL_P (decl)
16890075Sobrien      && DECL_INITIAL (decl))
16990075Sobrien    {
170132718Skan      error ("%Jinitialized variable '%D' is marked dllimport", decl, decl);
17190075Sobrien      return;
17290075Sobrien    }
17390075Sobrien  /* Nor can they be static.  */
17490075Sobrien  if (TREE_CODE (decl) == VAR_DECL
17590075Sobrien      /* ??? Is this test for vtables needed?  */
17690075Sobrien      && !DECL_VIRTUAL_P (decl)
17790075Sobrien      && 0 /*???*/)
17890075Sobrien    {
179132718Skan      error ("%Jstatic variable '%D' is marked dllimport", decl, decl);
18090075Sobrien      return;
18190075Sobrien    }
18290075Sobrien
18390075Sobrien  /* `extern' needn't be specified with dllimport.
18490075Sobrien     Specify `extern' now and hope for the best.  Sigh.  */
18590075Sobrien  if (TREE_CODE (decl) == VAR_DECL
18690075Sobrien      /* ??? Is this test for vtables needed?  */
18790075Sobrien      && !DECL_VIRTUAL_P (decl))
18890075Sobrien    {
18990075Sobrien      DECL_EXTERNAL (decl) = 1;
19090075Sobrien      TREE_PUBLIC (decl) = 1;
19190075Sobrien    }
19290075Sobrien
19390075Sobrien  newname = alloca (strlen (oldname) + 11);
19490075Sobrien  sprintf (newname, "%ci.__imp_%s", ARM_PE_FLAG_CHAR, oldname);
19590075Sobrien
19690075Sobrien  /* We pass newname through get_identifier to ensure it has a unique
19790075Sobrien     address.  RTL processing can sometimes peek inside the symbol ref
19890075Sobrien     and compare the string's addresses to see if two symbols are
19990075Sobrien     identical.  */
20090075Sobrien  /* ??? At least I think that's why we do this.  */
20190075Sobrien  idp = get_identifier (newname);
20290075Sobrien
20390075Sobrien  newrtl = gen_rtx (MEM, Pmode,
20490075Sobrien		    gen_rtx (SYMBOL_REF, Pmode,
20590075Sobrien			     IDENTIFIER_POINTER (idp)));
20690075Sobrien  XEXP (DECL_RTL (decl), 0) = newrtl;
20790075Sobrien}
20890075Sobrien
20990075Sobrienvoid
210132718Skanarm_pe_encode_section_info (decl, rtl, first)
21190075Sobrien     tree decl;
212132718Skan     rtx rtl;
213117395Skan     int first ATTRIBUTE_UNUSED;
21490075Sobrien{
215117395Skan  /* This bit is copied from arm_encode_section_info.  */
21690075Sobrien  if (optimize > 0 && TREE_CONSTANT (decl)
21790075Sobrien      && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
218132718Skan    SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
21990075Sobrien
22090075Sobrien  /* Mark the decl so we can tell from the rtl whether the object is
22190075Sobrien     dllexport'd or dllimport'd.  */
22290075Sobrien  if (arm_dllexport_p (decl))
22390075Sobrien    arm_mark_dllexport (decl);
22490075Sobrien  else if (arm_dllimport_p (decl))
22590075Sobrien    arm_mark_dllimport (decl);
22690075Sobrien  /* It might be that DECL has already been marked as dllimport, but a
22790075Sobrien     subsequent definition nullified that.  The attribute is gone but
22890075Sobrien     DECL_RTL still has @i.__imp_foo.  We need to remove that.  */
22990075Sobrien  else if ((TREE_CODE (decl) == FUNCTION_DECL
23090075Sobrien	    || TREE_CODE (decl) == VAR_DECL)
23190075Sobrien	   && DECL_RTL (decl) != NULL_RTX
23290075Sobrien	   && GET_CODE (DECL_RTL (decl)) == MEM
23390075Sobrien	   && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
23490075Sobrien	   && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
23590075Sobrien	   && arm_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
23690075Sobrien    {
23790075Sobrien      const char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
23890075Sobrien      tree idp = get_identifier (oldname + 9);
23990075Sobrien      rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
24090075Sobrien
24190075Sobrien      XEXP (DECL_RTL (decl), 0) = newrtl;
24290075Sobrien
24390075Sobrien      /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
24490075Sobrien	 ??? We leave these alone for now.  */
24590075Sobrien    }
24690075Sobrien}
24790075Sobrien
24890075Sobrienvoid
24990075Sobrienarm_pe_unique_section (decl, reloc)
25090075Sobrien     tree decl;
25190075Sobrien     int reloc;
25290075Sobrien{
25390075Sobrien  int len;
25490075Sobrien  const char * name;
25590075Sobrien  char * string;
25690075Sobrien  const char * prefix;
25790075Sobrien
25890075Sobrien  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
259117395Skan  name = arm_strip_name_encoding (name);
26090075Sobrien
26190075Sobrien  /* The object is put in, for example, section .text$foo.
26290075Sobrien     The linker will then ultimately place them in .text
26390075Sobrien     (everything from the $ on is stripped).  */
26490075Sobrien  if (TREE_CODE (decl) == FUNCTION_DECL)
26590075Sobrien    prefix = ".text$";
266117395Skan  else if (decl_readonly_section (decl, reloc))
26790075Sobrien    prefix = ".rdata$";
26890075Sobrien  else
26990075Sobrien    prefix = ".data$";
27090075Sobrien  len = strlen (name) + strlen (prefix);
27190075Sobrien  string = alloca (len + 1);
27290075Sobrien  sprintf (string, "%s%s", prefix, name);
27390075Sobrien
27490075Sobrien  DECL_SECTION_NAME (decl) = build_string (len, string);
27590075Sobrien}
276