summaryrefslogtreecommitdiff
path: root/gcc/config/sol2.c
blob: b15b895c70feb191412ffe1ad406f02ae3dd1e9e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/* General Solaris system support.
   Copyright (C) 2004, 2005 , 2007, 2010, 2011, 2012
   Free Software Foundation, Inc.
   Contributed by CodeSourcery, LLC.

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 3, 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 COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "output.h"
#include "tm.h"
#include "rtl.h"
#include "target.h"
#include "tm_p.h"
#include "diagnostic-core.h"
#include "ggc.h"
#include "hashtab.h"

tree solaris_pending_aligns, solaris_pending_inits, solaris_pending_finis;

/* Attach any pending attributes for DECL to the list in *ATTRIBUTES.
   Pending attributes come from #pragma or _Pragma, so this code is
   only useful in the C family front ends, but it is included in
   all languages to avoid changing the target machine initializer
   depending on the language.  */

void
solaris_insert_attributes (tree decl, tree *attributes)
{
  tree *x, next;

  if (solaris_pending_aligns != NULL && TREE_CODE (decl) == VAR_DECL)
    for (x = &solaris_pending_aligns; *x; x = &TREE_CHAIN (*x))
      {
	tree name = TREE_PURPOSE (*x);
	tree value = TREE_VALUE (*x);
	if (DECL_NAME (decl) == name)
	  {
	    if (lookup_attribute ("aligned", DECL_ATTRIBUTES (decl))
		|| lookup_attribute ("aligned", *attributes))
	      warning (0, "ignoring %<#pragma align%> for explicitly "
		       "aligned %q+D", decl);
	    else
	      *attributes = tree_cons (get_identifier ("aligned"), value,
				       *attributes);
	    next = TREE_CHAIN (*x);
	    ggc_free (*x);
	    *x = next;
	    break;
	  }
      }

  if (solaris_pending_inits != NULL && TREE_CODE (decl) == FUNCTION_DECL)
    for (x = &solaris_pending_inits; *x; x = &TREE_CHAIN (*x))
      {
	tree name = TREE_PURPOSE (*x);
	if (DECL_NAME (decl) == name)
	  {
	    *attributes = tree_cons (get_identifier ("init"), NULL,
				     *attributes);
	    TREE_USED (decl) = 1;
	    DECL_PRESERVE_P (decl) = 1;
	    next = TREE_CHAIN (*x);
	    ggc_free (*x);
	    *x = next;
	    break;
	  }
      }

  if (solaris_pending_finis != NULL && TREE_CODE (decl) == FUNCTION_DECL)
    for (x = &solaris_pending_finis; *x; x = &TREE_CHAIN (*x))
      {
	tree name = TREE_PURPOSE (*x);
	if (DECL_NAME (decl) == name)
	  {
	    *attributes = tree_cons (get_identifier ("fini"), NULL,
				     *attributes);
	    TREE_USED (decl) = 1;
	    DECL_PRESERVE_P (decl) = 1;
	    next = TREE_CHAIN (*x);
	    ggc_free (*x);
	    *x = next;
	    break;
	  }
      }
}

/* Output initializer or finalizer entries for DECL to FILE.  */

void
solaris_output_init_fini (FILE *file, tree decl)
{
  if (lookup_attribute ("init", DECL_ATTRIBUTES (decl)))
    {
      fprintf (file, "\t.pushsection\t" SECTION_NAME_FORMAT "\n", ".init");
      ASM_OUTPUT_CALL (file, decl);
      fprintf (file, "\t.popsection\n");
    }

  if (lookup_attribute ("fini", DECL_ATTRIBUTES (decl)))
    {
      fprintf (file, "\t.pushsection\t" SECTION_NAME_FORMAT "\n", ".fini");
      ASM_OUTPUT_CALL (file, decl);
      fprintf (file, "\t.popsection\n");
    }
}

/* Emit an assembler directive to set symbol for DECL visibility to
   the visibility type VIS, which must not be VISIBILITY_DEFAULT.  */

void
solaris_assemble_visibility (tree decl ATTRIBUTE_UNUSED,
			     int vis ATTRIBUTE_UNUSED)
{
#ifdef HAVE_GAS_HIDDEN
  /* Sun as uses .symbolic for STV_PROTECTED.  STV_INTERNAL is marked as
     `currently reserved', but the linker treats it like STV_HIDDEN.  Sun
     Studio 12.1 cc emits .hidden instead.

     There are 3 Sun extensions GCC doesn't yet know about: STV_EXPORTED,
     STV_SINGLETON, and STV_ELIMINATE.

     See Linker and Libraries Guide, Ch. 2, Link-Editor, Defining
     Additional Symbols, and Ch. 7, Object-File Format, Symbol Table
     Section.  */

  static const char * const visibility_types[] = {
    NULL, "symbolic", "hidden", "hidden"
  };

  const char *name, *type;

  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
  type = visibility_types[vis];

  fprintf (asm_out_file, "\t.%s\t", type);
  assemble_name (asm_out_file, name);
  fprintf (asm_out_file, "\n");
#else
  warning (OPT_Wattributes, "visibility attribute not supported "
	   "in this configuration; ignored");
#endif
}

