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