1/* SOM object file format.
2   Copyright (C) 1993-2017 Free Software Foundation, Inc.
3
4   This file is part of GAS, the GNU Assembler.
5
6   GAS is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as
8   published by the Free Software Foundation; either version 3,
9   or (at your option) any later version.
10
11   GAS is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14   the GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with GAS; see the file COPYING.  If not, write to the Free
18   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19   02110-1301, USA.
20
21   Written by the Center for Software Science at the University of Utah
22   and by Cygnus Support.  */
23
24#include "as.h"
25#include "subsegs.h"
26#include "aout/stab_gnu.h"
27
28static int version_seen = 0;
29static int copyright_seen = 0;
30static int compiler_seen = 0;
31
32/* Unused by SOM.  */
33
34void
35obj_read_begin_hook (void)
36{
37}
38
39/* Handle a .compiler directive.   This is intended to create the
40   compilation unit auxiliary header for MPE such that the linkeditor
41   can handle SOM extraction from archives. The format of the quoted
42   string is "sourcefile language version" and is delimited by blanks.  */
43
44void
45obj_som_compiler (int unused ATTRIBUTE_UNUSED)
46{
47  char *buf;
48  char c;
49  char *filename;
50  char *language_name;
51  char *p;
52  char *version_id;
53
54  if (compiler_seen)
55    {
56      as_bad (_("Only one .compiler pseudo-op per file!"));
57      ignore_rest_of_line ();
58      return;
59    }
60
61  SKIP_WHITESPACE ();
62  if (*input_line_pointer == '\"')
63    {
64      buf = input_line_pointer;
65      ++input_line_pointer;
66      while (is_a_char (next_char_of_string ()))
67	;
68      c = *input_line_pointer;
69      *input_line_pointer = '\000';
70    }
71  else
72    {
73      as_bad (_("Expected quoted string"));
74      ignore_rest_of_line ();
75      return;
76    }
77
78  /* Parse the quoted string into its component parts.  Skip the
79     quote.  */
80  filename = buf + 1;
81  p = filename;
82  while (*p != ' ' && *p != '\000')
83    p++;
84  if (*p == '\000')
85    {
86      as_bad (_(".compiler directive missing language and version"));
87      return;
88    }
89  *p = '\000';
90
91  language_name = ++p;
92  while (*p != ' ' && *p != '\000')
93    p++;
94  if (*p == '\000')
95    {
96      as_bad (_(".compiler directive missing version"));
97      return;
98    }
99  *p = '\000';
100
101  version_id = ++p;
102  while (*p != '\000')
103    p++;
104  /* Remove the trailing quote.  */
105  *(--p) = '\000';
106
107  compiler_seen = 1;
108  if (! bfd_som_attach_compilation_unit (stdoutput, filename, language_name,
109					 "GNU Tools", version_id))
110    {
111      bfd_perror (stdoutput->filename);
112      as_fatal (_("FATAL: Attaching compiler header %s"), stdoutput->filename);
113    }
114  *input_line_pointer = c;
115  demand_empty_rest_of_line ();
116}
117
118/* Handle a .version directive.  */
119
120void
121obj_som_version (int unused ATTRIBUTE_UNUSED)
122{
123  char *version, c;
124
125  if (version_seen)
126    {
127      as_bad (_("Only one .version pseudo-op per file!"));
128      ignore_rest_of_line ();
129      return;
130    }
131
132  SKIP_WHITESPACE ();
133  if (*input_line_pointer == '\"')
134    {
135      version = input_line_pointer;
136      ++input_line_pointer;
137      while (is_a_char (next_char_of_string ()))
138	;
139      c = *input_line_pointer;
140      *input_line_pointer = '\000';
141    }
142  else
143    {
144      as_bad (_("Expected quoted string"));
145      ignore_rest_of_line ();
146      return;
147    }
148
149  version_seen = 1;
150  if (!bfd_som_attach_aux_hdr (stdoutput, VERSION_AUX_ID, version))
151    as_fatal (_("attaching version header %s: %s"),
152	      stdoutput->filename, bfd_errmsg (bfd_get_error ()));
153
154  *input_line_pointer = c;
155  demand_empty_rest_of_line ();
156}
157
158/* Handle a .copyright directive.   This probably isn't complete, but
159   it's of dubious value anyway and (IMHO) not worth the time to finish.
160   If you care about copyright strings that much, you fix it.  */
161
162void
163obj_som_copyright (int unused ATTRIBUTE_UNUSED)
164{
165  char *copyright, c;
166
167  if (copyright_seen)
168    {
169      as_bad (_("Only one .copyright pseudo-op per file!"));
170      ignore_rest_of_line ();
171      return;
172    }
173
174  SKIP_WHITESPACE ();
175  if (*input_line_pointer == '\"')
176    {
177      copyright = input_line_pointer;
178      ++input_line_pointer;
179      while (is_a_char (next_char_of_string ()))
180	;
181      c = *input_line_pointer;
182      *input_line_pointer = '\000';
183    }
184  else
185    {
186      as_bad (_("Expected quoted string"));
187      ignore_rest_of_line ();
188      return;
189    }
190
191  copyright_seen = 1;
192  if (!bfd_som_attach_aux_hdr (stdoutput, COPYRIGHT_AUX_ID, copyright))
193    as_fatal (_("attaching copyright header %s: %s"),
194	      stdoutput->filename, bfd_errmsg (bfd_get_error ()));
195
196  *input_line_pointer = c;
197  demand_empty_rest_of_line ();
198}
199
200/* Perform any initialization necessary for stabs support.
201
202   For SOM we need to create the space which will contain the
203   two stabs subspaces.  Additionally we need to set up the
204   space/subspace relationships and set space/subspace attributes
205   which BFD does not understand.  */
206
207void
208obj_som_init_stab_section (segT seg)
209{
210  segT saved_seg = now_seg;
211  segT space;
212  subsegT saved_subseg = now_subseg;
213  char *p;
214 const char * file;
215  unsigned int stroff;
216
217  /* Make the space which will contain the debug subspaces.  */
218  space = bfd_make_section_old_way (stdoutput, "$GDB_DEBUG$");
219
220  /* Set SOM specific attributes for the space.  In particular we set
221     the space "defined", "private", "sort_key", and "spnum" values.
222
223     Due to a bug in pxdb (called by hpux linker), the sort keys
224     of the various stabs spaces/subspaces need to be "small".  We
225     reserve range 72/73 which appear to work well.  */
226  obj_set_section_attributes (space, 1, 1, 72, 2);
227  bfd_set_section_alignment (stdoutput, space, 2);
228
229  /* Set the containing space for both stab sections to be $GDB_DEBUG$
230     (just created above).  Also set some attributes which BFD does
231     not understand.  In particular, access bits, sort keys, and load
232     quadrant.  */
233  obj_set_subsection_attributes (seg, space, 0x1f, 73, 0, 0, 0, 0);
234  bfd_set_section_alignment (stdoutput, seg, 2);
235
236  /* Make some space for the first special stab entry and zero the memory.
237     It contains information about the length of this file's
238     stab string and the like.  Using it avoids the need to
239     relocate the stab strings.
240
241     The $GDB_STRINGS$ space will be created as a side effect of
242     the call to get_stab_string_offset.  */
243  p = frag_more (12);
244  memset (p, 0, 12);
245  file = as_where ((unsigned int *) NULL);
246  stroff = get_stab_string_offset (file, "$GDB_STRINGS$");
247  know (stroff == 1);
248  md_number_to_chars (p, stroff, 4);
249  seg_info (seg)->stabu.p = p;
250
251  /* Set the containing space for both stab sections to be $GDB_DEBUG$
252     (just created above).  Also set some attributes which BFD does
253     not understand.  In particular, access bits, sort keys, and load
254     quadrant.  */
255  seg = bfd_get_section_by_name (stdoutput, "$GDB_STRINGS$");
256  obj_set_subsection_attributes (seg, space, 0x1f, 72, 0, 0, 0, 0);
257  bfd_set_section_alignment (stdoutput, seg, 2);
258
259  subseg_set (saved_seg, saved_subseg);
260}
261
262/* Fill in the counts in the first entry in a .stabs section.  */
263
264static void
265adjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
266{
267  asection *strsec;
268  char *p;
269  int strsz, nsyms;
270
271  if (strcmp ("$GDB_SYMBOLS$", sec->name))
272    return;
273
274  strsec = bfd_get_section_by_name (abfd, "$GDB_STRINGS$");
275  if (strsec)
276    strsz = bfd_section_size (abfd, strsec);
277  else
278    strsz = 0;
279  nsyms = bfd_section_size (abfd, sec) / 12 - 1;
280
281  p = seg_info (sec)->stabu.p;
282  gas_assert (p != 0);
283
284  bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6);
285  bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8);
286}
287
288/* Called late in the assembly phase to adjust the special
289   stab entry and to set the starting address for each code subspace.  */
290
291void
292som_frob_file (void)
293{
294  bfd_map_over_sections (stdoutput, adjust_stab_sections, (void *) 0);
295}
296
297static void
298obj_som_weak (int ignore ATTRIBUTE_UNUSED)
299{
300  char *name;
301  int c;
302  symbolS *symbolP;
303
304  do
305    {
306      c = get_symbol_name (&name);
307      symbolP = symbol_find_or_make (name);
308      *input_line_pointer = c;
309      SKIP_WHITESPACE_AFTER_NAME ();
310      S_SET_WEAK (symbolP);
311      if (c == ',')
312	{
313	  input_line_pointer++;
314	  SKIP_WHITESPACE ();
315	  if (*input_line_pointer == '\n')
316	    c = '\n';
317	}
318    }
319  while (c == ',');
320  demand_empty_rest_of_line ();
321}
322
323const pseudo_typeS obj_pseudo_table[] =
324{
325  {"weak", obj_som_weak, 0},
326  {NULL, NULL, 0}
327};
328