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