xref: /netbsd-src/external/gpl3/gdb.old/dist/bfd/i386lynx.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1 /* BFD back-end for i386 a.out binaries under LynxOS.
2    Copyright (C) 1990-2022 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 bool lynx_core_file_matches_executable_p ();
90 bfd_cleanup 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 = bfd_log2 (bfd_get_reloc_size (g->howto));
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       if (symbols != NULL && r_index < bfd_get_symcount (abfd))		\
287 	cache_ptr->sym_ptr_ptr = symbols + r_index;			\
288       else								\
289 	cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;	\
290       cache_ptr->addend = ad;						\
291     }									\
292   else									\
293     {									\
294       /* defined, section relative. replace symbol with pointer to	\
295 	 symbol which points to section  */				\
296       switch (r_index)							\
297 	{								\
298 	case N_TEXT:							\
299 	case N_TEXT | N_EXT:						\
300 	  cache_ptr->sym_ptr_ptr  = obj_textsec(abfd)->symbol_ptr_ptr;	\
301 	  cache_ptr->addend = ad  - su->textsec->vma;			\
302 	  break;							\
303 	case N_DATA:							\
304 	case N_DATA | N_EXT:						\
305 	  cache_ptr->sym_ptr_ptr  = obj_datasec(abfd)->symbol_ptr_ptr;	\
306 	  cache_ptr->addend = ad - su->datasec->vma;			\
307 	  break;							\
308 	case N_BSS:							\
309 	case N_BSS | N_EXT:						\
310 	  cache_ptr->sym_ptr_ptr  = obj_bsssec(abfd)->symbol_ptr_ptr;	\
311 	  cache_ptr->addend = ad - su->bsssec->vma;			\
312 	  break;							\
313 	default:							\
314 	case N_ABS:							\
315 	case N_ABS | N_EXT:						\
316 	  cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;	\
317 	  cache_ptr->addend = ad;					\
318 	  break;							\
319 	}								\
320     }									\
321 
322 static void
323 NAME(lynx,swap_ext_reloc_in) (bfd *abfd,
324 			      struct reloc_ext_external *bytes,
325 			      arelent *cache_ptr,
326 			      asymbol **symbols,
327 			      bfd_size_type symcount ATTRIBUTE_UNUSED)
328 {
329   unsigned int r_index;
330   int r_extern;
331   unsigned int r_type;
332   struct aoutdata *su = &(abfd->tdata.aout_data->a);
333 
334   cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
335 
336   r_index = bytes->r_index[1];
337   r_extern = (0 != (bytes->r_index[0] & RELOC_EXT_BITS_EXTERN_BIG));
338   r_type = (bytes->r_index[0] & RELOC_EXT_BITS_TYPE_BIG)
339     >> RELOC_EXT_BITS_TYPE_SH_BIG;
340 
341   cache_ptr->howto = aout_32_ext_howto_table + r_type;
342   MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend));
343 }
344 
345 static void
346 NAME(lynx,swap_std_reloc_in) (bfd *abfd,
347 			      struct reloc_std_external *bytes,
348 			      arelent *cache_ptr,
349 			      asymbol **symbols,
350 			      bfd_size_type symcount ATTRIBUTE_UNUSED)
351 {
352   unsigned int r_index;
353   int r_extern;
354   unsigned int r_length;
355   int r_pcrel;
356   struct aoutdata *su = &(abfd->tdata.aout_data->a);
357 
358   cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
359 
360   r_index = bytes->r_index[1];
361   r_extern = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG));
362   r_pcrel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_BIG));
363   r_length = (bytes->r_index[0] & RELOC_STD_BITS_LENGTH_BIG)
364     >> RELOC_STD_BITS_LENGTH_SH_BIG;
365 
366   cache_ptr->howto = aout_32_std_howto_table + r_length + 4 * r_pcrel;
367   /* FIXME-soon:  Roll baserel, jmptable, relative bits into howto setting */
368 
369   MOVE_ADDRESS (0);
370 }
371 
372 /* Reloc hackery */
373 
374 static bool
375 NAME(lynx,slurp_reloc_table) (bfd *abfd,
376 			      sec_ptr asect,
377 			      asymbol **symbols)
378 {
379   bfd_size_type count;
380   bfd_size_type reloc_size;
381   void * relocs;
382   arelent *reloc_cache;
383   size_t each_size;
384 
385   if (asect->relocation)
386     return true;
387 
388   if (asect->flags & SEC_CONSTRUCTOR)
389     return true;
390 
391   if (asect == obj_datasec (abfd))
392     {
393       reloc_size = exec_hdr (abfd)->a_drsize;
394       goto doit;
395     }
396 
397   if (asect == obj_textsec (abfd))
398     {
399       reloc_size = exec_hdr (abfd)->a_trsize;
400       goto doit;
401     }
402 
403   bfd_set_error (bfd_error_invalid_operation);
404   return false;
405 
406  doit:
407   if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
408     return false;
409   each_size = obj_reloc_entry_size (abfd);
410 
411   count = reloc_size / each_size;
412 
413 
414   reloc_cache = (arelent *) bfd_zmalloc (count * sizeof (arelent));
415   if (!reloc_cache && count != 0)
416     return false;
417 
418   relocs = _bfd_alloc_and_read (abfd, reloc_size, reloc_size);
419   if (!relocs && reloc_size != 0)
420     {
421       free (reloc_cache);
422       return false;
423     }
424 
425   if (each_size == RELOC_EXT_SIZE)
426     {
427       struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
428       unsigned int counter = 0;
429       arelent *cache_ptr = reloc_cache;
430 
431       for (; counter < count; counter++, rptr++, cache_ptr++)
432 	{
433 	  NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols,
434 					(bfd_size_type) bfd_get_symcount (abfd));
435 	}
436     }
437   else
438     {
439       struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
440       unsigned int counter = 0;
441       arelent *cache_ptr = reloc_cache;
442 
443       for (; counter < count; counter++, rptr++, cache_ptr++)
444 	{
445 	  NAME(lynx,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols,
446 					(bfd_size_type) bfd_get_symcount (abfd));
447 	}
448 
449     }
450 
451   bfd_release (abfd, relocs);
452   asect->relocation = reloc_cache;
453   asect->reloc_count = count;
454   return true;
455 }
456 
457 
458 
459 /* Write out a relocation section into an object file.  */
460 
461 static bool
462 NAME(lynx,squirt_out_relocs) (bfd *abfd, asection *section)
463 {
464   arelent **generic;
465   unsigned char *native, *natptr;
466   size_t each_size;
467   unsigned int count = section->reloc_count;
468   bfd_size_type natsize;
469 
470   if (count == 0)
471     return true;
472 
473   each_size = obj_reloc_entry_size (abfd);
474   natsize = count;
475   natsize *= each_size;
476   native = (unsigned char *) bfd_zalloc (abfd, natsize);
477   if (!native)
478     return false;
479 
480   generic = section->orelocation;
481 
482   if (each_size == RELOC_EXT_SIZE)
483     {
484       for (natptr = native;
485 	   count != 0;
486 	   --count, natptr += each_size, ++generic)
487 	NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr);
488     }
489   else
490     {
491       for (natptr = native;
492 	   count != 0;
493 	   --count, natptr += each_size, ++generic)
494 	NAME(lynx,swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr);
495     }
496 
497   if (bfd_bwrite (native, natsize, abfd) != natsize)
498     {
499       bfd_release (abfd, native);
500       return false;
501     }
502   bfd_release (abfd, native);
503 
504   return true;
505 }
506 
507 /* This is stupid.  This function should be a boolean predicate */
508 static long
509 NAME(lynx,canonicalize_reloc) (bfd *abfd,
510 			       sec_ptr section,
511 			       arelent **relptr,
512 			       asymbol **symbols)
513 {
514   arelent *tblptr = section->relocation;
515   unsigned int count;
516 
517   if (!(tblptr || NAME(lynx,slurp_reloc_table) (abfd, section, symbols)))
518     return -1;
519 
520   if (section->flags & SEC_CONSTRUCTOR)
521     {
522       arelent_chain *chain = section->constructor_chain;
523       for (count = 0; count < section->reloc_count; count++)
524 	{
525 	  *relptr++ = &chain->relent;
526 	  chain = chain->next;
527 	}
528     }
529   else
530     {
531       tblptr = section->relocation;
532 
533       for (count = 0; count++ < section->reloc_count;)
534 	{
535 	  *relptr++ = tblptr++;
536 	}
537     }
538   *relptr = 0;
539 
540   return section->reloc_count;
541 }
542 
543 #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc)
544 
545 #include "aout-target.h"
546