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