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
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 (abfd, section_name);
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 (abfd, try_again);
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      /* Now set the section's attributes.  */
159      bfd_set_section_flags (abfd, sect, flags);
160      /* Assumed big-endian.  */
161      sect->size = ((ext->e_size[0] << 8)
162		    | ext->e_size[1] << 8
163		    | ext->e_size[2]);
164      sect->vma = H_GET_32 (abfd, ext->e_virtbase);
165      sect->filepos = H_GET_32 (abfd, ext->e_filebase);
166      /* FIXME XXX alignment?  */
167
168      /* Set relocation information for first section of each type.  */
169      if (trynum == 0)
170	switch (ext->e_type[0])
171	  {
172	  case N_TEXT:
173	    sect->rel_filepos = N_TRELOFF (*execp);
174	    sect->reloc_count = execp->a_trsize;
175	    break;
176
177	  case N_DATA:
178	    sect->rel_filepos = N_DRELOFF (*execp);
179	    sect->reloc_count = execp->a_drsize;
180	    break;
181
182	  default:
183	    break;
184	  }
185    }
186 no_more_sections:
187
188  adata (abfd).reloc_entry_size = sizeof (struct reloc_std_external);
189  adata (abfd).symbol_entry_size = sizeof (struct external_nlist);
190  adata (abfd).page_size = 1; /* Not applicable.  */
191  adata (abfd).segment_size = 1; /* Not applicable.  */
192  adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE;
193
194  return abfd->xvec;
195}
196
197static const bfd_target *
198aout_adobe_object_p (bfd *abfd)
199{
200  struct internal_exec anexec;
201  struct external_exec exec_bytes;
202  char *targ;
203  bfd_size_type amt = EXEC_BYTES_SIZE;
204
205  if (bfd_bread (& exec_bytes, amt, abfd) != amt)
206    {
207      if (bfd_get_error () != bfd_error_system_call)
208	bfd_set_error (bfd_error_wrong_format);
209      return NULL;
210    }
211
212  anexec.a_info = H_GET_32 (abfd, exec_bytes.e_info);
213
214  /* Normally we just compare for the magic number.
215     However, a bunch of Adobe tools aren't fixed up yet; they generate
216     files using ZMAGIC(!).
217     If the environment variable GNUTARGET is set to "a.out.adobe", we will
218     take just about any a.out file as an Adobe a.out file.  FIXME!  */
219
220  if (N_BADMAG (anexec))
221    {
222      targ = getenv ("GNUTARGET");
223      if (targ && !strcmp (targ, a_out_adobe_vec.name))
224	/* Just continue anyway, if specifically set to this format.  */
225	;
226      else
227	{
228	  bfd_set_error (bfd_error_wrong_format);
229	  return NULL;
230	}
231    }
232
233  aout_adobe_swap_exec_header_in (abfd, &exec_bytes, &anexec);
234  return aout_32_some_aout_object_p (abfd, &anexec, aout_adobe_callback);
235}
236
237struct bout_data_struct
238{
239  struct aoutdata a;
240  struct internal_exec e;
241};
242
243static bfd_boolean
244aout_adobe_mkobject (bfd *abfd)
245{
246  struct bout_data_struct *rawptr;
247  bfd_size_type amt = sizeof (struct bout_data_struct);
248
249  rawptr = bfd_zalloc (abfd, amt);
250  if (rawptr == NULL)
251    return FALSE;
252
253  abfd->tdata.bout_data = rawptr;
254  exec_hdr (abfd) = &rawptr->e;
255
256  adata (abfd).reloc_entry_size = sizeof (struct reloc_std_external);
257  adata (abfd).symbol_entry_size = sizeof (struct external_nlist);
258  adata (abfd).page_size = 1; /* Not applicable.  */
259  adata (abfd).segment_size = 1; /* Not applicable.  */
260  adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE;
261
262  return TRUE;
263}
264
265static void
266aout_adobe_write_section (bfd *abfd ATTRIBUTE_UNUSED,
267			  sec_ptr sect ATTRIBUTE_UNUSED)
268{
269  /* FIXME XXX.  */
270}
271
272static bfd_boolean
273aout_adobe_write_object_contents (bfd *abfd)
274{
275  struct external_exec swapped_hdr;
276  static struct external_segdesc sentinel[1];	/* Initialized to zero.  */
277  asection *sect;
278  bfd_size_type amt;
279
280  exec_hdr (abfd)->a_info = ZMAGIC;
281
282  /* Calculate text size as total of text sections, etc.  */
283  exec_hdr (abfd)->a_text = 0;
284  exec_hdr (abfd)->a_data = 0;
285  exec_hdr (abfd)->a_bss  = 0;
286  exec_hdr (abfd)->a_trsize = 0;
287  exec_hdr (abfd)->a_drsize = 0;
288
289  for (sect = abfd->sections; sect; sect = sect->next)
290    {
291      if (sect->flags & SEC_CODE)
292	{
293	  exec_hdr (abfd)->a_text += sect->size;
294	  exec_hdr (abfd)->a_trsize += sect->reloc_count *
295	    sizeof (struct reloc_std_external);
296	}
297      else if (sect->flags & SEC_DATA)
298	{
299	  exec_hdr (abfd)->a_data += sect->size;
300	  exec_hdr (abfd)->a_drsize += sect->reloc_count *
301	    sizeof (struct reloc_std_external);
302	}
303      else if (sect->flags & SEC_ALLOC && !(sect->flags & SEC_LOAD))
304	exec_hdr (abfd)->a_bss += sect->size;
305    }
306
307  exec_hdr (abfd)->a_syms = bfd_get_symcount (abfd)
308    * sizeof (struct external_nlist);
309  exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd);
310
311  aout_adobe_swap_exec_header_out (abfd, exec_hdr (abfd), &swapped_hdr);
312
313  amt = EXEC_BYTES_SIZE;
314  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
315      || bfd_bwrite (& swapped_hdr, amt, abfd) != amt)
316    return FALSE;
317
318  /* Now write out the section information.  Text first, data next, rest
319     afterward.  */
320  for (sect = abfd->sections; sect; sect = sect->next)
321    if (sect->flags & SEC_CODE)
322      aout_adobe_write_section (abfd, sect);
323
324  for (sect = abfd->sections; sect; sect = sect->next)
325    if (sect->flags & SEC_DATA)
326      aout_adobe_write_section (abfd, sect);
327
328  for (sect = abfd->sections; sect; sect = sect->next)
329    if (!(sect->flags & (SEC_CODE | SEC_DATA)))
330      aout_adobe_write_section (abfd, sect);
331
332  /* Write final `sentinel` section header (with type of 0).  */
333  amt = sizeof (*sentinel);
334  if (bfd_bwrite (sentinel, amt, abfd) != amt)
335    return FALSE;
336
337  /* Now write out reloc info, followed by syms and strings.  */
338  if (bfd_get_symcount (abfd) != 0)
339    {
340      if (bfd_seek (abfd, (file_ptr) (N_SYMOFF (*exec_hdr (abfd))), SEEK_SET)
341	  != 0)
342	return FALSE;
343
344      if (! aout_32_write_syms (abfd))
345	return FALSE;
346
347      if (bfd_seek (abfd, (file_ptr) (N_TRELOFF (*exec_hdr (abfd))), SEEK_SET)
348	  != 0)
349	return FALSE;
350
351      for (sect = abfd->sections; sect; sect = sect->next)
352	if (sect->flags & SEC_CODE)
353	  if (!aout_32_squirt_out_relocs (abfd, sect))
354	    return FALSE;
355
356      if (bfd_seek (abfd, (file_ptr) (N_DRELOFF (*exec_hdr (abfd))), SEEK_SET)
357	  != 0)
358	return FALSE;
359
360      for (sect = abfd->sections; sect; sect = sect->next)
361	if (sect->flags & SEC_DATA)
362	  if (!aout_32_squirt_out_relocs (abfd, sect))
363	    return FALSE;
364    }
365
366  return TRUE;
367}
368
369static bfd_boolean
370aout_adobe_set_section_contents (bfd *abfd,
371				 asection *section,
372				 const void * location,
373				 file_ptr offset,
374				 bfd_size_type count)
375{
376  file_ptr section_start;
377  sec_ptr sect;
378
379  /* Set by bfd.c handler.  */
380  if (! abfd->output_has_begun)
381    {
382      /* Assign file offsets to sections.  Text sections are first, and
383	 are contiguous.  Then data sections.  Everything else at the end.  */
384      section_start = N_TXTOFF (ignore<-->me);
385
386      for (sect = abfd->sections; sect; sect = sect->next)
387	{
388	  if (sect->flags & SEC_CODE)
389	    {
390	      sect->filepos = section_start;
391	      /* FIXME:  Round to alignment.  */
392	      section_start += sect->size;
393	    }
394	}
395
396      for (sect = abfd->sections; sect; sect = sect->next)
397	{
398	  if (sect->flags & SEC_DATA)
399	    {
400	      sect->filepos = section_start;
401	      /* FIXME:  Round to alignment.  */
402	      section_start += sect->size;
403	    }
404	}
405
406      for (sect = abfd->sections; sect; sect = sect->next)
407	{
408	  if (sect->flags & SEC_HAS_CONTENTS &&
409	      !(sect->flags & (SEC_CODE | SEC_DATA)))
410	    {
411	      sect->filepos = section_start;
412	      /* FIXME:  Round to alignment.  */
413	      section_start += sect->size;
414	    }
415	}
416    }
417
418  /* Regardless, once we know what we're doing, we might as well get
419     going.  */
420  if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0)
421    return FALSE;
422
423  if (count == 0)
424    return TRUE;
425
426  return bfd_bwrite (location, count, abfd) == count;
427}
428
429static bfd_boolean
430aout_adobe_set_arch_mach (bfd *abfd,
431			  enum bfd_architecture arch,
432			  unsigned long machine)
433{
434  if (! bfd_default_set_arch_mach (abfd, arch, machine))
435    return FALSE;
436
437  if (arch == bfd_arch_unknown
438      || arch == bfd_arch_m68k)
439    return TRUE;
440
441  return FALSE;
442}
443
444static int
445aout_adobe_sizeof_headers (bfd *ignore_abfd ATTRIBUTE_UNUSED,
446			   bfd_boolean ignore ATTRIBUTE_UNUSED)
447{
448  return sizeof (struct internal_exec);
449}
450
451/* Build the transfer vector for Adobe A.Out files.  */
452
453#define aout_32_bfd_make_debug_symbol ((asymbol *(*) (bfd *, void *, unsigned long)) bfd_nullvoidptr)
454#define aout_32_bfd_reloc_type_lookup ((reloc_howto_type *(*) (bfd *, bfd_reloc_code_real_type)) bfd_nullvoidptr)
455#define aout_32_close_and_cleanup                   aout_32_bfd_free_cached_info
456#define	aout_32_set_arch_mach		            aout_adobe_set_arch_mach
457#define	aout_32_set_section_contents	            aout_adobe_set_section_contents
458#define	aout_32_sizeof_headers		            aout_adobe_sizeof_headers
459#define aout_32_bfd_get_relocated_section_contents  bfd_generic_get_relocated_section_contents
460#define aout_32_get_section_contents_in_window      _bfd_generic_get_section_contents_in_window
461#define aout_32_bfd_relax_section                   bfd_generic_relax_section
462#define aout_32_bfd_gc_sections                     bfd_generic_gc_sections
463#define aout_32_bfd_merge_sections	            bfd_generic_merge_sections
464#define aout_32_bfd_is_group_section	            bfd_generic_is_group_section
465#define aout_32_bfd_discard_group	            bfd_generic_discard_group
466#define aout_32_section_already_linked              _bfd_generic_section_already_linked
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_final_link		            _bfd_generic_final_link
472#define aout_32_bfd_link_split_section	            _bfd_generic_link_split_section
473
474const bfd_target a_out_adobe_vec =
475{
476  "a.out.adobe",		/* Name.  */
477  bfd_target_aout_flavour,
478  BFD_ENDIAN_BIG,		/* Data byte order is unknown (big assumed).  */
479  BFD_ENDIAN_BIG,		/* Header byte order is big.  */
480  (HAS_RELOC | EXEC_P |		/* Object flags.  */
481   HAS_LINENO | HAS_DEBUG |
482   HAS_SYMS | HAS_LOCALS | WP_TEXT ),
483  /* section flags */
484  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_DATA | SEC_RELOC),
485  '_',				/* Symbol leading char.  */
486  ' ',				/* AR_pad_char.  */
487  16,				/* AR_max_namelen.  */
488
489  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
490  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
491  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
492  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
493  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
494  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Headers.  */
495
496  {_bfd_dummy_target, aout_adobe_object_p,	/* bfd_check_format.  */
497   bfd_generic_archive_p, _bfd_dummy_target},
498  {bfd_false, aout_adobe_mkobject,		/* bfd_set_format.  */
499   _bfd_generic_mkarchive, bfd_false},
500  {bfd_false, aout_adobe_write_object_contents,/* bfd_write_contents.  */
501   _bfd_write_archive_contents, bfd_false},
502
503  BFD_JUMP_TABLE_GENERIC (aout_32),
504  BFD_JUMP_TABLE_COPY (_bfd_generic),
505  BFD_JUMP_TABLE_CORE (_bfd_nocore),
506  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd),
507  BFD_JUMP_TABLE_SYMBOLS (aout_32),
508  BFD_JUMP_TABLE_RELOCS (aout_32),
509  BFD_JUMP_TABLE_WRITE (aout_32),
510  BFD_JUMP_TABLE_LINK (aout_32),
511  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
512
513  NULL,
514
515  NULL
516};
517