xref: /netbsd-src/external/gpl3/gdb.old/dist/bfd/i386lynx.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
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
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
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
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
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
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_and_read (abfd, reloc_size, reloc_size);
415   if (!relocs && reloc_size != 0)
416     {
417       free (reloc_cache);
418       return FALSE;
419     }
420 
421   if (each_size == RELOC_EXT_SIZE)
422     {
423       struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
424       unsigned int counter = 0;
425       arelent *cache_ptr = reloc_cache;
426 
427       for (; counter < count; counter++, rptr++, cache_ptr++)
428 	{
429 	  NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols,
430 					(bfd_size_type) bfd_get_symcount (abfd));
431 	}
432     }
433   else
434     {
435       struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
436       unsigned int counter = 0;
437       arelent *cache_ptr = reloc_cache;
438 
439       for (; counter < count; counter++, rptr++, cache_ptr++)
440 	{
441 	  NAME(lynx,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols,
442 					(bfd_size_type) bfd_get_symcount (abfd));
443 	}
444 
445     }
446 
447   bfd_release (abfd, relocs);
448   asect->relocation = reloc_cache;
449   asect->reloc_count = count;
450   return TRUE;
451 }
452 
453 
454 
455 /* Write out a relocation section into an object file.  */
456 
457 static bfd_boolean
458 NAME(lynx,squirt_out_relocs) (bfd *abfd, asection *section)
459 {
460   arelent **generic;
461   unsigned char *native, *natptr;
462   size_t each_size;
463   unsigned int count = section->reloc_count;
464   bfd_size_type natsize;
465 
466   if (count == 0)
467     return TRUE;
468 
469   each_size = obj_reloc_entry_size (abfd);
470   natsize = count;
471   natsize *= each_size;
472   native = (unsigned char *) bfd_zalloc (abfd, natsize);
473   if (!native)
474     return FALSE;
475 
476   generic = section->orelocation;
477 
478   if (each_size == RELOC_EXT_SIZE)
479     {
480       for (natptr = native;
481 	   count != 0;
482 	   --count, natptr += each_size, ++generic)
483 	NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr);
484     }
485   else
486     {
487       for (natptr = native;
488 	   count != 0;
489 	   --count, natptr += each_size, ++generic)
490 	NAME(lynx,swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr);
491     }
492 
493   if (bfd_bwrite (native, natsize, abfd) != natsize)
494     {
495       bfd_release (abfd, native);
496       return FALSE;
497     }
498   bfd_release (abfd, native);
499 
500   return TRUE;
501 }
502 
503 /* This is stupid.  This function should be a boolean predicate */
504 static long
505 NAME(lynx,canonicalize_reloc) (bfd *abfd,
506 			       sec_ptr section,
507 			       arelent **relptr,
508 			       asymbol **symbols)
509 {
510   arelent *tblptr = section->relocation;
511   unsigned int count;
512 
513   if (!(tblptr || NAME(lynx,slurp_reloc_table) (abfd, section, symbols)))
514     return -1;
515 
516   if (section->flags & SEC_CONSTRUCTOR)
517     {
518       arelent_chain *chain = section->constructor_chain;
519       for (count = 0; count < section->reloc_count; count++)
520 	{
521 	  *relptr++ = &chain->relent;
522 	  chain = chain->next;
523 	}
524     }
525   else
526     {
527       tblptr = section->relocation;
528 
529       for (count = 0; count++ < section->reloc_count;)
530 	{
531 	  *relptr++ = tblptr++;
532 	}
533     }
534   *relptr = 0;
535 
536   return section->reloc_count;
537 }
538 
539 #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc)
540 
541 #include "aout-target.h"
542