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