1 /* BFD back-end for i386 a.out binaries under LynxOS. 2 Copyright (C) 1990-2014 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 bfd_size_type text_size; /* dummy vars */ \ 40 file_ptr text_end; \ 41 if (adata(abfd).magic == undecided_magic) \ 42 NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \ 43 \ 44 execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \ 45 execp->a_entry = bfd_get_start_address (abfd); \ 46 \ 47 execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \ 48 obj_reloc_entry_size (abfd)); \ 49 execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \ 50 obj_reloc_entry_size (abfd)); \ 51 NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \ 52 \ 53 if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 \ 54 || bfd_bwrite (&exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE, \ 55 abfd) != EXEC_BYTES_SIZE) \ 56 return FALSE; \ 57 /* Now write out reloc info, followed by syms and strings */ \ 58 \ 59 if (bfd_get_symcount (abfd) != 0) \ 60 { \ 61 if (bfd_seek (abfd, (file_ptr) (N_SYMOFF(*execp)), SEEK_SET) \ 62 != 0) \ 63 return FALSE; \ 64 \ 65 if (! NAME(aout,write_syms) (abfd)) return FALSE; \ 66 \ 67 if (bfd_seek (abfd, (file_ptr) (N_TRELOFF(*execp)), SEEK_SET) \ 68 != 0) \ 69 return FALSE; \ 70 \ 71 if (!NAME(lynx,squirt_out_relocs) (abfd, obj_textsec (abfd))) \ 72 return FALSE; \ 73 if (bfd_seek (abfd, (file_ptr) (N_DRELOFF(*execp)), SEEK_SET) \ 74 != 0) \ 75 return 0; \ 76 \ 77 if (!NAME(lynx,squirt_out_relocs) (abfd, obj_datasec (abfd))) \ 78 return FALSE; \ 79 } \ 80 } 81 #endif 82 83 #include "libaout.h" 84 #include "aout/aout64.h" 85 86 87 #ifdef LYNX_CORE 88 89 char *lynx_core_file_failing_command (); 90 int lynx_core_file_failing_signal (); 91 bfd_boolean lynx_core_file_matches_executable_p (); 92 const bfd_target *lynx_core_file_p (); 93 94 #define MY_core_file_failing_command lynx_core_file_failing_command 95 #define MY_core_file_failing_signal lynx_core_file_failing_signal 96 #define MY_core_file_matches_executable_p lynx_core_file_matches_executable_p 97 #define MY_core_file_p lynx_core_file_p 98 99 #endif /* LYNX_CORE */ 100 101 103 #define KEEPIT udata.i 104 105 extern reloc_howto_type aout_32_ext_howto_table[]; 106 extern reloc_howto_type aout_32_std_howto_table[]; 107 108 /* Standard reloc stuff */ 109 /* Output standard relocation information to a file in target byte order. */ 110 111 static void 112 NAME(lynx,swap_std_reloc_out) (bfd *abfd, 113 arelent *g, 114 struct reloc_std_external *natptr) 115 { 116 int r_index; 117 asymbol *sym = *(g->sym_ptr_ptr); 118 int r_extern; 119 unsigned int r_length; 120 int r_pcrel; 121 int r_baserel, r_jmptable, r_relative; 122 asection *output_section = sym->section->output_section; 123 124 PUT_WORD (abfd, g->address, natptr->r_address); 125 126 r_length = g->howto->size; /* Size as a power of two */ 127 r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ 128 /* r_baserel, r_jmptable, r_relative??? FIXME-soon */ 129 r_baserel = 0; 130 r_jmptable = 0; 131 r_relative = 0; 132 133 /* name was clobbered by aout_write_syms to be symbol index */ 134 135 /* If this relocation is relative to a symbol then set the 136 r_index to the symbols index, and the r_extern bit. 137 138 Absolute symbols can come in in two ways, either as an offset 139 from the abs section, or as a symbol which has an abs value. 140 check for that here 141 */ 142 143 if (bfd_is_com_section (output_section) 144 || bfd_is_abs_section (output_section) 145 || bfd_is_und_section (output_section)) 146 { 147 if (bfd_abs_section_ptr->symbol == sym) 148 { 149 /* Whoops, looked like an abs symbol, but is really an offset 150 from the abs section */ 151 r_index = 0; 152 r_extern = 0; 153 } 154 else 155 { 156 /* Fill in symbol */ 157 r_extern = 1; 158 r_index = (*g->sym_ptr_ptr)->KEEPIT; 159 } 160 } 161 else 162 { 163 /* Just an ordinary section */ 164 r_extern = 0; 165 r_index = output_section->target_index; 166 } 167 168 /* now the fun stuff */ 169 if (bfd_header_big_endian (abfd)) 170 { 171 natptr->r_index[0] = r_index >> 16; 172 natptr->r_index[1] = r_index >> 8; 173 natptr->r_index[2] = r_index; 174 natptr->r_type[0] = 175 (r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0) 176 | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0) 177 | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0) 178 | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0) 179 | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0) 180 | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG); 181 } 182 else 183 { 184 natptr->r_index[2] = r_index >> 16; 185 natptr->r_index[1] = r_index >> 8; 186 natptr->r_index[0] = r_index; 187 natptr->r_type[0] = 188 (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0) 189 | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0) 190 | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0) 191 | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0) 192 | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0) 193 | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE); 194 } 195 } 196 197 198 /* Extended stuff */ 199 /* Output extended relocation information to a file in target byte order. */ 200 201 static void 202 NAME(lynx,swap_ext_reloc_out) (bfd *abfd, 203 arelent *g, 204 struct reloc_ext_external *natptr) 205 { 206 int r_index; 207 int r_extern; 208 unsigned int r_type; 209 unsigned int r_addend; 210 asymbol *sym = *(g->sym_ptr_ptr); 211 asection *output_section = sym->section->output_section; 212 213 PUT_WORD (abfd, g->address, natptr->r_address); 214 215 r_type = (unsigned int) g->howto->type; 216 217 r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; 218 219 220 /* If this relocation is relative to a symbol then set the 221 r_index to the symbols index, and the r_extern bit. 222 223 Absolute symbols can come in in two ways, either as an offset 224 from the abs section, or as a symbol which has an abs value. 225 check for that here 226 */ 227 228 if (bfd_is_com_section (output_section) 229 || bfd_is_abs_section (output_section) 230 || bfd_is_und_section (output_section)) 231 { 232 if (bfd_abs_section_ptr->symbol == sym) 233 { 234 /* Whoops, looked like an abs symbol, but is really an offset 235 from the abs section */ 236 r_index = 0; 237 r_extern = 0; 238 } 239 else 240 { 241 r_extern = 1; 242 r_index = (*g->sym_ptr_ptr)->KEEPIT; 243 } 244 } 245 else 246 { 247 /* Just an ordinary section */ 248 r_extern = 0; 249 r_index = output_section->target_index; 250 } 251 252 253 /* now the fun stuff */ 254 if (bfd_header_big_endian (abfd)) 255 { 256 natptr->r_index[0] = r_index >> 16; 257 natptr->r_index[1] = r_index >> 8; 258 natptr->r_index[2] = r_index; 259 natptr->r_type[0] = 260 (r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0) 261 | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG); 262 } 263 else 264 { 265 natptr->r_index[2] = r_index >> 16; 266 natptr->r_index[1] = r_index >> 8; 267 natptr->r_index[0] = r_index; 268 natptr->r_type[0] = 269 (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0) 270 | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE); 271 } 272 273 PUT_WORD (abfd, r_addend, natptr->r_addend); 274 } 275 276 /* BFD deals internally with all things based from the section they're 277 in. so, something in 10 bytes into a text section with a base of 278 50 would have a symbol (.text+10) and know .text vma was 50. 279 280 Aout keeps all it's symbols based from zero, so the symbol would 281 contain 60. This macro subs the base of each section from the value 282 to give the true offset from the section */ 283 284 285 #define MOVE_ADDRESS(ad) \ 286 if (r_extern) \ 287 { \ 288 /* undefined symbol */ \ 289 cache_ptr->sym_ptr_ptr = symbols + r_index; \ 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 case N_TEXT: \ 298 case N_TEXT | N_EXT: \ 299 cache_ptr->sym_ptr_ptr = obj_textsec(abfd)->symbol_ptr_ptr; \ 300 cache_ptr->addend = ad - su->textsec->vma; \ 301 break; \ 302 case N_DATA: \ 303 case N_DATA | N_EXT: \ 304 cache_ptr->sym_ptr_ptr = obj_datasec(abfd)->symbol_ptr_ptr; \ 305 cache_ptr->addend = ad - su->datasec->vma; \ 306 break; \ 307 case N_BSS: \ 308 case N_BSS | N_EXT: \ 309 cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; \ 310 cache_ptr->addend = ad - su->bsssec->vma; \ 311 break; \ 312 default: \ 313 case N_ABS: \ 314 case N_ABS | N_EXT: \ 315 cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; \ 316 cache_ptr->addend = ad; \ 317 break; \ 318 } \ 319 } \ 320 321 static void 322 NAME(lynx,swap_ext_reloc_in) (bfd *abfd, 323 struct reloc_ext_external *bytes, 324 arelent *cache_ptr, 325 asymbol **symbols, 326 bfd_size_type symcount ATTRIBUTE_UNUSED) 327 { 328 int r_index; 329 int r_extern; 330 unsigned int r_type; 331 struct aoutdata *su = &(abfd->tdata.aout_data->a); 332 333 cache_ptr->address = (GET_SWORD (abfd, bytes->r_address)); 334 335 r_index = bytes->r_index[1]; 336 r_extern = (0 != (bytes->r_index[0] & RELOC_EXT_BITS_EXTERN_BIG)); 337 r_type = (bytes->r_index[0] & RELOC_EXT_BITS_TYPE_BIG) 338 >> RELOC_EXT_BITS_TYPE_SH_BIG; 339 340 cache_ptr->howto = aout_32_ext_howto_table + r_type; 341 MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend)); 342 } 343 344 static void 345 NAME(lynx,swap_std_reloc_in) (bfd *abfd, 346 struct reloc_std_external *bytes, 347 arelent *cache_ptr, 348 asymbol **symbols, 349 bfd_size_type symcount ATTRIBUTE_UNUSED) 350 { 351 int r_index; 352 int r_extern; 353 unsigned int r_length; 354 int r_pcrel; 355 struct aoutdata *su = &(abfd->tdata.aout_data->a); 356 357 cache_ptr->address = H_GET_32 (abfd, bytes->r_address); 358 359 r_index = bytes->r_index[1]; 360 r_extern = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG)); 361 r_pcrel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_BIG)); 362 r_length = (bytes->r_index[0] & RELOC_STD_BITS_LENGTH_BIG) 363 >> RELOC_STD_BITS_LENGTH_SH_BIG; 364 365 cache_ptr->howto = aout_32_std_howto_table + r_length + 4 * r_pcrel; 366 /* FIXME-soon: Roll baserel, jmptable, relative bits into howto setting */ 367 368 MOVE_ADDRESS (0); 369 } 370 371 /* Reloc hackery */ 372 373 static bfd_boolean 374 NAME(lynx,slurp_reloc_table) (bfd *abfd, 375 sec_ptr asect, 376 asymbol **symbols) 377 { 378 bfd_size_type count; 379 bfd_size_type reloc_size; 380 void * relocs; 381 arelent *reloc_cache; 382 size_t each_size; 383 384 if (asect->relocation) 385 return TRUE; 386 387 if (asect->flags & SEC_CONSTRUCTOR) 388 return TRUE; 389 390 if (asect == obj_datasec (abfd)) 391 { 392 reloc_size = exec_hdr (abfd)->a_drsize; 393 goto doit; 394 } 395 396 if (asect == obj_textsec (abfd)) 397 { 398 reloc_size = exec_hdr (abfd)->a_trsize; 399 goto doit; 400 } 401 402 bfd_set_error (bfd_error_invalid_operation); 403 return FALSE; 404 405 doit: 406 if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0) 407 return FALSE; 408 each_size = obj_reloc_entry_size (abfd); 409 410 count = reloc_size / each_size; 411 412 413 reloc_cache = (arelent *) bfd_zmalloc (count * sizeof (arelent)); 414 if (!reloc_cache && count != 0) 415 return FALSE; 416 417 relocs = bfd_alloc (abfd, reloc_size); 418 if (!relocs && reloc_size != 0) 419 { 420 free (reloc_cache); 421 return FALSE; 422 } 423 424 if (bfd_bread (relocs, reloc_size, abfd) != reloc_size) 425 { 426 bfd_release (abfd, relocs); 427 free (reloc_cache); 428 return FALSE; 429 } 430 431 if (each_size == RELOC_EXT_SIZE) 432 { 433 struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs; 434 unsigned int counter = 0; 435 arelent *cache_ptr = reloc_cache; 436 437 for (; counter < count; counter++, rptr++, cache_ptr++) 438 { 439 NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols, 440 (bfd_size_type) bfd_get_symcount (abfd)); 441 } 442 } 443 else 444 { 445 struct reloc_std_external *rptr = (struct reloc_std_external *) relocs; 446 unsigned int counter = 0; 447 arelent *cache_ptr = reloc_cache; 448 449 for (; counter < count; counter++, rptr++, cache_ptr++) 450 { 451 NAME(lynx,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols, 452 (bfd_size_type) bfd_get_symcount (abfd)); 453 } 454 455 } 456 457 bfd_release (abfd, relocs); 458 asect->relocation = reloc_cache; 459 asect->reloc_count = count; 460 return TRUE; 461 } 462 463 464 465 /* Write out a relocation section into an object file. */ 466 467 static bfd_boolean 468 NAME(lynx,squirt_out_relocs) (bfd *abfd, asection *section) 469 { 470 arelent **generic; 471 unsigned char *native, *natptr; 472 size_t each_size; 473 unsigned int count = section->reloc_count; 474 bfd_size_type natsize; 475 476 if (count == 0) 477 return TRUE; 478 479 each_size = obj_reloc_entry_size (abfd); 480 natsize = count; 481 natsize *= each_size; 482 native = (unsigned char *) bfd_zalloc (abfd, natsize); 483 if (!native) 484 return FALSE; 485 486 generic = section->orelocation; 487 488 if (each_size == RELOC_EXT_SIZE) 489 { 490 for (natptr = native; 491 count != 0; 492 --count, natptr += each_size, ++generic) 493 NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr); 494 } 495 else 496 { 497 for (natptr = native; 498 count != 0; 499 --count, natptr += each_size, ++generic) 500 NAME(lynx,swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr); 501 } 502 503 if (bfd_bwrite (native, natsize, abfd) != natsize) 504 { 505 bfd_release (abfd, native); 506 return FALSE; 507 } 508 bfd_release (abfd, native); 509 510 return TRUE; 511 } 512 513 /* This is stupid. This function should be a boolean predicate */ 514 static long 515 NAME(lynx,canonicalize_reloc) (bfd *abfd, 516 sec_ptr section, 517 arelent **relptr, 518 asymbol **symbols) 519 { 520 arelent *tblptr = section->relocation; 521 unsigned int count; 522 523 if (!(tblptr || NAME(lynx,slurp_reloc_table) (abfd, section, symbols))) 524 return -1; 525 526 if (section->flags & SEC_CONSTRUCTOR) 527 { 528 arelent_chain *chain = section->constructor_chain; 529 for (count = 0; count < section->reloc_count; count++) 530 { 531 *relptr++ = &chain->relent; 532 chain = chain->next; 533 } 534 } 535 else 536 { 537 tblptr = section->relocation; 538 539 for (count = 0; count++ < section->reloc_count;) 540 { 541 *relptr++ = tblptr++; 542 } 543 } 544 *relptr = 0; 545 546 return section->reloc_count; 547 } 548 549 #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc) 550 551 #include "aout-target.h" 552