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