1/* BFD back-end for a.out.adobe binaries.
2   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
3   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
4   Free Software Foundation, Inc.
5   Written by Cygnus Support.  Based on bout.c.
6
7   This file is part of BFD, the Binary File Descriptor library.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 3 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
22
23#include "sysdep.h"
24#include "bfd.h"
25#include "libbfd.h"
26#include "aout/adobe.h"
27#include "aout/stab_gnu.h"
28#include "libaout.h"		/* BFD a.out internal data structures.  */
29
30/* Forward decl.  */
31extern const bfd_target a_out_adobe_vec;
32
33/* Swaps the information in an executable header taken from a raw byte
34   stream memory image, into the internal exec_header structure.  */
35
36static void
37aout_adobe_swap_exec_header_in (bfd *abfd,
38				struct external_exec *bytes,
39				struct internal_exec *execp)
40{
41  /* Now fill in fields in the execp, from the bytes in the raw data.  */
42  execp->a_info   = H_GET_32 (abfd, bytes->e_info);
43  execp->a_text   = GET_WORD (abfd, bytes->e_text);
44  execp->a_data   = GET_WORD (abfd, bytes->e_data);
45  execp->a_bss    = GET_WORD (abfd, bytes->e_bss);
46  execp->a_syms   = GET_WORD (abfd, bytes->e_syms);
47  execp->a_entry  = GET_WORD (abfd, bytes->e_entry);
48  execp->a_trsize = GET_WORD (abfd, bytes->e_trsize);
49  execp->a_drsize = GET_WORD (abfd, bytes->e_drsize);
50}
51
52/* Swaps the information in an internal exec header structure into the
53   supplied buffer ready for writing to disk.  */
54
55static void
56aout_adobe_swap_exec_header_out (bfd *abfd,
57				 struct internal_exec *execp,
58				 struct external_exec *bytes)
59{
60  /* Now fill in fields in the raw data, from the fields in the exec
61     struct.  */
62  H_PUT_32 (abfd, execp->a_info  , bytes->e_info);
63  PUT_WORD (abfd, execp->a_text  , bytes->e_text);
64  PUT_WORD (abfd, execp->a_data  , bytes->e_data);
65  PUT_WORD (abfd, execp->a_bss   , bytes->e_bss);
66  PUT_WORD (abfd, execp->a_syms  , bytes->e_syms);
67  PUT_WORD (abfd, execp->a_entry , bytes->e_entry);
68  PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize);
69  PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize);
70}
71
72/* Finish up the opening of a b.out file for reading.  Fill in all the
73   fields that are not handled by common code.  */
74
75static const bfd_target *
76aout_adobe_callback (bfd *abfd)
77{
78  struct internal_exec *execp = exec_hdr (abfd);
79  asection *sect;
80  struct external_segdesc ext[1];
81  char *section_name;
82  char try_again[30];	/* Name and number.  */
83  char *newname;
84  int trynum;
85  flagword flags;
86
87  /* Architecture and machine type -- unknown in this format.  */
88  bfd_set_arch_mach (abfd, bfd_arch_unknown, 0L);
89
90  /* The positions of the string table and symbol table.  */
91  obj_str_filepos (abfd) = N_STROFF (*execp);
92  obj_sym_filepos (abfd) = N_SYMOFF (*execp);
93
94  /* Suck up the section information from the file, one section at a time.  */
95  for (;;)
96    {
97      bfd_size_type amt = sizeof (*ext);
98      if (bfd_bread ( ext, amt, abfd) != amt)
99	{
100	  if (bfd_get_error () != bfd_error_system_call)
101	    bfd_set_error (bfd_error_wrong_format);
102
103	  return NULL;
104	}
105      switch (ext->e_type[0])
106	{
107	case N_TEXT:
108	  section_name = ".text";
109	  flags = SEC_CODE | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS;
110	  break;
111
112	case N_DATA:
113	  section_name = ".data";
114	  flags = SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS;
115	  break;
116
117	case N_BSS:
118	  section_name = ".bss";
119	  flags = SEC_DATA | SEC_HAS_CONTENTS;
120	  break;
121
122	case 0:
123	  goto no_more_sections;
124
125	default:
126	  (*_bfd_error_handler)
127	    (_("%B: Unknown section type in a.out.adobe file: %x\n"),
128	     abfd, ext->e_type[0]);
129	  goto no_more_sections;
130	}
131
132      /* First one is called ".text" or whatever; subsequent ones are
133	 ".text1", ".text2", ...  */
134      bfd_set_error (bfd_error_no_error);
135      sect = bfd_make_section_with_flags (abfd, section_name, flags);
136      trynum = 0;
137
138      while (!sect)
139	{
140	  if (bfd_get_error () != bfd_error_no_error)
141	    /* Some other error -- slide into the sunset.  */
142	    return NULL;
143	  sprintf (try_again, "%s%d", section_name, ++trynum);
144	  sect = bfd_make_section_with_flags (abfd, try_again, flags);
145	}
146
147      /* Fix the name, if it is a sprintf'd name.  */
148      if (sect->name == try_again)
149	{
150	  amt = strlen (sect->name);
151	  newname = bfd_zalloc (abfd, amt);
152	  if (newname == NULL)
153	    return NULL;
154	  strcpy (newname, sect->name);
155	  sect->name = newname;
156	}
157
158      /* Assumed big-endian.  */
159      sect->size = ((ext->e_size[0] << 8)
160		    | ext->e_size[1] << 8
161		    | ext->e_size[2]);
162      sect->vma = H_GET_32 (abfd, ext->e_virtbase);
163      sect->filepos = H_GET_32 (abfd, ext->e_filebase);
164      /* FIXME XXX alignment?  */
165
166      /* Set relocation information for first section of each type.  */
167      if (trynum == 0)
168	switch (ext->e_type[0])
169	  {
170	  case N_TEXT:
171	    sect->rel_filepos = N_TRELOFF (*execp);
172	    sect->reloc_count = execp->a_trsize;
173	    break;
174
175	  case N_DATA:
176	    sect->rel_filepos = N_DRELOFF (*execp);
177	    sect->reloc_count = execp->a_drsize;
178	    break;
179
180	  default:
181	    break;
182	  }
183    }
184 no_more_sections:
185
186  adata (abfd).reloc_entry_size = sizeof (struct reloc_std_external);
187  adata (abfd).symbol_entry_size = sizeof (struct external_nlist);
188  adata (abfd).page_size = 1; /* Not applicable.  */
189  adata (abfd).segment_size = 1; /* Not applicable.  */
190  adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE;
191
192  return abfd->xvec;
193}
194
195static const bfd_target *
196aout_adobe_object_p (bfd *abfd)
197{
198  struct internal_exec anexec;
199  struct external_exec exec_bytes;
200  char *targ;
201  bfd_size_type amt = EXEC_BYTES_SIZE;
202
203  if (bfd_bread (& exec_bytes, amt, abfd) != amt)
204    {
205      if (bfd_get_error () != bfd_error_system_call)
206	bfd_set_error (bfd_error_wrong_format);
207      return NULL;
208    }
209
210  anexec.a_info = H_GET_32 (abfd, exec_bytes.e_info);
211
212  /* Normally we just compare for the magic number.
213     However, a bunch of Adobe tools aren't fixed up yet; they generate
214     files using ZMAGIC(!).
215     If the environment variable GNUTARGET is set to "a.out.adobe", we will
216     take just about any a.out file as an Adobe a.out file.  FIXME!  */
217
218  if (N_BADMAG (anexec))
219    {
220      targ = getenv ("GNUTARGET");
221      if (targ && !strcmp (targ, a_out_adobe_vec.name))
222	/* Just continue anyway, if specifically set to this format.  */
223	;
224      else
225	{
226	  bfd_set_error (bfd_error_wrong_format);
227	  return NULL;
228	}
229    }
230
231  aout_adobe_swap_exec_header_in (abfd, &exec_bytes, &anexec);
232  return aout_32_some_aout_object_p (abfd, &anexec, aout_adobe_callback);
233}
234
235struct bout_data_struct
236{
237  struct aoutdata a;
238  struct internal_exec e;
239};
240
241static bfd_boolean
242aout_adobe_mkobject (bfd *abfd)
243{
244  struct bout_data_struct *rawptr;
245  bfd_size_type amt = sizeof (struct bout_data_struct);
246
247  rawptr = bfd_zalloc (abfd, amt);
248  if (rawptr == NULL)
249    return FALSE;
250
251  abfd->tdata.bout_data = rawptr;
252  exec_hdr (abfd) = &rawptr->e;
253
254  adata (abfd).reloc_entry_size = sizeof (struct reloc_std_external);
255  adata (abfd).symbol_entry_size = sizeof (struct external_nlist);
256  adata (abfd).page_size = 1; /* Not applicable.  */
257  adata (abfd).segment_size = 1; /* Not applicable.  */
258  adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE;
259
260  return TRUE;
261}
262
263static void
264aout_adobe_write_section (bfd *abfd ATTRIBUTE_UNUSED,
265			  sec_ptr sect ATTRIBUTE_UNUSED)
266{
267  /* FIXME XXX.  */
268}
269
270static bfd_boolean
271aout_adobe_write_object_contents (bfd *abfd)
272{
273  struct external_exec swapped_hdr;
274  static struct external_segdesc sentinel[1];	/* Initialized to zero.  */
275  asection *sect;
276  bfd_size_type amt;
277
278  exec_hdr (abfd)->a_info = ZMAGIC;
279
280  /* Calculate text size as total of text sections, etc.  */
281  exec_hdr (abfd)->a_text = 0;
282  exec_hdr (abfd)->a_data = 0;
283  exec_hdr (abfd)->a_bss  = 0;
284  exec_hdr (abfd)->a_trsize = 0;
285  exec_hdr (abfd)->a_drsize = 0;
286
287  for (sect = abfd->sections; sect; sect = sect->next)
288    {
289      if (sect->flags & SEC_CODE)
290	{
291	  exec_hdr (abfd)->a_text += sect->size;
292	  exec_hdr (abfd)->a_trsize += sect->reloc_count *
293	    sizeof (struct reloc_std_external);
294	}
295      else if (sect->flags & SEC_DATA)
296	{
297	  exec_hdr (abfd)->a_data += sect->size;
298	  exec_hdr (abfd)->a_drsize += sect->reloc_count *
299	    sizeof (struct reloc_std_external);
300	}
301      else if (sect->flags & SEC_ALLOC && !(sect->flags & SEC_LOAD))
302	exec_hdr (abfd)->a_bss += sect->size;
303    }
304
305  exec_hdr (abfd)->a_syms = bfd_get_symcount (abfd)
306    * sizeof (struct external_nlist);
307  exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd);
308
309  aout_adobe_swap_exec_header_out (abfd, exec_hdr (abfd), &swapped_hdr);
310
311  amt = EXEC_BYTES_SIZE;
312  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
313      || bfd_bwrite (& swapped_hdr, amt, abfd) != amt)
314    return FALSE;
315
316  /* Now write out the section information.  Text first, data next, rest
317     afterward.  */
318  for (sect = abfd->sections; sect; sect = sect->next)
319    if (sect->flags & SEC_CODE)
320      aout_adobe_write_section (abfd, sect);
321
322  for (sect = abfd->sections; sect; sect = sect->next)
323    if (sect->flags & SEC_DATA)
324      aout_adobe_write_section (abfd, sect);
325
326  for (sect = abfd->sections; sect; sect = sect->next)
327    if (!(sect->flags & (SEC_CODE | SEC_DATA)))
328      aout_adobe_write_section (abfd, sect);
329
330  /* Write final `sentinel` section header (with type of 0).  */
331  amt = sizeof (*sentinel);
332  if (bfd_bwrite (sentinel, amt, abfd) != amt)
333    return FALSE;
334
335  /* Now write out reloc info, followed by syms and strings.  */
336  if (bfd_get_symcount (abfd) != 0)
337    {
338      if (bfd_seek (abfd, (file_ptr) (N_SYMOFF (*exec_hdr (abfd))), SEEK_SET)
339	  != 0)
340	return FALSE;
341
342      if (! aout_32_write_syms (abfd))
343	return FALSE;
344
345      if (bfd_seek (abfd, (file_ptr) (N_TRELOFF (*exec_hdr (abfd))), SEEK_SET)
346	  != 0)
347	return FALSE;
348
349      for (sect = abfd->sections; sect; sect = sect->next)
350	if (sect->flags & SEC_CODE)
351	  if (!aout_32_squirt_out_relocs (abfd, sect))
352	    return FALSE;
353
354      if (bfd_seek (abfd, (file_ptr) (N_DRELOFF (*exec_hdr (abfd))), SEEK_SET)
355	  != 0)
356	return FALSE;
357
358      for (sect = abfd->sections; sect; sect = sect->next)
359	if (sect->flags & SEC_DATA)
360	  if (!aout_32_squirt_out_relocs (abfd, sect))
361	    return FALSE;
362    }
363
364  return TRUE;
365}
366
367static bfd_boolean
368aout_adobe_set_section_contents (bfd *abfd,
369				 asection *section,
370				 const void * location,
371				 file_ptr offset,
372				 bfd_size_type count)
373{
374  file_ptr section_start;
375  sec_ptr sect;
376
377  /* Set by bfd.c handler.  */
378  if (! abfd->output_has_begun)
379    {
380      /* Assign file offsets to sections.  Text sections are first, and
381	 are contiguous.  Then data sections.  Everything else at the end.  */
382      section_start = N_TXTOFF (ignore<-->me);
383
384      for (sect = abfd->sections; sect; sect = sect->next)
385	{
386	  if (sect->flags & SEC_CODE)
387	    {
388	      sect->filepos = section_start;
389	      /* FIXME:  Round to alignment.  */
390	      section_start += sect->size;
391	    }
392	}
393
394      for (sect = abfd->sections; sect; sect = sect->next)
395	{
396	  if (sect->flags & SEC_DATA)
397	    {
398	      sect->filepos = section_start;
399	      /* FIXME:  Round to alignment.  */
400	      section_start += sect->size;
401	    }
402	}
403
404      for (sect = abfd->sections; sect; sect = sect->next)
405	{
406	  if (sect->flags & SEC_HAS_CONTENTS &&
407	      !(sect->flags & (SEC_CODE | SEC_DATA)))
408	    {
409	      sect->filepos = section_start;
410	      /* FIXME:  Round to alignment.  */
411	      section_start += sect->size;
412	    }
413	}
414    }
415
416  /* Regardless, once we know what we're doing, we might as well get
417     going.  */
418  if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0)
419    return FALSE;
420
421  if (count == 0)
422    return TRUE;
423
424  return bfd_bwrite (location, count, abfd) == count;
425}
426
427static bfd_boolean
428aout_adobe_set_arch_mach (bfd *abfd,
429			  enum bfd_architecture arch,
430			  unsigned long machine)
431{
432  if (! bfd_default_set_arch_mach (abfd, arch, machine))
433    return FALSE;
434
435  if (arch == bfd_arch_unknown
436      || arch == bfd_arch_m68k)
437    return TRUE;
438
439  return FALSE;
440}
441
442static int
443aout_adobe_sizeof_headers (bfd *ignore_abfd ATTRIBUTE_UNUSED,
444			   struct bfd_link_info *info ATTRIBUTE_UNUSED)
445{
446  return sizeof (struct internal_exec);
447}
448
449/* Build the transfer vector for Adobe A.Out files.  */
450
451#define aout_32_bfd_make_debug_symbol ((asymbol *(*) (bfd *, void *, unsigned long)) bfd_nullvoidptr)
452#define aout_32_bfd_reloc_type_lookup ((reloc_howto_type *(*) (bfd *, bfd_reloc_code_real_type)) bfd_nullvoidptr)
453#define aout_32_bfd_reloc_name_lookup ((reloc_howto_type *(*) (bfd *, const char *)) bfd_nullvoidptr)
454#define aout_32_close_and_cleanup                   aout_32_bfd_free_cached_info
455#define	aout_32_set_arch_mach		            aout_adobe_set_arch_mach
456#define	aout_32_set_section_contents	            aout_adobe_set_section_contents
457#define	aout_32_sizeof_headers		            aout_adobe_sizeof_headers
458#define aout_32_bfd_get_relocated_section_contents  bfd_generic_get_relocated_section_contents
459#define aout_32_get_section_contents_in_window      _bfd_generic_get_section_contents_in_window
460#define aout_32_bfd_relax_section                   bfd_generic_relax_section
461#define aout_32_bfd_gc_sections                     bfd_generic_gc_sections
462#define aout_32_bfd_merge_sections	            bfd_generic_merge_sections
463#define aout_32_bfd_is_group_section	            bfd_generic_is_group_section
464#define aout_32_bfd_discard_group	            bfd_generic_discard_group
465#define aout_32_section_already_linked              _bfd_generic_section_already_linked
466#define aout_32_bfd_define_common_symbol            bfd_generic_define_common_symbol
467#define aout_32_bfd_link_hash_table_create          _bfd_generic_link_hash_table_create
468#define aout_32_bfd_link_hash_table_free            _bfd_generic_link_hash_table_free
469#define aout_32_bfd_link_add_symbols	            _bfd_generic_link_add_symbols
470#define aout_32_bfd_link_just_syms	            _bfd_generic_link_just_syms
471#define aout_32_bfd_copy_link_hash_symbol_type \
472  _bfd_generic_copy_link_hash_symbol_type
473#define aout_32_bfd_final_link		            _bfd_generic_final_link
474#define aout_32_bfd_link_split_section	            _bfd_generic_link_split_section
475
476const bfd_target a_out_adobe_vec =
477{
478  "a.out.adobe",		/* Name.  */
479  bfd_target_aout_flavour,
480  BFD_ENDIAN_BIG,		/* Data byte order is unknown (big assumed).  */
481  BFD_ENDIAN_BIG,		/* Header byte order is big.  */
482  (HAS_RELOC | EXEC_P |		/* Object flags.  */
483   HAS_LINENO | HAS_DEBUG |
484   HAS_SYMS | HAS_LOCALS | WP_TEXT ),
485  /* section flags */
486  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_DATA | SEC_RELOC),
487  '_',				/* Symbol leading char.  */
488  ' ',				/* AR_pad_char.  */
489  16,				/* AR_max_namelen.  */
490
491  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
492  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
493  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
494  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
495  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
496  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Headers.  */
497
498  {_bfd_dummy_target, aout_adobe_object_p,	/* bfd_check_format.  */
499   bfd_generic_archive_p, _bfd_dummy_target},
500  {bfd_false, aout_adobe_mkobject,		/* bfd_set_format.  */
501   _bfd_generic_mkarchive, bfd_false},
502  {bfd_false, aout_adobe_write_object_contents,/* bfd_write_contents.  */
503   _bfd_write_archive_contents, bfd_false},
504
505  BFD_JUMP_TABLE_GENERIC (aout_32),
506  BFD_JUMP_TABLE_COPY (_bfd_generic),
507  BFD_JUMP_TABLE_CORE (_bfd_nocore),
508  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd),
509  BFD_JUMP_TABLE_SYMBOLS (aout_32),
510  BFD_JUMP_TABLE_RELOCS (aout_32),
511  BFD_JUMP_TABLE_WRITE (aout_32),
512  BFD_JUMP_TABLE_LINK (aout_32),
513  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
514
515  NULL,
516
517  NULL
518};
519