1 /* BFD back-end for i386 a.out binaries under LynxOS.
2    Copyright (C) 1990-2024 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, 0, SEEK_SET) != 0                                       \
52           || bfd_write (&exec_bytes, 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_outsymbols (abfd) != NULL                                       \
58           && bfd_get_symcount (abfd) != 0)                                      \
59       {                                                                                   \
60           if (bfd_seek (abfd, N_SYMOFF (execp), SEEK_SET) != 0)                 \
61             return false;                                                                 \
62                                                                                           \
63           if (! NAME (aout, write_syms) (abfd))                                 \
64             return false;                                                                 \
65       }                                                                                   \
66                                                                                           \
67     if (bfd_seek (abfd, N_TRELOFF (execp), SEEK_SET) != 0)            \
68       return false;                                                             \
69     if (!NAME (lynx, squirt_out_relocs) (abfd, obj_textsec (abfd)))   \
70       return false;                                                             \
71                                                                                           \
72     if (bfd_seek (abfd, N_DRELOFF (execp), SEEK_SET) != 0)            \
73       return false;                                                             \
74     if (!NAME (lynx, squirt_out_relocs) (abfd, obj_datasec (abfd)))   \
75       return false;                                                             \
76   }
77 #endif
78 
79 #include "libaout.h"
80 #include "aout/aout64.h"
81 
82 
83 #ifdef LYNX_CORE
84 
85 char *lynx_core_file_failing_command ();
86 int lynx_core_file_failing_signal ();
87 bool lynx_core_file_matches_executable_p ();
88 bfd_cleanup lynx_core_file_p ();
89 
90 #define   MY_core_file_failing_command lynx_core_file_failing_command
91 #define   MY_core_file_failing_signal lynx_core_file_failing_signal
92 #define   MY_core_file_matches_executable_p lynx_core_file_matches_executable_p
93 #define   MY_core_file_p lynx_core_file_p
94 
95 #endif /* LYNX_CORE */
96 
97 
98 #define KEEPIT udata.i
99 
100 extern reloc_howto_type aout_32_ext_howto_table[];
101 extern reloc_howto_type aout_32_std_howto_table[];
102 
103 /* Standard reloc stuff */
104 /* Output standard relocation information to a file in target byte order. */
105 
106 static void
NAME(lynx,swap_std_reloc_out)107 NAME(lynx,swap_std_reloc_out) (bfd *abfd,
108                                      arelent *g,
109                                      struct reloc_std_external *natptr)
110 {
111   int r_index;
112   asymbol *sym = *(g->sym_ptr_ptr);
113   int r_extern;
114   unsigned int r_length;
115   int r_pcrel;
116   int r_baserel, r_jmptable, r_relative;
117   asection *output_section = sym->section->output_section;
118 
119   PUT_WORD (abfd, g->address, natptr->r_address);
120 
121   r_length = bfd_log2 (bfd_get_reloc_size (g->howto));
122   r_pcrel = (int) g->howto->pc_relative;          /* Relative to PC? */
123   /* r_baserel, r_jmptable, r_relative???  FIXME-soon */
124   r_baserel = 0;
125   r_jmptable = 0;
126   r_relative = 0;
127 
128   /* name was clobbered by aout_write_syms to be symbol index */
129 
130   /* If this relocation is relative to a symbol then set the
131      r_index to the symbols index, and the r_extern bit.
132 
133      Absolute symbols can come in in two ways, either as an offset
134      from the abs section, or as a symbol which has an abs value.
135      check for that here
136   */
137 
138   if (bfd_is_com_section (output_section)
139       || bfd_is_abs_section (output_section)
140       || bfd_is_und_section (output_section))
141     {
142       if (bfd_abs_section_ptr->symbol == sym)
143           {
144             /* Whoops, looked like an abs symbol, but is really an offset
145                from the abs section */
146             r_index = 0;
147             r_extern = 0;
148           }
149       else
150           {
151             /* Fill in symbol */
152             r_extern = 1;
153             r_index = (*g->sym_ptr_ptr)->KEEPIT;
154           }
155     }
156   else
157     {
158       /* Just an ordinary section */
159       r_extern = 0;
160       r_index = output_section->target_index;
161     }
162 
163   /* now the fun stuff */
164   if (bfd_header_big_endian (abfd))
165     {
166       natptr->r_index[0] = r_index >> 16;
167       natptr->r_index[1] = r_index >> 8;
168       natptr->r_index[2] = r_index;
169       natptr->r_type[0] =
170           (r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
171           | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
172           | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
173           | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
174           | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
175           | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG);
176     }
177   else
178     {
179       natptr->r_index[2] = r_index >> 16;
180       natptr->r_index[1] = r_index >> 8;
181       natptr->r_index[0] = r_index;
182       natptr->r_type[0] =
183           (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
184           | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
185           | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
186           | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
187           | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
188           | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE);
189     }
190 }
191 
192 
193 /* Extended stuff */
194 /* Output extended relocation information to a file in target byte order. */
195 
196 static void
NAME(lynx,swap_ext_reloc_out)197 NAME(lynx,swap_ext_reloc_out) (bfd *abfd,
198                                      arelent *g,
199                                      struct reloc_ext_external *natptr)
200 {
201   int r_index;
202   int r_extern;
203   unsigned int r_type;
204   unsigned int r_addend;
205   asymbol *sym = *(g->sym_ptr_ptr);
206   asection *output_section = sym->section->output_section;
207 
208   PUT_WORD (abfd, g->address, natptr->r_address);
209 
210   r_type = (unsigned int) g->howto->type;
211 
212   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
213 
214 
215   /* If this relocation is relative to a symbol then set the
216      r_index to the symbols index, and the r_extern bit.
217 
218      Absolute symbols can come in in two ways, either as an offset
219      from the abs section, or as a symbol which has an abs value.
220      check for that here
221      */
222 
223   if (bfd_is_com_section (output_section)
224       || bfd_is_abs_section (output_section)
225       || bfd_is_und_section (output_section))
226     {
227       if (bfd_abs_section_ptr->symbol == sym)
228           {
229             /* Whoops, looked like an abs symbol, but is really an offset
230            from the abs section */
231             r_index = 0;
232             r_extern = 0;
233           }
234       else
235           {
236             r_extern = 1;
237             r_index = (*g->sym_ptr_ptr)->KEEPIT;
238           }
239     }
240   else
241     {
242       /* Just an ordinary section */
243       r_extern = 0;
244       r_index = output_section->target_index;
245     }
246 
247 
248   /* now the fun stuff */
249   if (bfd_header_big_endian (abfd))
250     {
251       natptr->r_index[0] = r_index >> 16;
252       natptr->r_index[1] = r_index >> 8;
253       natptr->r_index[2] = r_index;
254       natptr->r_type[0] =
255           (r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
256           | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
257     }
258   else
259     {
260       natptr->r_index[2] = r_index >> 16;
261       natptr->r_index[1] = r_index >> 8;
262       natptr->r_index[0] = r_index;
263       natptr->r_type[0] =
264           (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
265           | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
266     }
267 
268   PUT_WORD (abfd, r_addend, natptr->r_addend);
269 }
270 
271 /* BFD deals internally with all things based from the section they're
272    in. so, something in 10 bytes into a text section  with a base of
273    50 would have a symbol (.text+10) and know .text vma was 50.
274 
275    Aout keeps all it's symbols based from zero, so the symbol would
276    contain 60. This macro subs the base of each section from the value
277    to give the true offset from the section */
278 
279 
280 #define MOVE_ADDRESS(ad)                                                        \
281   if (r_extern)                                                                           \
282     {                                                                                     \
283       /* undefined symbol */                                                    \
284       if (symbols != NULL && r_index < bfd_get_symcount (abfd))                 \
285           cache_ptr->sym_ptr_ptr = symbols + r_index;                           \
286       else                                                                                \
287           cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;         \
288       cache_ptr->addend = ad;                                                   \
289     }                                                                                     \
290   else                                                                                    \
291     {                                                                                     \
292       /* defined, section relative. replace symbol with pointer to    \
293            symbol which points to section  */                                   \
294       switch (r_index)                                                                    \
295           {                                                                               \
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   unsigned 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   unsigned 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 bool
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_and_read (abfd, reloc_size, reloc_size);
417   if (!relocs && reloc_size != 0)
418     {
419       free (reloc_cache);
420       return false;
421     }
422 
423   if (each_size == RELOC_EXT_SIZE)
424     {
425       struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
426       unsigned int counter = 0;
427       arelent *cache_ptr = reloc_cache;
428 
429       for (; counter < count; counter++, rptr++, cache_ptr++)
430           {
431             NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols,
432                                                   (bfd_size_type) bfd_get_symcount (abfd));
433           }
434     }
435   else
436     {
437       struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
438       unsigned int counter = 0;
439       arelent *cache_ptr = reloc_cache;
440 
441       for (; counter < count; counter++, rptr++, cache_ptr++)
442           {
443             NAME(lynx,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols,
444                                                   (bfd_size_type) bfd_get_symcount (abfd));
445           }
446 
447     }
448 
449   bfd_release (abfd, relocs);
450   asect->relocation = reloc_cache;
451   asect->reloc_count = count;
452   return true;
453 }
454 
455 
456 
457 /* Write out a relocation section into an object file.  */
458 
459 static bool
NAME(lynx,squirt_out_relocs)460 NAME(lynx,squirt_out_relocs) (bfd *abfd, asection *section)
461 {
462   arelent **generic;
463   unsigned char *native, *natptr;
464   size_t each_size;
465   unsigned int count = section->reloc_count;
466   bfd_size_type natsize;
467 
468   if (count == 0)
469     return true;
470 
471   each_size = obj_reloc_entry_size (abfd);
472   natsize = count;
473   natsize *= each_size;
474   native = (unsigned char *) bfd_zalloc (abfd, natsize);
475   if (!native)
476     return false;
477 
478   generic = section->orelocation;
479 
480   if (each_size == RELOC_EXT_SIZE)
481     {
482       for (natptr = native;
483              count != 0;
484              --count, natptr += each_size, ++generic)
485           NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr);
486     }
487   else
488     {
489       for (natptr = native;
490              count != 0;
491              --count, natptr += each_size, ++generic)
492           NAME(lynx,swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr);
493     }
494 
495   if (bfd_write (native, natsize, abfd) != natsize)
496     {
497       bfd_release (abfd, native);
498       return false;
499     }
500   bfd_release (abfd, native);
501 
502   return true;
503 }
504 
505 /* This is stupid.  This function should be a boolean predicate */
506 static long
NAME(lynx,canonicalize_reloc)507 NAME(lynx,canonicalize_reloc) (bfd *abfd,
508                                      sec_ptr section,
509                                      arelent **relptr,
510                                      asymbol **symbols)
511 {
512   arelent *tblptr = section->relocation;
513   unsigned int count;
514 
515   if (!(tblptr || NAME(lynx,slurp_reloc_table) (abfd, section, symbols)))
516     return -1;
517 
518   if (section->flags & SEC_CONSTRUCTOR)
519     {
520       arelent_chain *chain = section->constructor_chain;
521       for (count = 0; count < section->reloc_count; count++)
522           {
523             *relptr++ = &chain->relent;
524             chain = chain->next;
525           }
526     }
527   else
528     {
529       tblptr = section->relocation;
530 
531       for (count = 0; count++ < section->reloc_count;)
532           {
533             *relptr++ = tblptr++;
534           }
535     }
536   *relptr = 0;
537 
538   return section->reloc_count;
539 }
540 
541 #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc)
542 
543 #include "aout-target.h"
544