Automatic date update in version.in
[binutils-gdb.git] / bfd / i386lynx.c
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 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 \f
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 if (r_index < bfd_get_symcount (abfd)) \
287 cache_ptr->sym_ptr_ptr = symbols + r_index; \
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
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
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
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
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_bwrite (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
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"