1 /* BFD back-end for i386 a.out binaries under LynxOS.
2    Copyright (C) 1990-2020 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 
87 char *lynx_core_file_failing_command ();
88 int lynx_core_file_failing_signal ();
89 bfd_boolean lynx_core_file_matches_executable_p ();
90 const 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 
102 extern reloc_howto_type aout_32_ext_howto_table[];
103 extern 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 
108 static void
NAME(lynx,swap_std_reloc_out)109 NAME(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 
198 static void
NAME(lynx,swap_ext_reloc_out)199 NAME(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 
318 static void
NAME(lynx,swap_ext_reloc_in)319 NAME(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 
341 static void
NAME(lynx,swap_std_reloc_in)342 NAME(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 
370 static bfd_boolean
NAME(lynx,slurp_reloc_table)371 NAME(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 
402 doit:
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 
464 static bfd_boolean
NAME(lynx,squirt_out_relocs)465 NAME(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 */
511 static long
NAME(lynx,canonicalize_reloc)512 NAME(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