/* Hash table of group signature symbols.  */

static htab_t solaris_comdat_htab;

/* Group section information entry stored in solaris_comdat_htab.  */

typedef struct comdat_entry
{
  const char *name;
  unsigned int flags;
  tree decl;
  const char *sig;
} comdat_entry;

/* Helper routines for maintaining solaris_comdat_htab.  */

static hashval_t
comdat_hash (const void *p)
{
  const comdat_entry *entry = (const comdat_entry *) p;

  return htab_hash_string (entry->sig);
}

static int
comdat_eq (const void *p1, const void *p2)
{
  const comdat_entry *entry1 = (const comdat_entry *) p1;
  const comdat_entry *entry2 = (const comdat_entry *) p2;

  return strcmp (entry1->sig, entry2->sig) == 0;
}

/* Output assembly to switch to COMDAT group section NAME with attributes
   FLAGS and group signature symbol DECL, using Sun as syntax.  */

void
solaris_elf_asm_comdat_section (const char *name, unsigned int flags, tree decl)
{
  const char *signature;
  char *section;
  comdat_entry entry, **slot;

  if (TREE_CODE (decl) == IDENTIFIER_NODE)
    signature = IDENTIFIER_POINTER (decl);
  else
    signature = IDENTIFIER_POINTER (DECL_COMDAT_GROUP (decl));

  /* Sun as requires group sections to be fragmented, i.e. to have names of
     the form <section>%<fragment>.  Strictly speaking this is only
     necessary to support cc -xF, but is enforced globally in violation of
     the ELF gABI.  We keep the section names generated by GCC (generally
     of the form .text.<signature>) and append %<signature> to pacify as,
     despite the redundancy.  */
  section = concat (name, "%", signature, NULL);

  /* Clear SECTION_LINKONCE flag so targetm.asm_out.named_section only
     emits this as a regular section.  Emit section before .group
     directive since Sun as treats undeclared sections as @progbits,
     which conflicts with .bss* sections which are @nobits.  */
  targetm.asm_out.named_section (section, flags & ~SECTION_LINKONCE, decl);
  
  /* Sun as separates declaration of a group section and of the group
     itself, using the .group directive and the #comdat flag.  */
  fprintf (asm_out_file, "\t.group\t%s," SECTION_NAME_FORMAT ",#comdat\n",
	   signature, section);

  /* Unlike GNU as, group signature symbols need to be defined explicitly
     for Sun as.  With a few exceptions, this is already the case.  To
     identify the missing ones without changing the affected frontents,
     remember the signature symbols and emit those not marked
     TREE_SYMBOL_REFERENCED in solaris_file_end.  */
  if (solaris_comdat_htab == NULL)
    solaris_comdat_htab = htab_create_alloc (37, comdat_hash, comdat_eq, NULL,
					     xcalloc, free);

  entry.sig = signature;
  slot = (comdat_entry **) htab_find_slot (solaris_comdat_htab, &entry, INSERT);

  if (*slot == NULL)
    {
      *slot = XCNEW (comdat_entry);
      /* Remember fragmented section name.  */
      (*slot)->name = section;
      /* Emit as regular section, .group declaration has already been done.  */
      (*slot)->flags = flags & ~SECTION_LINKONCE;
      (*slot)->decl = decl;
      (*slot)->sig = signature;
    }
}

/* Define unreferenced COMDAT group signature symbol corresponding to SLOT.  */

static int
solaris_define_comdat_signature (void **slot, void *aux ATTRIBUTE_UNUSED)
{
  comdat_entry *entry = *(comdat_entry **) slot;
  tree decl = entry->decl;

  if (TREE_CODE (decl) != IDENTIFIER_NODE)
    decl = DECL_COMDAT_GROUP (decl);

  if (!TREE_SYMBOL_REFERENCED (decl))
    {
      /* Switch to group section, otherwise Sun as complains
	 `Group Id symbol defined outside of group'.  */
      switch_to_section (get_section (entry->name, entry->flags, entry->decl));

      ASM_OUTPUT_LABEL (asm_out_file, entry->sig);
    }

  /* Continue with scan.  */
  return 1;
}

/* Emit unreferenced COMDAT group signature symbols for Sun as.  */

void
solaris_file_end (void)
{
  if (solaris_comdat_htab == NULL)
    return;

  htab_traverse (solaris_comdat_htab, solaris_define_comdat_signature, NULL);
}

void
solaris_override_options (void)
{
  /* Don't emit DWARF3/4 unless specifically selected.  Solaris ld cannot
     handle CIE version 3 in .eh_frame.  */
  if (!global_options_set.x_dwarf_version)
    dwarf_version = 2;
}