1/* SOM object file format.
2   Copyright (C) 1993-2022 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  /* Nothing to do if the section has already been created.  */
218  if (bfd_get_section_by_name (stdoutput, "$GDB_DEBUG$"))
219    return;
220
221  /* Make the space which will contain the debug subspaces.  */
222  space = bfd_make_section_old_way (stdoutput, "$GDB_DEBUG$");
223
224  /* Set SOM specific attributes for the space.  In particular we set
225     the space "defined", "private", "sort_key", and "spnum" values.
226
227     Due to a bug in pxdb (called by hpux linker), the sort keys
228     of the various stabs spaces/subspaces need to be "small".  We
229     reserve range 72/73 which appear to work well.  */
230  obj_set_section_attributes (space, 1, 1, 72, 2);
231  bfd_set_section_alignment (space, 2);
232
233  /* Set the containing space for both stab sections to be $GDB_DEBUG$
234     (just created above).  Also set some attributes which BFD does
235     not understand.  In particular, access bits, sort keys, and load
236     quadrant.  */
237  obj_set_subsection_attributes (seg, space, 0x1f, 73, 0, 0, 0, 0);
238  bfd_set_section_alignment (seg, 2);
239
240  /* Make some space for the first special stab entry and zero the memory.
241     It contains information about the length of this file's
242     stab string and the like.  Using it avoids the need to
243     relocate the stab strings.
244
245     The $GDB_STRINGS$ space will be created as a side effect of
246     the call to get_stab_string_offset.  */
247  p = frag_more (12);
248  memset (p, 0, 12);
249  file = as_where ((unsigned int *) NULL);
250  stroff = get_stab_string_offset (file, "$GDB_STRINGS$", false);
251  know (stroff == 1);
252  md_number_to_chars (p, stroff, 4);
253  seg_info (seg)->stabu.p = p;
254
255  /* Set the containing space for both stab sections to be $GDB_DEBUG$
256     (just created above).  Also set some attributes which BFD does
257     not understand.  In particular, access bits, sort keys, and load
258     quadrant.  */
259  seg = bfd_get_section_by_name (stdoutput, "$GDB_STRINGS$");
260  obj_set_subsection_attributes (seg, space, 0x1f, 72, 0, 0, 0, 0);
261  bfd_set_section_alignment (seg, 2);
262
263  subseg_set (saved_seg, saved_subseg);
264}
265
266/* Fill in the counts in the first entry in a .stabs section.  */
267
268static void
269adjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
270{
271  asection *strsec;
272  char *p;
273  int strsz, nsyms;
274
275  if (strcmp ("$GDB_SYMBOLS$", sec->name))
276    return;
277
278  strsec = bfd_get_section_by_name (abfd, "$GDB_STRINGS$");
279  if (strsec)
280    strsz = bfd_section_size (strsec);
281  else
282    strsz = 0;
283  nsyms = bfd_section_size (sec) / 12 - 1;
284
285  p = seg_info (sec)->stabu.p;
286  gas_assert (p != 0);
287
288  bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6);
289  bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8);
290}
291
292/* Called late in the assembly phase to adjust the special
293   stab entry and to set the starting address for each code subspace.  */
294
295void
296som_frob_file (void)
297{
298  bfd_map_over_sections (stdoutput, adjust_stab_sections, (void *) 0);
299}
300
301static void
302obj_som_weak (int ignore ATTRIBUTE_UNUSED)
303{
304  char *name;
305  int c;
306  symbolS *symbolP;
307
308  do
309    {
310      c = get_symbol_name (&name);
311      symbolP = symbol_find_or_make (name);
312      *input_line_pointer = c;
313      SKIP_WHITESPACE_AFTER_NAME ();
314      S_SET_WEAK (symbolP);
315      if (c == ',')
316	{
317	  input_line_pointer++;
318	  SKIP_WHITESPACE ();
319	  if (*input_line_pointer == '\n')
320	    c = '\n';
321	}
322    }
323  while (c == ',');
324  demand_empty_rest_of_line ();
325}
326
327const pseudo_typeS obj_pseudo_table[] =
328{
329  {"weak", obj_som_weak, 0},
330  {NULL, NULL, 0}
331};
332