1 /* a.out object file format
2    Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000,
3    2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
4 
5    This file is part of GAS, the GNU Assembler.
6 
7    GAS is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2,
10    or (at your option) any later version.
11 
12    GAS is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15    the GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GAS; see the file COPYING.  If not, write to the Free
19    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20    02110-1301, USA.  */
21 
22 #define OBJ_HEADER "obj-aout.h"
23 
24 #include "as.h"
25 #ifdef BFD_ASSEMBLER
26 #undef NO_RELOC
27 #include "aout/aout64.h"
28 #endif
29 #include "obstack.h"
30 
31 #ifndef BFD_ASSEMBLER
32 /* in: segT   out: N_TYPE bits.  */
33 const short seg_N_TYPE[] =
34 {
35   N_ABS,
36   N_TEXT,
37   N_DATA,
38   N_BSS,
39   N_UNDF,			/* Unknown.  */
40   N_UNDF,			/* Error.  */
41   N_UNDF,			/* Expression.  */
42   N_UNDF,			/* Debug.  */
43   N_UNDF,			/* Ntv.  */
44   N_UNDF,			/* Ptv.  */
45   N_REGISTER,			/* Register.  */
46 };
47 
48 const segT N_TYPE_seg[N_TYPE + 2] =
49 {				/* N_TYPE == 0x1E = 32-2 */
50   SEG_UNKNOWN,			/* N_UNDF == 0 */
51   SEG_GOOF,
52   SEG_ABSOLUTE,			/* N_ABS == 2 */
53   SEG_GOOF,
54   SEG_TEXT,			/* N_TEXT == 4 */
55   SEG_GOOF,
56   SEG_DATA,			/* N_DATA == 6 */
57   SEG_GOOF,
58   SEG_BSS,			/* N_BSS == 8 */
59   SEG_GOOF,
60   SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
61   SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
62   SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
63   SEG_REGISTER,			/* Dummy N_REGISTER for regs = 30.  */
64   SEG_GOOF,
65 };
66 #endif
67 
68 #ifdef BFD_ASSEMBLER
69 
70 void
obj_aout_frob_symbol(symbolS * sym,int * punt ATTRIBUTE_UNUSED)71 obj_aout_frob_symbol (symbolS *sym, int *punt ATTRIBUTE_UNUSED)
72 {
73   flagword flags;
74   asection *sec;
75   int desc, type, other;
76 
77   flags = symbol_get_bfdsym (sym)->flags;
78   desc = aout_symbol (symbol_get_bfdsym (sym))->desc;
79   type = aout_symbol (symbol_get_bfdsym (sym))->type;
80   other = aout_symbol (symbol_get_bfdsym (sym))->other;
81   sec = S_GET_SEGMENT (sym);
82 
83   /* Only frob simple symbols this way right now.  */
84   if (! (type & ~ (N_TYPE | N_EXT)))
85     {
86       if (type == (N_UNDF | N_EXT)
87 	  && sec == &bfd_abs_section)
88 	{
89 	  sec = bfd_und_section_ptr;
90 	  S_SET_SEGMENT (sym, sec);
91 	}
92 
93       if ((type & N_TYPE) != N_INDR
94 	  && (type & N_TYPE) != N_SETA
95 	  && (type & N_TYPE) != N_SETT
96 	  && (type & N_TYPE) != N_SETD
97 	  && (type & N_TYPE) != N_SETB
98 	  && type != N_WARNING
99 	  && (sec == &bfd_abs_section
100 	      || sec == &bfd_und_section))
101 	return;
102       if (flags & BSF_EXPORT)
103 	type |= N_EXT;
104 
105       switch (type & N_TYPE)
106 	{
107 	case N_SETA:
108 	case N_SETT:
109 	case N_SETD:
110 	case N_SETB:
111 	  /* Set the debugging flag for constructor symbols so that
112 	     BFD leaves them alone.  */
113 	  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
114 
115 	  /* You can't put a common symbol in a set.  The way a set
116 	     element works is that the symbol has a definition and a
117 	     name, and the linker adds the definition to the set of
118 	     that name.  That does not work for a common symbol,
119 	     because the linker can't tell which common symbol the
120 	     user means.  FIXME: Using as_bad here may be
121 	     inappropriate, since the user may want to force a
122 	     particular type without regard to the semantics of sets;
123 	     on the other hand, we certainly don't want anybody to be
124 	     mislead into thinking that their code will work.  */
125 	  if (S_IS_COMMON (sym))
126 	    as_bad (_("Attempt to put a common symbol into set %s"),
127 		    S_GET_NAME (sym));
128 	  /* Similarly, you can't put an undefined symbol in a set.  */
129 	  else if (! S_IS_DEFINED (sym))
130 	    as_bad (_("Attempt to put an undefined symbol into set %s"),
131 		    S_GET_NAME (sym));
132 
133 	  break;
134 	case N_INDR:
135 	  /* Put indirect symbols in the indirect section.  */
136 	  S_SET_SEGMENT (sym, bfd_ind_section_ptr);
137 	  symbol_get_bfdsym (sym)->flags |= BSF_INDIRECT;
138 	  if (type & N_EXT)
139 	    {
140 	      symbol_get_bfdsym (sym)->flags |= BSF_EXPORT;
141 	      symbol_get_bfdsym (sym)->flags &=~ BSF_LOCAL;
142 	    }
143 	  break;
144 	case N_WARNING:
145 	  /* Mark warning symbols.  */
146 	  symbol_get_bfdsym (sym)->flags |= BSF_WARNING;
147 	  break;
148 	}
149     }
150   else
151     symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
152 
153   aout_symbol (symbol_get_bfdsym (sym))->type = type;
154 
155   /* Double check weak symbols.  */
156   if (S_IS_WEAK (sym) && S_IS_COMMON (sym))
157     as_bad (_("Symbol `%s' can not be both weak and common"),
158 	    S_GET_NAME (sym));
159 }
160 
161 void
obj_aout_frob_file_before_fix(void)162 obj_aout_frob_file_before_fix (void)
163 {
164   /* Relocation processing may require knowing the VMAs of the sections.
165      Since writing to a section will cause the BFD back end to compute the
166      VMAs, fake it out here....  */
167   bfd_byte b = 0;
168   bfd_boolean x = TRUE;
169   if (bfd_section_size (stdoutput, text_section) != 0)
170     x = bfd_set_section_contents (stdoutput, text_section, &b, (file_ptr) 0,
171 				  (bfd_size_type) 1);
172   else if (bfd_section_size (stdoutput, data_section) != 0)
173     x = bfd_set_section_contents (stdoutput, data_section, &b, (file_ptr) 0,
174 				  (bfd_size_type) 1);
175 
176   assert (x);
177 }
178 
179 #else /* ! BFD_ASSEMBLER */
180 
181 /* Relocation.  */
182 
183 /** Crawl along a fixS chain. Emit the segment's relocations.  */
184 
185 void
obj_emit_relocations(char ** where,fixS * fixP,relax_addressT segment_address_in_file)186 obj_emit_relocations (char **where,
187 		      fixS *fixP,		/* Fixup chain for this segment.  */
188 		      relax_addressT segment_address_in_file)
189 {
190   for (; fixP; fixP = fixP->fx_next)
191     if (fixP->fx_done == 0)
192       {
193 	symbolS *sym;
194 
195 	sym = fixP->fx_addsy;
196 	while (sym->sy_value.X_op == O_symbol
197 	       && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
198 	  sym = sym->sy_value.X_add_symbol;
199 	fixP->fx_addsy = sym;
200 
201 	if (! sym->sy_resolved && ! S_IS_DEFINED (sym))
202 	  {
203 	    char *file;
204 	    unsigned int line;
205 
206 	    if (expr_symbol_where (sym, &file, &line))
207 	      as_bad_where (file, line, _("unresolved relocation"));
208 	    else
209 	      as_bad (_("bad relocation: symbol `%s' not in symbol table"),
210 		      S_GET_NAME (sym));
211 	  }
212 
213 	tc_aout_fix_to_chars (*where, fixP, segment_address_in_file);
214 	*where += md_reloc_size;
215       }
216 }
217 
218 #ifndef obj_header_append
219 /* Aout file generation & utilities.  */
220 
221 /* An AOUT header on disk is laid out in target byte order.  */
222 
223 void
obj_header_append(char ** where,object_headers * headers)224 obj_header_append (char **where, object_headers *headers)
225 {
226   char *p;
227 
228   tc_headers_hook (headers);
229 
230 #ifdef __A_OUT_GNU_H__
231 #define SIZEOF_HEADER(PIECE) (sizeof (((struct exec_bytes *) 0)->PIECE))
232 #else
233 #define SIZEOF_HEADER(PIECE) 4
234 #endif
235 #define DO(PIECE) \
236   md_number_to_chars (p, headers->header.PIECE, SIZEOF_HEADER (PIECE)); \
237   p += SIZEOF_HEADER (PIECE);
238 
239   p = *where;
240   DO (a_info);
241   DO (a_text);
242   DO (a_data);
243   DO (a_bss);
244   DO (a_syms);
245   DO (a_entry);
246   DO (a_trsize);
247   DO (a_drsize);
248   *where = p;
249 #undef DO
250 #undef SIZEOF_HEADER
251 }
252 #endif /* ! defined (obj_header_append) */
253 
254 void
obj_symbol_to_chars(char ** where,symbolS * symbolP)255 obj_symbol_to_chars (char **where, symbolS *symbolP)
256 {
257   char *p = *where;
258   md_number_to_chars (p, S_GET_OFFSET (symbolP), 4);
259   p += 4;
260   /* Can't use S_GET_TYPE here as it masks.  */
261   *p++ = symbolP->sy_symbol.n_type;
262   *p++ = symbolP->sy_symbol.n_other;
263   md_number_to_chars (p, S_GET_DESC (symbolP), 2);
264   p += 2;
265   md_number_to_chars (p, S_GET_VALUE (symbolP), 4);
266   p += 4;
267   *where = p;
268 }
269 
270 void
obj_emit_symbols(char ** where,symbolS * symbol_rootP)271 obj_emit_symbols (char **where, symbolS *symbol_rootP)
272 {
273   symbolS *symbolP;
274 
275   /* Emit all symbols left in the symbol chain.  */
276   for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
277     {
278       /* Used to save the offset of the name. It is used to point
279 	 to the string in memory but must be a file offset.  */
280       char *temp;
281 
282       temp = S_GET_NAME (symbolP);
283       S_SET_OFFSET (symbolP, symbolP->sy_name_offset);
284 
285       /* Any symbol still undefined and is not a dbg symbol is made N_EXT.  */
286       if (!S_IS_DEBUG (symbolP) && !S_IS_DEFINED (symbolP))
287 	S_SET_EXTERNAL (symbolP);
288 
289       /* Adjust the type of a weak symbol.  */
290       if (S_GET_WEAK (symbolP))
291 	{
292 	  switch (S_GET_TYPE (symbolP))
293 	    {
294 	    case N_UNDF: S_SET_TYPE (symbolP, N_WEAKU); break;
295 	    case N_ABS:	 S_SET_TYPE (symbolP, N_WEAKA); break;
296 	    case N_TEXT: S_SET_TYPE (symbolP, N_WEAKT); break;
297 	    case N_DATA: S_SET_TYPE (symbolP, N_WEAKD); break;
298 	    case N_BSS:  S_SET_TYPE (symbolP, N_WEAKB); break;
299 	    default: as_bad (_("%s: bad type for weak symbol"), temp); break;
300 	    }
301 	}
302 
303       obj_symbol_to_chars (where, symbolP);
304       S_SET_NAME (symbolP, temp);
305     }
306 }
307 
308 #endif /* ! BFD_ASSEMBLER */
309 
310 static void
obj_aout_line(int ignore ATTRIBUTE_UNUSED)311 obj_aout_line (int ignore ATTRIBUTE_UNUSED)
312 {
313   /* Assume delimiter is part of expression.
314      BSD4.2 as fails with delightful bug, so we
315      are not being incompatible here.  */
316   new_logical_line ((char *) NULL, (int) (get_absolute_expression ()));
317   demand_empty_rest_of_line ();
318 }
319 
320 /* Handle .weak.  This is a GNU extension.  */
321 
322 static void
obj_aout_weak(int ignore ATTRIBUTE_UNUSED)323 obj_aout_weak (int ignore ATTRIBUTE_UNUSED)
324 {
325   char *name;
326   int c;
327   symbolS *symbolP;
328 
329   do
330     {
331       name = input_line_pointer;
332       c = get_symbol_end ();
333       symbolP = symbol_find_or_make (name);
334       *input_line_pointer = c;
335       SKIP_WHITESPACE ();
336       S_SET_WEAK (symbolP);
337       if (c == ',')
338 	{
339 	  input_line_pointer++;
340 	  SKIP_WHITESPACE ();
341 	  if (*input_line_pointer == '\n')
342 	    c = '\n';
343 	}
344     }
345   while (c == ',');
346   demand_empty_rest_of_line ();
347 }
348 
349 /* Handle .type.  On {Net,Open}BSD, this is used to set the n_other field,
350    which is then apparently used when doing dynamic linking.  Older
351    versions of gas ignored the .type pseudo-op, so we also ignore it if
352    we can't parse it.  */
353 
354 static void
obj_aout_type(int ignore ATTRIBUTE_UNUSED)355 obj_aout_type (int ignore ATTRIBUTE_UNUSED)
356 {
357   char *name;
358   int c;
359   symbolS *sym;
360 
361   name = input_line_pointer;
362   c = get_symbol_end ();
363   sym = symbol_find_or_make (name);
364   *input_line_pointer = c;
365   SKIP_WHITESPACE ();
366   if (*input_line_pointer == ',')
367     {
368       ++input_line_pointer;
369       SKIP_WHITESPACE ();
370       if (*input_line_pointer == '@')
371 	{
372 	  ++input_line_pointer;
373 	  if (strncmp (input_line_pointer, "object", 6) == 0)
374 	    S_SET_OTHER (sym, 1);
375 	  else if (strncmp (input_line_pointer, "function", 8) == 0)
376 	    S_SET_OTHER (sym, 2);
377 	}
378     }
379 
380   /* Ignore everything else on the line.  */
381   s_ignore (0);
382 }
383 
384 #ifndef BFD_ASSEMBLER
385 
386 void
obj_crawl_symbol_chain(object_headers * headers)387 obj_crawl_symbol_chain (object_headers *headers)
388 {
389   symbolS *symbolP;
390   symbolS **symbolPP;
391   int symbol_number = 0;
392 
393   tc_crawl_symbol_chain (headers);
394 
395   symbolPP = &symbol_rootP;	/*->last symbol chain link.  */
396   while ((symbolP = *symbolPP) != NULL)
397     {
398       if (symbolP->sy_mri_common)
399 	{
400 	  if (S_IS_EXTERNAL (symbolP))
401 	    as_bad (_("%s: global symbols not supported in common sections"),
402 		    S_GET_NAME (symbolP));
403 	  *symbolPP = symbol_next (symbolP);
404 	  continue;
405 	}
406 
407       if (flag_readonly_data_in_text && (S_GET_SEGMENT (symbolP) == SEG_DATA))
408 	{
409 	  S_SET_SEGMENT (symbolP, SEG_TEXT);
410 	}
411 
412       resolve_symbol_value (symbolP);
413 
414       /* Skip symbols which were equated to undefined or common
415 	 symbols.  Also skip defined uncommon symbols which can
416 	 be resolved since in this case they should have been
417 	 resolved to a non-symbolic constant.  */
418       if (symbolP->sy_value.X_op == O_symbol
419 	  && (! S_IS_DEFINED (symbolP)
420 	      || S_IS_COMMON (symbolP)
421 	      || symbol_resolved_p (symbolP)))
422 	{
423 	  *symbolPP = symbol_next (symbolP);
424 	  continue;
425 	}
426 
427       /* OK, here is how we decide which symbols go out into the brave
428 	 new symtab.  Symbols that do are:
429 
430 	 * symbols with no name (stabd's?)
431 	 * symbols with debug info in their N_TYPE
432 
433 	 Symbols that don't are:
434 	 * symbols that are registers
435 	 * symbols with \1 as their 3rd character (numeric labels)
436 	 * "local labels" as defined by S_LOCAL_NAME(name) if the -L
437 	 switch was passed to gas.
438 
439 	 All other symbols are output.  We complain if a deleted
440 	 symbol was marked external.  */
441 
442       if (!S_IS_REGISTER (symbolP)
443 	  && (!S_GET_NAME (symbolP)
444 	      || S_IS_DEBUG (symbolP)
445 	      || !S_IS_DEFINED (symbolP)
446 	      || S_IS_EXTERNAL (symbolP)
447 	      || (S_GET_NAME (symbolP)[0] != '\001'
448 		  && (flag_keep_locals || !S_LOCAL_NAME (symbolP)))))
449 	{
450 	  symbolP->sy_number = symbol_number++;
451 
452 	  /* The + 1 after strlen account for the \0 at the
453 			   end of each string */
454 	  if (!S_IS_STABD (symbolP))
455 	    {
456 	      /* Ordinary case.  */
457 	      symbolP->sy_name_offset = string_byte_count;
458 	      string_byte_count += strlen (S_GET_NAME (symbolP)) + 1;
459 	    }
460 	  else			/* .Stabd case.  */
461 	    symbolP->sy_name_offset = 0;
462 	  symbolPP = &symbolP->sy_next;
463 	}
464       else
465 	{
466 	  if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP))
467 	    /* This warning should never get triggered any more.
468 	       Well, maybe if you're doing twisted things with
469 	       register names...  */
470 	    as_bad (_("Local symbol %s never defined."),
471 		    decode_local_label_name (S_GET_NAME (symbolP)));
472 
473 	  /* Unhook it from the chain */
474 	  *symbolPP = symbol_next (symbolP);
475 	}
476     }
477 
478   H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number);
479 }
480 
481 /* Find strings by crawling along symbol table chain.  */
482 
483 void
obj_emit_strings(char ** where)484 obj_emit_strings (char **where)
485 {
486   symbolS *symbolP;
487 
488   md_number_to_chars (*where, string_byte_count, 4);
489   *where += 4;
490 
491   for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
492     if (S_GET_NAME (symbolP))
493       append (where, S_GET_NAME (symbolP),
494 	      (unsigned long) (strlen (S_GET_NAME (symbolP)) + 1));
495 }
496 
497 #ifndef AOUT_VERSION
498 #define AOUT_VERSION 0
499 #endif
500 
501 void
obj_pre_write_hook(object_headers * headers)502 obj_pre_write_hook (object_headers *headers)
503 {
504   H_SET_DYNAMIC (headers, 0);
505   H_SET_VERSION (headers, AOUT_VERSION);
506   H_SET_MACHTYPE (headers, AOUT_MACHTYPE);
507   tc_aout_pre_write_hook (headers);
508 }
509 
510 #endif /* ! BFD_ASSEMBLER */
511 
512 #ifdef BFD_ASSEMBLER
513 
514 /* Support for an AOUT emulation.  */
515 
516 static void
aout_pop_insert(void)517 aout_pop_insert (void)
518 {
519   pop_insert (aout_pseudo_table);
520 }
521 
522 static int
obj_aout_s_get_other(symbolS * sym)523 obj_aout_s_get_other (symbolS *sym)
524 {
525   return aout_symbol (symbol_get_bfdsym (sym))->other;
526 }
527 
528 static void
obj_aout_s_set_other(symbolS * sym,int o)529 obj_aout_s_set_other (symbolS *sym, int o)
530 {
531   aout_symbol (symbol_get_bfdsym (sym))->other = o;
532 }
533 
534 static int
obj_aout_sec_sym_ok_for_reloc(asection * sec ATTRIBUTE_UNUSED)535 obj_aout_sec_sym_ok_for_reloc (asection *sec ATTRIBUTE_UNUSED)
536 {
537   return obj_sec_sym_ok_for_reloc (sec);
538 }
539 
540 static void
obj_aout_process_stab(segT seg ATTRIBUTE_UNUSED,int w,const char * s,int t,int o,int d)541 obj_aout_process_stab (segT seg ATTRIBUTE_UNUSED,
542 		       int w,
543 		       const char *s,
544 		       int t,
545 		       int o,
546 		       int d)
547 {
548   aout_process_stab (w, s, t, o, d);
549 }
550 
551 static int
obj_aout_s_get_desc(symbolS * sym)552 obj_aout_s_get_desc (symbolS *sym)
553 {
554   return aout_symbol (symbol_get_bfdsym (sym))->desc;
555 }
556 
557 static void
obj_aout_s_set_desc(symbolS * sym,int d)558 obj_aout_s_set_desc (symbolS *sym, int d)
559 {
560   aout_symbol (symbol_get_bfdsym (sym))->desc = d;
561 }
562 
563 static int
obj_aout_s_get_type(symbolS * sym)564 obj_aout_s_get_type (symbolS *sym)
565 {
566   return aout_symbol (symbol_get_bfdsym (sym))->type;
567 }
568 
569 static void
obj_aout_s_set_type(symbolS * sym,int t)570 obj_aout_s_set_type (symbolS *sym, int t)
571 {
572   aout_symbol (symbol_get_bfdsym (sym))->type = t;
573 }
574 
575 static int
obj_aout_separate_stab_sections(void)576 obj_aout_separate_stab_sections (void)
577 {
578   return 0;
579 }
580 
581 /* When changed, make sure these table entries match the single-format
582    definitions in obj-aout.h.  */
583 
584 const struct format_ops aout_format_ops =
585 {
586   bfd_target_aout_flavour,
587   1,	/* dfl_leading_underscore.  */
588   0,	/* emit_section_symbols.  */
589   0,	/* begin.  */
590   0,	/* app_file.  */
591   obj_aout_frob_symbol,
592   0,	/* frob_file.  */
593   0,	/* frob_file_before_adjust.  */
594   obj_aout_frob_file_before_fix,
595   0,	/* frob_file_after_relocs.  */
596   0,	/* s_get_size.  */
597   0,	/* s_set_size.  */
598   0,	/* s_get_align.  */
599   0,	/* s_set_align.  */
600   obj_aout_s_get_other,
601   obj_aout_s_set_other,
602   obj_aout_s_get_desc,
603   obj_aout_s_set_desc,
604   obj_aout_s_get_type,
605   obj_aout_s_set_type,
606   0,	/* copy_symbol_attributes.  */
607   0,	/* generate_asm_lineno.  */
608   obj_aout_process_stab,
609   obj_aout_separate_stab_sections,
610   0,	/* init_stab_section.  */
611   obj_aout_sec_sym_ok_for_reloc,
612   aout_pop_insert,
613   0,	/* ecoff_set_ext.  */
614   0,	/* read_begin_hook.  */
615   0 	/* symbol_new_hook.  */
616 };
617 #endif /* BFD_ASSEMBLER */
618 
619 const pseudo_typeS aout_pseudo_table[] =
620 {
621   {"line", obj_aout_line, 0},	/* Source code line number.  */
622   {"ln", obj_aout_line, 0},	/* COFF line number that we use anyway.  */
623 
624   {"weak", obj_aout_weak, 0},	/* Mark symbol as weak.  */
625 
626   {"type", obj_aout_type, 0},
627 
628   /* coff debug pseudos (ignored) */
629   {"def", s_ignore, 0},
630   {"dim", s_ignore, 0},
631   {"endef", s_ignore, 0},
632   {"ident", s_ignore, 0},
633   {"line", s_ignore, 0},
634   {"ln", s_ignore, 0},
635   {"scl", s_ignore, 0},
636   {"size", s_ignore, 0},
637   {"tag", s_ignore, 0},
638   {"val", s_ignore, 0},
639   {"version", s_ignore, 0},
640 
641   {"optim", s_ignore, 0},	/* For sun386i cc (?).  */
642 
643   /* other stuff */
644   {"ABORT", s_abort, 0},
645 
646   {NULL, NULL, 0}
647 };
648