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
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 2 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 "bfd.h"
24#include "sysdep.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_close_and_cleanup                   aout_32_bfd_free_cached_info
454#define	aout_32_set_arch_mach		            aout_adobe_set_arch_mach
455#define	aout_32_set_section_contents	            aout_adobe_set_section_contents
456#define	aout_32_sizeof_headers		            aout_adobe_sizeof_headers
457#define aout_32_bfd_get_relocated_section_contents  bfd_generic_get_relocated_section_contents
458#define aout_32_get_section_contents_in_window      _bfd_generic_get_section_contents_in_window
459#define aout_32_bfd_relax_section                   bfd_generic_relax_section
460#define aout_32_bfd_gc_sections                     bfd_generic_gc_sections
461#define aout_32_bfd_merge_sections	            bfd_generic_merge_sections
462#define aout_32_bfd_is_group_section	            bfd_generic_is_group_section
463#define aout_32_bfd_discard_group	            bfd_generic_discard_group
464#define aout_32_section_already_linked              _bfd_generic_section_already_linked
465#define aout_32_bfd_link_hash_table_create          _bfd_generic_link_hash_table_create
466#define aout_32_bfd_link_hash_table_free            _bfd_generic_link_hash_table_free
467#define aout_32_bfd_link_add_symbols	            _bfd_generic_link_add_symbols
468#define aout_32_bfd_link_just_syms	            _bfd_generic_link_just_syms
469#define aout_32_bfd_final_link		            _bfd_generic_final_link
470#define aout_32_bfd_link_split_section	            _bfd_generic_link_split_section
471
472const bfd_target a_out_adobe_vec =
473{
474  "a.out.adobe",		/* Name.  */
475  bfd_target_aout_flavour,
476  BFD_ENDIAN_BIG,		/* Data byte order is unknown (big assumed).  */
477  BFD_ENDIAN_BIG,		/* Header byte order is big.  */
478  (HAS_RELOC | EXEC_P |		/* Object flags.  */
479   HAS_LINENO | HAS_DEBUG |
480   HAS_SYMS | HAS_LOCALS | WP_TEXT ),
481  /* section flags */
482  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_DATA | SEC_RELOC),
483  '_',				/* Symbol leading char.  */
484  ' ',				/* AR_pad_char.  */
485  16,				/* AR_max_namelen.  */
486
487  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
488  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
489  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
490  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
491  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
492  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Headers.  */
493
494  {_bfd_dummy_target, aout_adobe_object_p,	/* bfd_check_format.  */
495   bfd_generic_archive_p, _bfd_dummy_target},
496  {bfd_false, aout_adobe_mkobject,		/* bfd_set_format.  */
497   _bfd_generic_mkarchive, bfd_false},
498  {bfd_false, aout_adobe_write_object_contents,/* bfd_write_contents.  */
499   _bfd_write_archive_contents, bfd_false},
500
501  BFD_JUMP_TABLE_GENERIC (aout_32),
502  BFD_JUMP_TABLE_COPY (_bfd_generic),
503  BFD_JUMP_TABLE_CORE (_bfd_nocore),
504  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd),
505  BFD_JUMP_TABLE_SYMBOLS (aout_32),
506  BFD_JUMP_TABLE_RELOCS (aout_32),
507  BFD_JUMP_TABLE_WRITE (aout_32),
508  BFD_JUMP_TABLE_LINK (aout_32),
509  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
510
511  NULL,
512
513  NULL
514};
515