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