1/* BFD back-end for i386 a.out binaries under LynxOS.
2   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2001, 2002,
3   2003, 2007 Free Software Foundation, Inc.
4
5   This file is part of BFD, the Binary File Descriptor library.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22#define N_SHARED_LIB(x) 0
23
24#define TEXT_START_ADDR 0
25#define TARGET_PAGE_SIZE 4096
26#define SEGMENT_SIZE TARGET_PAGE_SIZE
27#define DEFAULT_ARCH bfd_arch_i386
28
29/* Do not "beautify" the CONCAT* macro args.  Traditional C will not
30   remove whitespace added here, and thus will fail to concatenate
31   the tokens.  */
32#define MY(OP) CONCAT2 (i386lynx_aout_,OP)
33#define TARGETNAME "a.out-i386-lynx"
34
35#include "sysdep.h"
36#include "bfd.h"
37#include "libbfd.h"
38
39#ifndef WRITE_HEADERS
40#define WRITE_HEADERS(abfd, execp)					      \
41      {									      \
42	bfd_size_type text_size; /* dummy vars */			      \
43	file_ptr text_end;						      \
44	if (adata(abfd).magic == undecided_magic)			      \
45	  NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end);     \
46    									      \
47	execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE;	      \
48	execp->a_entry = bfd_get_start_address (abfd);			      \
49    									      \
50	execp->a_trsize = ((obj_textsec (abfd)->reloc_count) *		      \
51			   obj_reloc_entry_size (abfd));		      \
52	execp->a_drsize = ((obj_datasec (abfd)->reloc_count) *		      \
53			   obj_reloc_entry_size (abfd));		      \
54	NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes);	      \
55									      \
56	if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0		      \
57	    || bfd_bwrite ((PTR) &exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE, \
58			  abfd) != EXEC_BYTES_SIZE)			      \
59	  return FALSE;							      \
60	/* Now write out reloc info, followed by syms and strings */	      \
61  									      \
62	if (bfd_get_symcount (abfd) != 0) 				      \
63	    {								      \
64	      if (bfd_seek (abfd, (file_ptr) (N_SYMOFF(*execp)), SEEK_SET)    \
65		  != 0)							      \
66	        return FALSE;						      \
67									      \
68	      if (! NAME(aout,write_syms) (abfd)) return FALSE;		      \
69									      \
70	      if (bfd_seek (abfd, (file_ptr) (N_TRELOFF(*execp)), SEEK_SET)   \
71		  != 0)							      \
72	        return FALSE;						      \
73									      \
74	      if (!NAME(lynx,squirt_out_relocs) (abfd, obj_textsec (abfd)))   \
75		return FALSE;						      \
76	      if (bfd_seek (abfd, (file_ptr) (N_DRELOFF(*execp)), SEEK_SET)   \
77		  != 0)							      \
78	        return 0;						      \
79									      \
80	      if (!NAME(lynx,squirt_out_relocs) (abfd, obj_datasec (abfd)))   \
81		return FALSE;						      \
82	    }								      \
83      }
84#endif
85
86#include "libaout.h"
87#include "aout/aout64.h"
88
89void NAME (lynx,swap_std_reloc_out)
90  PARAMS ((bfd *, arelent *, struct reloc_std_external *));
91void NAME (lynx,swap_ext_reloc_out)
92  PARAMS ((bfd *, arelent *, struct reloc_ext_external *));
93void NAME (lynx,swap_ext_reloc_in)
94  PARAMS ((bfd *, struct reloc_ext_external *, arelent *, asymbol **,
95	   bfd_size_type));
96void NAME (lynx,swap_std_reloc_in)
97  PARAMS ((bfd *, struct reloc_std_external *, arelent *, asymbol **,
98	   bfd_size_type));
99bfd_boolean NAME (lynx,slurp_reloc_table)
100  PARAMS ((bfd *, sec_ptr, asymbol **));
101bfd_boolean NAME (lynx,squirt_out_relocs)
102  PARAMS ((bfd *, asection *));
103long NAME (lynx,canonicalize_reloc)
104  PARAMS ((bfd *, sec_ptr, arelent **, asymbol **));
105
106#ifdef LYNX_CORE
107
108char *lynx_core_file_failing_command ();
109int lynx_core_file_failing_signal ();
110bfd_boolean lynx_core_file_matches_executable_p ();
111const bfd_target *lynx_core_file_p ();
112
113#define	MY_core_file_failing_command lynx_core_file_failing_command
114#define	MY_core_file_failing_signal lynx_core_file_failing_signal
115#define	MY_core_file_matches_executable_p lynx_core_file_matches_executable_p
116#define	MY_core_file_p lynx_core_file_p
117
118#endif /* LYNX_CORE */
119
120
121#define KEEPIT udata.i
122
123extern reloc_howto_type aout_32_ext_howto_table[];
124extern reloc_howto_type aout_32_std_howto_table[];
125
126/* Standard reloc stuff */
127/* Output standard relocation information to a file in target byte order. */
128
129void
130NAME(lynx,swap_std_reloc_out) (abfd, g, natptr)
131     bfd *abfd;
132     arelent *g;
133     struct reloc_std_external *natptr;
134{
135  int r_index;
136  asymbol *sym = *(g->sym_ptr_ptr);
137  int r_extern;
138  unsigned int r_length;
139  int r_pcrel;
140  int r_baserel, r_jmptable, r_relative;
141  unsigned int r_addend;
142  asection *output_section = sym->section->output_section;
143
144  PUT_WORD (abfd, g->address, natptr->r_address);
145
146  r_length = g->howto->size;	/* Size as a power of two */
147  r_pcrel = (int) g->howto->pc_relative;	/* Relative to PC? */
148  /* r_baserel, r_jmptable, r_relative???  FIXME-soon */
149  r_baserel = 0;
150  r_jmptable = 0;
151  r_relative = 0;
152
153  r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
154
155  /* name was clobbered by aout_write_syms to be symbol index */
156
157  /* If this relocation is relative to a symbol then set the
158     r_index to the symbols index, and the r_extern bit.
159
160     Absolute symbols can come in in two ways, either as an offset
161     from the abs section, or as a symbol which has an abs value.
162     check for that here
163  */
164
165
166  if (bfd_is_com_section (output_section)
167      || bfd_is_abs_section (output_section)
168      || bfd_is_und_section (output_section))
169    {
170      if (bfd_abs_section_ptr->symbol == sym)
171	{
172	  /* Whoops, looked like an abs symbol, but is really an offset
173	     from the abs section */
174	  r_index = 0;
175	  r_extern = 0;
176	}
177      else
178	{
179	  /* Fill in symbol */
180	  r_extern = 1;
181	  r_index = (*g->sym_ptr_ptr)->KEEPIT;
182	}
183    }
184  else
185    {
186      /* Just an ordinary section */
187      r_extern = 0;
188      r_index = output_section->target_index;
189    }
190
191  /* now the fun stuff */
192  if (bfd_header_big_endian (abfd))
193    {
194      natptr->r_index[0] = r_index >> 16;
195      natptr->r_index[1] = r_index >> 8;
196      natptr->r_index[2] = r_index;
197      natptr->r_type[0] =
198	(r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
199	| (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
200	| (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
201	| (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
202	| (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
203	| (r_length << RELOC_STD_BITS_LENGTH_SH_BIG);
204    }
205  else
206    {
207      natptr->r_index[2] = r_index >> 16;
208      natptr->r_index[1] = r_index >> 8;
209      natptr->r_index[0] = r_index;
210      natptr->r_type[0] =
211	(r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
212	| (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
213	| (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
214	| (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
215	| (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
216	| (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE);
217    }
218}
219
220
221/* Extended stuff */
222/* Output extended relocation information to a file in target byte order. */
223
224void
225NAME(lynx,swap_ext_reloc_out) (abfd, g, natptr)
226     bfd *abfd;
227     arelent *g;
228     register struct reloc_ext_external *natptr;
229{
230  int r_index;
231  int r_extern;
232  unsigned int r_type;
233  unsigned int r_addend;
234  asymbol *sym = *(g->sym_ptr_ptr);
235  asection *output_section = sym->section->output_section;
236
237  PUT_WORD (abfd, g->address, natptr->r_address);
238
239  r_type = (unsigned int) g->howto->type;
240
241  r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
242
243
244  /* If this relocation is relative to a symbol then set the
245     r_index to the symbols index, and the r_extern bit.
246
247     Absolute symbols can come in in two ways, either as an offset
248     from the abs section, or as a symbol which has an abs value.
249     check for that here
250     */
251
252  if (bfd_is_com_section (output_section)
253      || bfd_is_abs_section (output_section)
254      || bfd_is_und_section (output_section))
255    {
256      if (bfd_abs_section_ptr->symbol == sym)
257	{
258	  /* Whoops, looked like an abs symbol, but is really an offset
259	 from the abs section */
260	  r_index = 0;
261	  r_extern = 0;
262	}
263      else
264	{
265	  r_extern = 1;
266	  r_index = (*g->sym_ptr_ptr)->KEEPIT;
267	}
268    }
269  else
270    {
271      /* Just an ordinary section */
272      r_extern = 0;
273      r_index = output_section->target_index;
274    }
275
276
277  /* now the fun stuff */
278  if (bfd_header_big_endian (abfd))
279    {
280      natptr->r_index[0] = r_index >> 16;
281      natptr->r_index[1] = r_index >> 8;
282      natptr->r_index[2] = r_index;
283      natptr->r_type[0] =
284	(r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
285	| (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
286    }
287  else
288    {
289      natptr->r_index[2] = r_index >> 16;
290      natptr->r_index[1] = r_index >> 8;
291      natptr->r_index[0] = r_index;
292      natptr->r_type[0] =
293	(r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
294	| (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
295    }
296
297  PUT_WORD (abfd, r_addend, natptr->r_addend);
298}
299
300/* BFD deals internally with all things based from the section they're
301   in. so, something in 10 bytes into a text section  with a base of
302   50 would have a symbol (.text+10) and know .text vma was 50.
303
304   Aout keeps all it's symbols based from zero, so the symbol would
305   contain 60. This macro subs the base of each section from the value
306   to give the true offset from the section */
307
308
309#define MOVE_ADDRESS(ad)       						\
310  if (r_extern) {							\
311   /* undefined symbol */						\
312     cache_ptr->sym_ptr_ptr = symbols + r_index;			\
313     cache_ptr->addend = ad;						\
314     } else {								\
315    /* defined, section relative. replace symbol with pointer to    	\
316       symbol which points to section  */				\
317    switch (r_index) {							\
318    case N_TEXT:							\
319    case N_TEXT | N_EXT:						\
320      cache_ptr->sym_ptr_ptr  = obj_textsec(abfd)->symbol_ptr_ptr;	\
321      cache_ptr->addend = ad  - su->textsec->vma;			\
322      break;								\
323    case N_DATA:							\
324    case N_DATA | N_EXT:						\
325      cache_ptr->sym_ptr_ptr  = obj_datasec(abfd)->symbol_ptr_ptr;	\
326      cache_ptr->addend = ad - su->datasec->vma;			\
327      break;								\
328    case N_BSS:								\
329    case N_BSS | N_EXT:							\
330      cache_ptr->sym_ptr_ptr  = obj_bsssec(abfd)->symbol_ptr_ptr;	\
331      cache_ptr->addend = ad - su->bsssec->vma;				\
332      break;								\
333    default:								\
334    case N_ABS:								\
335    case N_ABS | N_EXT:							\
336     cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;	\
337      cache_ptr->addend = ad;						\
338      break;								\
339    }									\
340  }     								\
341
342void
343NAME(lynx,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
344     bfd *abfd;
345     struct reloc_ext_external *bytes;
346     arelent *cache_ptr;
347     asymbol **symbols;
348     bfd_size_type symcount ATTRIBUTE_UNUSED;
349{
350  int r_index;
351  int r_extern;
352  unsigned int r_type;
353  struct aoutdata *su = &(abfd->tdata.aout_data->a);
354
355  cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
356
357  r_index = bytes->r_index[1];
358  r_extern = (0 != (bytes->r_index[0] & RELOC_EXT_BITS_EXTERN_BIG));
359  r_type = (bytes->r_index[0] & RELOC_EXT_BITS_TYPE_BIG)
360    >> RELOC_EXT_BITS_TYPE_SH_BIG;
361
362  cache_ptr->howto = aout_32_ext_howto_table + r_type;
363  MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend));
364}
365
366void
367NAME(lynx,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
368     bfd *abfd;
369     struct reloc_std_external *bytes;
370     arelent *cache_ptr;
371     asymbol **symbols;
372     bfd_size_type symcount ATTRIBUTE_UNUSED;
373{
374  int r_index;
375  int r_extern;
376  unsigned int r_length;
377  int r_pcrel;
378  int r_baserel, r_jmptable, r_relative;
379  struct aoutdata *su = &(abfd->tdata.aout_data->a);
380
381  cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
382
383  r_index = bytes->r_index[1];
384  r_extern = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG));
385  r_pcrel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_BIG));
386  r_baserel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_BASEREL_BIG));
387  r_jmptable = (0 != (bytes->r_index[0] & RELOC_STD_BITS_JMPTABLE_BIG));
388  r_relative = (0 != (bytes->r_index[0] & RELOC_STD_BITS_RELATIVE_BIG));
389  r_length = (bytes->r_index[0] & RELOC_STD_BITS_LENGTH_BIG)
390    >> RELOC_STD_BITS_LENGTH_SH_BIG;
391
392  cache_ptr->howto = aout_32_std_howto_table + r_length + 4 * r_pcrel;
393  /* FIXME-soon:  Roll baserel, jmptable, relative bits into howto setting */
394
395  MOVE_ADDRESS (0);
396}
397
398/* Reloc hackery */
399
400bfd_boolean
401NAME(lynx,slurp_reloc_table) (abfd, asect, symbols)
402     bfd *abfd;
403     sec_ptr asect;
404     asymbol **symbols;
405{
406  bfd_size_type count;
407  bfd_size_type reloc_size;
408  PTR relocs;
409  arelent *reloc_cache;
410  size_t each_size;
411
412  if (asect->relocation)
413    return TRUE;
414
415  if (asect->flags & SEC_CONSTRUCTOR)
416    return TRUE;
417
418  if (asect == obj_datasec (abfd))
419    {
420      reloc_size = exec_hdr (abfd)->a_drsize;
421      goto doit;
422    }
423
424  if (asect == obj_textsec (abfd))
425    {
426      reloc_size = exec_hdr (abfd)->a_trsize;
427      goto doit;
428    }
429
430  bfd_set_error (bfd_error_invalid_operation);
431  return FALSE;
432
433doit:
434  if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
435    return FALSE;
436  each_size = obj_reloc_entry_size (abfd);
437
438  count = reloc_size / each_size;
439
440
441  reloc_cache = (arelent *) bfd_zmalloc (count * sizeof (arelent));
442  if (!reloc_cache && count != 0)
443    return FALSE;
444
445  relocs = (PTR) bfd_alloc (abfd, reloc_size);
446  if (!relocs && reloc_size != 0)
447    {
448      free (reloc_cache);
449      return FALSE;
450    }
451
452  if (bfd_bread (relocs, reloc_size, abfd) != reloc_size)
453    {
454      bfd_release (abfd, relocs);
455      free (reloc_cache);
456      return FALSE;
457    }
458
459  if (each_size == RELOC_EXT_SIZE)
460    {
461      register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
462      unsigned int counter = 0;
463      arelent *cache_ptr = reloc_cache;
464
465      for (; counter < count; counter++, rptr++, cache_ptr++)
466	{
467	  NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols,
468					(bfd_size_type) bfd_get_symcount (abfd));
469	}
470    }
471  else
472    {
473      register struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
474      unsigned int counter = 0;
475      arelent *cache_ptr = reloc_cache;
476
477      for (; counter < count; counter++, rptr++, cache_ptr++)
478	{
479	  NAME(lynx,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols,
480					(bfd_size_type) bfd_get_symcount (abfd));
481	}
482
483    }
484
485  bfd_release (abfd, relocs);
486  asect->relocation = reloc_cache;
487  asect->reloc_count = count;
488  return TRUE;
489}
490
491
492
493/* Write out a relocation section into an object file.  */
494
495bfd_boolean
496NAME(lynx,squirt_out_relocs) (abfd, section)
497     bfd *abfd;
498     asection *section;
499{
500  arelent **generic;
501  unsigned char *native, *natptr;
502  size_t each_size;
503
504  unsigned int count = section->reloc_count;
505  bfd_size_type natsize;
506
507  if (count == 0)
508    return TRUE;
509
510  each_size = obj_reloc_entry_size (abfd);
511  natsize = count;
512  natsize *= each_size;
513  native = (unsigned char *) bfd_zalloc (abfd, natsize);
514  if (!native)
515    return FALSE;
516
517  generic = section->orelocation;
518
519  if (each_size == RELOC_EXT_SIZE)
520    {
521      for (natptr = native;
522	   count != 0;
523	   --count, natptr += each_size, ++generic)
524	NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr);
525    }
526  else
527    {
528      for (natptr = native;
529	   count != 0;
530	   --count, natptr += each_size, ++generic)
531	NAME(lynx,swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr);
532    }
533
534  if (bfd_bwrite ((PTR) native, natsize, abfd) != natsize)
535    {
536      bfd_release (abfd, native);
537      return FALSE;
538    }
539  bfd_release (abfd, native);
540
541  return TRUE;
542}
543
544/* This is stupid.  This function should be a boolean predicate */
545long
546NAME(lynx,canonicalize_reloc) (abfd, section, relptr, symbols)
547     bfd *abfd;
548     sec_ptr section;
549     arelent **relptr;
550     asymbol **symbols;
551{
552  arelent *tblptr = section->relocation;
553  unsigned int count;
554
555  if (!(tblptr || NAME(lynx,slurp_reloc_table) (abfd, section, symbols)))
556    return -1;
557
558  if (section->flags & SEC_CONSTRUCTOR)
559    {
560      arelent_chain *chain = section->constructor_chain;
561      for (count = 0; count < section->reloc_count; count++)
562	{
563	  *relptr++ = &chain->relent;
564	  chain = chain->next;
565	}
566    }
567  else
568    {
569      tblptr = section->relocation;
570
571      for (count = 0; count++ < section->reloc_count;)
572	{
573	  *relptr++ = tblptr++;
574	}
575    }
576  *relptr = 0;
577
578  return section->reloc_count;
579}
580
581#define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc)
582
583#include "aout-target.h"
584