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 
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 2 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, 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 
88 void NAME (lynx,swap_std_reloc_out)
89   PARAMS ((bfd *, arelent *, struct reloc_std_external *));
90 void NAME (lynx,swap_ext_reloc_out)
91   PARAMS ((bfd *, arelent *, struct reloc_ext_external *));
92 void NAME (lynx,swap_ext_reloc_in)
93   PARAMS ((bfd *, struct reloc_ext_external *, arelent *, asymbol **,
94 	   bfd_size_type));
95 void NAME (lynx,swap_std_reloc_in)
96   PARAMS ((bfd *, struct reloc_std_external *, arelent *, asymbol **,
97 	   bfd_size_type));
98 bfd_boolean NAME (lynx,slurp_reloc_table)
99   PARAMS ((bfd *, sec_ptr, asymbol **));
100 bfd_boolean NAME (lynx,squirt_out_relocs)
101   PARAMS ((bfd *, asection *));
102 long NAME (lynx,canonicalize_reloc)
103   PARAMS ((bfd *, sec_ptr, arelent **, asymbol **));
104 
105 #ifdef LYNX_CORE
106 
107 char *lynx_core_file_failing_command ();
108 int lynx_core_file_failing_signal ();
109 bfd_boolean lynx_core_file_matches_executable_p ();
110 const 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 
122 extern reloc_howto_type aout_32_ext_howto_table[];
123 extern 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 
128 void
129 NAME(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 
223 void
224 NAME(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 
341 void
342 NAME(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 
365 void
366 NAME(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 
399 bfd_boolean
400 NAME(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 
432 doit:
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 
494 bfd_boolean
495 NAME(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 */
544 long
545 NAME(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