1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module) 2 Copyright 1994, 1995, 2000, 2001, 2002, 2003 3 Free Software Foundation, Inc. 4 5 This file is part of BFD, the Binary File Descriptor library. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20 21 #include "bfd.h" 22 #include "sysdep.h" 23 #include "libbfd.h" 24 25 /* The format of a PowerPC NLM changed. Define OLDFORMAT to get the 26 old format. */ 27 28 #define ARCH_SIZE 32 29 30 #include "nlm/ppc-ext.h" 31 #define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header 32 33 #include "libnlm.h" 34 35 #ifdef OLDFORMAT 36 static bfd_boolean nlm_powerpc_backend_object_p 37 PARAMS ((bfd *)); 38 static bfd_boolean nlm_powerpc_write_prefix 39 PARAMS ((bfd *)); 40 #endif 41 42 static bfd_boolean nlm_powerpc_read_reloc 43 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *)); 44 static bfd_boolean nlm_powerpc_mangle_relocs 45 PARAMS ((bfd *, asection *, const PTR, bfd_vma, bfd_size_type)); 46 static bfd_boolean nlm_powerpc_read_import 47 PARAMS ((bfd *, nlmNAME(symbol_type) *)); 48 49 #ifdef OLDFORMAT 50 static bfd_boolean nlm_powerpc_write_reloc 51 PARAMS ((bfd *, asection *, arelent *, int)); 52 #endif 53 54 static bfd_boolean nlm_powerpc_write_import 55 PARAMS ((bfd *, asection *, arelent *)); 56 static bfd_boolean nlm_powerpc_write_external 57 PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *)); 58 59 #ifndef OLDFORMAT 60 static bfd_boolean nlm_powerpc_set_public_section 61 PARAMS ((bfd *, nlmNAME(symbol_type) *)); 62 static bfd_vma nlm_powerpc_get_public_offset 63 PARAMS ((bfd *, asymbol *)); 64 #endif 65 66 #ifdef OLDFORMAT 67 68 /* The prefix header is only used in the old format. */ 69 70 /* PowerPC NLM's have a prefix header before the standard NLM. This 71 function reads it in, verifies the version, and seeks the bfd to 72 the location before the regular NLM header. */ 73 74 static bfd_boolean 75 nlm_powerpc_backend_object_p (abfd) 76 bfd *abfd; 77 { 78 struct nlm32_powerpc_external_prefix_header s; 79 80 if (bfd_bread ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s) 81 return FALSE; 82 83 if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0 84 || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION) 85 return FALSE; 86 87 return TRUE; 88 } 89 90 /* Write out the prefix. */ 91 92 static bfd_boolean 93 nlm_powerpc_write_prefix (abfd) 94 bfd *abfd; 95 { 96 struct nlm32_powerpc_external_prefix_header s; 97 98 memset (&s, 0, sizeof s); 99 memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature); 100 H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion); 101 H_PUT_32 (abfd, 0, s.origins); 102 103 /* FIXME: What should we do about the date? */ 104 105 if (bfd_bwrite ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s) 106 return FALSE; 107 108 return TRUE; 109 } 110 111 #endif /* OLDFORMAT */ 112 113 #ifndef OLDFORMAT 114 115 /* There is only one type of reloc in a PowerPC NLM. */ 116 117 static reloc_howto_type nlm_powerpc_howto = 118 HOWTO (0, /* type */ 119 0, /* rightshift */ 120 2, /* size (0 = byte, 1 = short, 2 = long) */ 121 32, /* bitsize */ 122 FALSE, /* pc_relative */ 123 0, /* bitpos */ 124 complain_overflow_bitfield, /* complain_on_overflow */ 125 0, /* special_function */ 126 "32", /* name */ 127 TRUE, /* partial_inplace */ 128 0xffffffff, /* src_mask */ 129 0xffffffff, /* dst_mask */ 130 FALSE); /* pcrel_offset */ 131 132 /* Read a PowerPC NLM reloc. */ 133 134 static bfd_boolean 135 nlm_powerpc_read_reloc (abfd, sym, secp, rel) 136 bfd *abfd; 137 nlmNAME(symbol_type) *sym; 138 asection **secp; 139 arelent *rel; 140 { 141 bfd_byte temp[4]; 142 bfd_vma val; 143 const char *name; 144 145 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp)) 146 return FALSE; 147 148 val = bfd_get_32 (abfd, temp); 149 150 /* The value is a word offset into either the code or data segment. 151 This is the location which needs to be adjusted. 152 153 The high bit is 0 if the value is an offset into the data 154 segment, or 1 if the value is an offset into the text segment. 155 156 If this is a relocation fixup rather than an imported symbol (the 157 sym argument is NULL), then the second most significant bit is 0 158 if the address of the data segment should be added to the 159 location addressed by the value, or 1 if the address of the text 160 segment should be added. 161 162 If this is an imported symbol, the second most significant bit is 163 not used and must be 0. */ 164 165 if ((val & NLM_HIBIT) == 0) 166 name = NLM_INITIALIZED_DATA_NAME; 167 else 168 { 169 name = NLM_CODE_NAME; 170 val &=~ NLM_HIBIT; 171 } 172 *secp = bfd_get_section_by_name (abfd, name); 173 174 if (sym == NULL) 175 { 176 if ((val & (NLM_HIBIT >> 1)) == 0) 177 name = NLM_INITIALIZED_DATA_NAME; 178 else 179 { 180 name = NLM_CODE_NAME; 181 val &=~ (NLM_HIBIT >> 1); 182 } 183 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr; 184 } 185 186 rel->howto = &nlm_powerpc_howto; 187 188 rel->address = val << 2; 189 rel->addend = 0; 190 191 return TRUE; 192 } 193 194 #else /* OLDFORMAT */ 195 196 /* This reloc handling is only applicable to the old format. */ 197 198 /* How to process the various reloc types. PowerPC NLMs use XCOFF 199 reloc types, and I have just copied the XCOFF reloc table here. */ 200 201 static reloc_howto_type nlm_powerpc_howto_table[] = 202 { 203 /* Standard 32 bit relocation. */ 204 HOWTO (0, /* type */ 205 0, /* rightshift */ 206 2, /* size (0 = byte, 1 = short, 2 = long) */ 207 32, /* bitsize */ 208 FALSE, /* pc_relative */ 209 0, /* bitpos */ 210 complain_overflow_bitfield, /* complain_on_overflow */ 211 0, /* special_function */ 212 "R_POS", /* name */ 213 TRUE, /* partial_inplace */ 214 0xffffffff, /* src_mask */ 215 0xffffffff, /* dst_mask */ 216 FALSE), /* pcrel_offset */ 217 218 /* 32 bit relocation, but store negative value. */ 219 HOWTO (1, /* type */ 220 0, /* rightshift */ 221 -2, /* size (0 = byte, 1 = short, 2 = long) */ 222 32, /* bitsize */ 223 FALSE, /* pc_relative */ 224 0, /* bitpos */ 225 complain_overflow_bitfield, /* complain_on_overflow */ 226 0, /* special_function */ 227 "R_NEG", /* name */ 228 TRUE, /* partial_inplace */ 229 0xffffffff, /* src_mask */ 230 0xffffffff, /* dst_mask */ 231 FALSE), /* pcrel_offset */ 232 233 /* 32 bit PC relative relocation. */ 234 HOWTO (2, /* type */ 235 0, /* rightshift */ 236 2, /* size (0 = byte, 1 = short, 2 = long) */ 237 32, /* bitsize */ 238 TRUE, /* pc_relative */ 239 0, /* bitpos */ 240 complain_overflow_signed, /* complain_on_overflow */ 241 0, /* special_function */ 242 "R_REL", /* name */ 243 TRUE, /* partial_inplace */ 244 0xffffffff, /* src_mask */ 245 0xffffffff, /* dst_mask */ 246 FALSE), /* pcrel_offset */ 247 248 /* 16 bit TOC relative relocation. */ 249 HOWTO (3, /* type */ 250 0, /* rightshift */ 251 1, /* size (0 = byte, 1 = short, 2 = long) */ 252 16, /* bitsize */ 253 FALSE, /* pc_relative */ 254 0, /* bitpos */ 255 complain_overflow_signed, /* complain_on_overflow */ 256 0, /* special_function */ 257 "R_TOC", /* name */ 258 TRUE, /* partial_inplace */ 259 0xffff, /* src_mask */ 260 0xffff, /* dst_mask */ 261 FALSE), /* pcrel_offset */ 262 263 /* I don't really know what this is. */ 264 HOWTO (4, /* type */ 265 1, /* rightshift */ 266 2, /* size (0 = byte, 1 = short, 2 = long) */ 267 32, /* bitsize */ 268 FALSE, /* pc_relative */ 269 0, /* bitpos */ 270 complain_overflow_bitfield, /* complain_on_overflow */ 271 0, /* special_function */ 272 "R_RTB", /* name */ 273 TRUE, /* partial_inplace */ 274 0xffffffff, /* src_mask */ 275 0xffffffff, /* dst_mask */ 276 FALSE), /* pcrel_offset */ 277 278 /* External TOC relative symbol. */ 279 HOWTO (5, /* type */ 280 0, /* rightshift */ 281 2, /* size (0 = byte, 1 = short, 2 = long) */ 282 16, /* bitsize */ 283 FALSE, /* pc_relative */ 284 0, /* bitpos */ 285 complain_overflow_bitfield, /* complain_on_overflow */ 286 0, /* special_function */ 287 "R_GL", /* name */ 288 TRUE, /* partial_inplace */ 289 0xffff, /* src_mask */ 290 0xffff, /* dst_mask */ 291 FALSE), /* pcrel_offset */ 292 293 /* Local TOC relative symbol. */ 294 HOWTO (6, /* type */ 295 0, /* rightshift */ 296 2, /* size (0 = byte, 1 = short, 2 = long) */ 297 16, /* bitsize */ 298 FALSE, /* pc_relative */ 299 0, /* bitpos */ 300 complain_overflow_bitfield, /* complain_on_overflow */ 301 0, /* special_function */ 302 "R_TCL", /* name */ 303 TRUE, /* partial_inplace */ 304 0xffff, /* src_mask */ 305 0xffff, /* dst_mask */ 306 FALSE), /* pcrel_offset */ 307 308 { 7 }, 309 310 /* Non modifiable absolute branch. */ 311 HOWTO (8, /* type */ 312 0, /* rightshift */ 313 2, /* size (0 = byte, 1 = short, 2 = long) */ 314 26, /* bitsize */ 315 FALSE, /* pc_relative */ 316 0, /* bitpos */ 317 complain_overflow_bitfield, /* complain_on_overflow */ 318 0, /* special_function */ 319 "R_BA", /* name */ 320 TRUE, /* partial_inplace */ 321 0x3fffffc, /* src_mask */ 322 0x3fffffc, /* dst_mask */ 323 FALSE), /* pcrel_offset */ 324 325 { 9 }, 326 327 /* Non modifiable relative branch. */ 328 HOWTO (0xa, /* type */ 329 0, /* rightshift */ 330 2, /* size (0 = byte, 1 = short, 2 = long) */ 331 26, /* bitsize */ 332 TRUE, /* pc_relative */ 333 0, /* bitpos */ 334 complain_overflow_signed, /* complain_on_overflow */ 335 0, /* special_function */ 336 "R_BR", /* name */ 337 TRUE, /* partial_inplace */ 338 0x3fffffc, /* src_mask */ 339 0x3fffffc, /* dst_mask */ 340 FALSE), /* pcrel_offset */ 341 342 { 0xb }, 343 344 /* Indirect load. */ 345 HOWTO (0xc, /* type */ 346 0, /* rightshift */ 347 2, /* size (0 = byte, 1 = short, 2 = long) */ 348 16, /* bitsize */ 349 FALSE, /* pc_relative */ 350 0, /* bitpos */ 351 complain_overflow_bitfield, /* complain_on_overflow */ 352 0, /* special_function */ 353 "R_RL", /* name */ 354 TRUE, /* partial_inplace */ 355 0xffff, /* src_mask */ 356 0xffff, /* dst_mask */ 357 FALSE), /* pcrel_offset */ 358 359 /* Load address. */ 360 HOWTO (0xd, /* type */ 361 0, /* rightshift */ 362 2, /* size (0 = byte, 1 = short, 2 = long) */ 363 16, /* bitsize */ 364 FALSE, /* pc_relative */ 365 0, /* bitpos */ 366 complain_overflow_bitfield, /* complain_on_overflow */ 367 0, /* special_function */ 368 "R_RLA", /* name */ 369 TRUE, /* partial_inplace */ 370 0xffff, /* src_mask */ 371 0xffff, /* dst_mask */ 372 FALSE), /* pcrel_offset */ 373 374 { 0xe }, 375 376 /* Non-relocating reference. */ 377 HOWTO (0xf, /* type */ 378 0, /* rightshift */ 379 2, /* size (0 = byte, 1 = short, 2 = long) */ 380 32, /* bitsize */ 381 FALSE, /* pc_relative */ 382 0, /* bitpos */ 383 complain_overflow_bitfield, /* complain_on_overflow */ 384 0, /* special_function */ 385 "R_REF", /* name */ 386 FALSE, /* partial_inplace */ 387 0, /* src_mask */ 388 0, /* dst_mask */ 389 FALSE), /* pcrel_offset */ 390 391 { 0x10 }, 392 { 0x11 }, 393 394 /* TOC relative indirect load. */ 395 HOWTO (0x12, /* type */ 396 0, /* rightshift */ 397 2, /* size (0 = byte, 1 = short, 2 = long) */ 398 16, /* bitsize */ 399 FALSE, /* pc_relative */ 400 0, /* bitpos */ 401 complain_overflow_bitfield, /* complain_on_overflow */ 402 0, /* special_function */ 403 "R_TRL", /* name */ 404 TRUE, /* partial_inplace */ 405 0xffff, /* src_mask */ 406 0xffff, /* dst_mask */ 407 FALSE), /* pcrel_offset */ 408 409 /* TOC relative load address. */ 410 HOWTO (0x13, /* type */ 411 0, /* rightshift */ 412 2, /* size (0 = byte, 1 = short, 2 = long) */ 413 16, /* bitsize */ 414 FALSE, /* pc_relative */ 415 0, /* bitpos */ 416 complain_overflow_bitfield, /* complain_on_overflow */ 417 0, /* special_function */ 418 "R_TRLA", /* name */ 419 TRUE, /* partial_inplace */ 420 0xffff, /* src_mask */ 421 0xffff, /* dst_mask */ 422 FALSE), /* pcrel_offset */ 423 424 /* Modifiable relative branch. */ 425 HOWTO (0x14, /* type */ 426 1, /* rightshift */ 427 2, /* size (0 = byte, 1 = short, 2 = long) */ 428 32, /* bitsize */ 429 FALSE, /* pc_relative */ 430 0, /* bitpos */ 431 complain_overflow_bitfield, /* complain_on_overflow */ 432 0, /* special_function */ 433 "R_RRTBI", /* name */ 434 TRUE, /* partial_inplace */ 435 0xffffffff, /* src_mask */ 436 0xffffffff, /* dst_mask */ 437 FALSE), /* pcrel_offset */ 438 439 /* Modifiable absolute branch. */ 440 HOWTO (0x15, /* type */ 441 1, /* rightshift */ 442 2, /* size (0 = byte, 1 = short, 2 = long) */ 443 32, /* bitsize */ 444 FALSE, /* pc_relative */ 445 0, /* bitpos */ 446 complain_overflow_bitfield, /* complain_on_overflow */ 447 0, /* special_function */ 448 "R_RRTBA", /* name */ 449 TRUE, /* partial_inplace */ 450 0xffffffff, /* src_mask */ 451 0xffffffff, /* dst_mask */ 452 FALSE), /* pcrel_offset */ 453 454 /* Modifiable call absolute indirect. */ 455 HOWTO (0x16, /* type */ 456 0, /* rightshift */ 457 2, /* size (0 = byte, 1 = short, 2 = long) */ 458 16, /* bitsize */ 459 FALSE, /* pc_relative */ 460 0, /* bitpos */ 461 complain_overflow_bitfield, /* complain_on_overflow */ 462 0, /* special_function */ 463 "R_CAI", /* name */ 464 TRUE, /* partial_inplace */ 465 0xffff, /* src_mask */ 466 0xffff, /* dst_mask */ 467 FALSE), /* pcrel_offset */ 468 469 /* Modifiable call relative. */ 470 HOWTO (0x17, /* type */ 471 0, /* rightshift */ 472 2, /* size (0 = byte, 1 = short, 2 = long) */ 473 16, /* bitsize */ 474 FALSE, /* pc_relative */ 475 0, /* bitpos */ 476 complain_overflow_bitfield, /* complain_on_overflow */ 477 0, /* special_function */ 478 "R_REL", /* name */ 479 TRUE, /* partial_inplace */ 480 0xffff, /* src_mask */ 481 0xffff, /* dst_mask */ 482 FALSE), /* pcrel_offset */ 483 484 /* Modifiable branch absolute. */ 485 HOWTO (0x18, /* type */ 486 0, /* rightshift */ 487 2, /* size (0 = byte, 1 = short, 2 = long) */ 488 16, /* bitsize */ 489 FALSE, /* pc_relative */ 490 0, /* bitpos */ 491 complain_overflow_bitfield, /* complain_on_overflow */ 492 0, /* special_function */ 493 "R_RBA", /* name */ 494 TRUE, /* partial_inplace */ 495 0xffff, /* src_mask */ 496 0xffff, /* dst_mask */ 497 FALSE), /* pcrel_offset */ 498 499 /* Modifiable branch absolute. */ 500 HOWTO (0x19, /* type */ 501 0, /* rightshift */ 502 2, /* size (0 = byte, 1 = short, 2 = long) */ 503 16, /* bitsize */ 504 FALSE, /* pc_relative */ 505 0, /* bitpos */ 506 complain_overflow_bitfield, /* complain_on_overflow */ 507 0, /* special_function */ 508 "R_RBAC", /* name */ 509 TRUE, /* partial_inplace */ 510 0xffff, /* src_mask */ 511 0xffff, /* dst_mask */ 512 FALSE), /* pcrel_offset */ 513 514 /* Modifiable branch relative. */ 515 HOWTO (0x1a, /* type */ 516 0, /* rightshift */ 517 2, /* size (0 = byte, 1 = short, 2 = long) */ 518 26, /* bitsize */ 519 FALSE, /* pc_relative */ 520 0, /* bitpos */ 521 complain_overflow_signed, /* complain_on_overflow */ 522 0, /* special_function */ 523 "R_REL", /* name */ 524 TRUE, /* partial_inplace */ 525 0xffff, /* src_mask */ 526 0xffff, /* dst_mask */ 527 FALSE), /* pcrel_offset */ 528 529 /* Modifiable branch absolute. */ 530 HOWTO (0x1b, /* type */ 531 0, /* rightshift */ 532 2, /* size (0 = byte, 1 = short, 2 = long) */ 533 16, /* bitsize */ 534 FALSE, /* pc_relative */ 535 0, /* bitpos */ 536 complain_overflow_bitfield, /* complain_on_overflow */ 537 0, /* special_function */ 538 "R_REL", /* name */ 539 TRUE, /* partial_inplace */ 540 0xffff, /* src_mask */ 541 0xffff, /* dst_mask */ 542 FALSE) /* pcrel_offset */ 543 }; 544 545 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \ 546 / sizeof nlm_powerpc_howto_table[0]) 547 548 /* Read a PowerPC NLM reloc. */ 549 550 static bfd_boolean 551 nlm_powerpc_read_reloc (abfd, sym, secp, rel) 552 bfd *abfd; 553 nlmNAME(symbol_type) *sym; 554 asection **secp; 555 arelent *rel; 556 { 557 struct nlm32_powerpc_external_reloc ext; 558 bfd_vma l_vaddr; 559 unsigned long l_symndx; 560 int l_rtype; 561 int l_rsecnm; 562 asection *code_sec, *data_sec, *bss_sec; 563 564 /* Read the reloc from the file. */ 565 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext) 566 return FALSE; 567 568 /* Swap in the fields. */ 569 l_vaddr = H_GET_32 (abfd, ext.l_vaddr); 570 l_symndx = H_GET_32 (abfd, ext.l_symndx); 571 l_rtype = H_GET_16 (abfd, ext.l_rtype); 572 l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm); 573 574 /* Get the sections now, for convenience. */ 575 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); 576 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); 577 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME); 578 579 /* Work out the arelent fields. */ 580 if (sym != NULL) 581 { 582 /* This is an import. sym_ptr_ptr is filled in by 583 nlm_canonicalize_reloc. */ 584 rel->sym_ptr_ptr = NULL; 585 } 586 else 587 { 588 asection *sec; 589 590 if (l_symndx == 0) 591 sec = code_sec; 592 else if (l_symndx == 1) 593 sec = data_sec; 594 else if (l_symndx == 2) 595 sec = bss_sec; 596 else 597 { 598 bfd_set_error (bfd_error_bad_value); 599 return FALSE; 600 } 601 602 rel->sym_ptr_ptr = sec->symbol_ptr_ptr; 603 } 604 605 rel->addend = 0; 606 607 BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT); 608 609 rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff); 610 611 BFD_ASSERT (rel->howto->name != NULL 612 && ((l_rtype & 0x8000) != 0 613 ? (rel->howto->complain_on_overflow 614 == complain_overflow_signed) 615 : (rel->howto->complain_on_overflow 616 == complain_overflow_bitfield)) 617 && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1); 618 619 if (l_rsecnm == 0) 620 *secp = code_sec; 621 else if (l_rsecnm == 1) 622 { 623 *secp = data_sec; 624 l_vaddr -= bfd_section_size (abfd, code_sec); 625 } 626 else 627 { 628 bfd_set_error (bfd_error_bad_value); 629 return FALSE; 630 } 631 632 rel->address = l_vaddr; 633 634 return TRUE; 635 } 636 637 #endif /* OLDFORMAT */ 638 639 /* Mangle PowerPC NLM relocs for output. */ 640 641 static bfd_boolean 642 nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count) 643 bfd *abfd ATTRIBUTE_UNUSED; 644 asection *sec ATTRIBUTE_UNUSED; 645 const PTR data ATTRIBUTE_UNUSED; 646 bfd_vma offset ATTRIBUTE_UNUSED; 647 bfd_size_type count ATTRIBUTE_UNUSED; 648 { 649 return TRUE; 650 } 651 652 /* Read a PowerPC NLM import record */ 653 654 static bfd_boolean 655 nlm_powerpc_read_import (abfd, sym) 656 bfd *abfd; 657 nlmNAME(symbol_type) *sym; 658 { 659 struct nlm_relent *nlm_relocs; /* relocation records for symbol */ 660 bfd_size_type rcount; /* number of relocs */ 661 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */ 662 unsigned char symlength; /* length of symbol name */ 663 char *name; 664 665 if (bfd_bread ((PTR) &symlength, (bfd_size_type) sizeof (symlength), abfd) 666 != sizeof (symlength)) 667 return FALSE; 668 sym -> symbol.the_bfd = abfd; 669 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1); 670 if (name == NULL) 671 return FALSE; 672 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength) 673 return FALSE; 674 name[symlength] = '\0'; 675 sym -> symbol.name = name; 676 sym -> symbol.flags = 0; 677 sym -> symbol.value = 0; 678 sym -> symbol.section = bfd_und_section_ptr; 679 if (bfd_bread ((PTR) temp, (bfd_size_type) sizeof (temp), abfd) 680 != sizeof (temp)) 681 return FALSE; 682 rcount = H_GET_32 (abfd, temp); 683 nlm_relocs = ((struct nlm_relent *) 684 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent))); 685 if (nlm_relocs == (struct nlm_relent *) NULL) 686 return FALSE; 687 sym -> relocs = nlm_relocs; 688 sym -> rcnt = 0; 689 while (sym -> rcnt < rcount) 690 { 691 asection *section; 692 693 if (! nlm_powerpc_read_reloc (abfd, sym, §ion, &nlm_relocs -> reloc)) 694 return FALSE; 695 nlm_relocs -> section = section; 696 nlm_relocs++; 697 sym -> rcnt++; 698 } 699 return TRUE; 700 } 701 702 #ifndef OLDFORMAT 703 704 /* Write a PowerPC NLM reloc. */ 705 706 static bfd_boolean 707 nlm_powerpc_write_import (abfd, sec, rel) 708 bfd *abfd; 709 asection *sec; 710 arelent *rel; 711 { 712 asymbol *sym; 713 bfd_vma val; 714 bfd_byte temp[4]; 715 716 /* PowerPC NetWare only supports one kind of reloc. */ 717 if (rel->addend != 0 718 || rel->howto == NULL 719 || rel->howto->rightshift != 0 720 || rel->howto->size != 2 721 || rel->howto->bitsize != 32 722 || rel->howto->bitpos != 0 723 || rel->howto->pc_relative 724 || (rel->howto->src_mask != 0xffffffff && rel->addend != 0) 725 || rel->howto->dst_mask != 0xffffffff) 726 { 727 bfd_set_error (bfd_error_invalid_operation); 728 return FALSE; 729 } 730 731 sym = *rel->sym_ptr_ptr; 732 733 /* The value we write out is the offset into the appropriate 734 segment, rightshifted by two. This offset is the section vma, 735 adjusted by the vma of the lowest section in that segment, plus 736 the address of the relocation. */ 737 val = bfd_get_section_vma (abfd, sec) + rel->address; 738 if ((val & 3) != 0) 739 { 740 bfd_set_error (bfd_error_bad_value); 741 return FALSE; 742 } 743 val >>= 2; 744 745 /* The high bit is 0 if the reloc is in the data section, or 1 if 746 the reloc is in the code section. */ 747 if (bfd_get_section_flags (abfd, sec) & SEC_DATA) 748 val -= nlm_get_data_low (abfd); 749 else 750 { 751 val -= nlm_get_text_low (abfd); 752 val |= NLM_HIBIT; 753 } 754 755 if (! bfd_is_und_section (bfd_get_section (sym))) 756 { 757 /* This is an internal relocation fixup. The second most 758 significant bit is 0 if this is a reloc against the data 759 segment, or 1 if it is a reloc against the text segment. */ 760 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE) 761 val |= NLM_HIBIT >> 1; 762 } 763 764 bfd_put_32 (abfd, val, temp); 765 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp)) 766 return FALSE; 767 768 return TRUE; 769 } 770 771 #else /* OLDFORMAT */ 772 773 /* This is used for the reloc handling in the old format. */ 774 775 /* Write a PowerPC NLM reloc. */ 776 777 static bfd_boolean 778 nlm_powerpc_write_reloc (abfd, sec, rel, indx) 779 bfd *abfd; 780 asection *sec; 781 arelent *rel; 782 int indx; 783 { 784 struct nlm32_powerpc_external_reloc ext; 785 asection *code_sec, *data_sec, *bss_sec; 786 asymbol *sym; 787 asection *symsec; 788 unsigned long l_symndx; 789 int l_rtype; 790 int l_rsecnm; 791 reloc_howto_type *howto; 792 bfd_size_type address; 793 794 /* Get the sections now, for convenience. */ 795 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); 796 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); 797 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME); 798 799 sym = *rel->sym_ptr_ptr; 800 symsec = bfd_get_section (sym); 801 if (indx != -1) 802 { 803 BFD_ASSERT (bfd_is_und_section (symsec)); 804 l_symndx = indx + 3; 805 } 806 else 807 { 808 if (symsec == code_sec) 809 l_symndx = 0; 810 else if (symsec == data_sec) 811 l_symndx = 1; 812 else if (symsec == bss_sec) 813 l_symndx = 2; 814 else 815 { 816 bfd_set_error (bfd_error_bad_value); 817 return FALSE; 818 } 819 } 820 821 H_PUT_32 (abfd, l_symndx, ext.l_symndx); 822 823 for (howto = nlm_powerpc_howto_table; 824 howto < nlm_powerpc_howto_table + HOWTO_COUNT; 825 howto++) 826 { 827 if (howto->rightshift == rel->howto->rightshift 828 && howto->size == rel->howto->size 829 && howto->bitsize == rel->howto->bitsize 830 && howto->pc_relative == rel->howto->pc_relative 831 && howto->bitpos == rel->howto->bitpos 832 && (howto->partial_inplace == rel->howto->partial_inplace 833 || (! rel->howto->partial_inplace 834 && rel->addend == 0)) 835 && (howto->src_mask == rel->howto->src_mask 836 || (rel->howto->src_mask == 0 837 && rel->addend == 0)) 838 && howto->dst_mask == rel->howto->dst_mask 839 && howto->pcrel_offset == rel->howto->pcrel_offset) 840 break; 841 } 842 if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT) 843 { 844 bfd_set_error (bfd_error_bad_value); 845 return FALSE; 846 } 847 848 l_rtype = howto->type; 849 if (howto->complain_on_overflow == complain_overflow_signed) 850 l_rtype |= 0x8000; 851 l_rtype |= (howto->bitsize - 1) << 8; 852 H_PUT_16 (abfd, l_rtype, ext.l_rtype); 853 854 address = rel->address; 855 856 if (sec == code_sec) 857 l_rsecnm = 0; 858 else if (sec == data_sec) 859 { 860 l_rsecnm = 1; 861 address += bfd_section_size (abfd, code_sec); 862 } 863 else 864 { 865 bfd_set_error (bfd_error_bad_value); 866 return FALSE; 867 } 868 869 H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm); 870 H_PUT_32 (abfd, address, ext.l_vaddr); 871 872 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext) 873 return FALSE; 874 875 return TRUE; 876 } 877 878 /* Write a PowerPC NLM import. */ 879 880 static bfd_boolean 881 nlm_powerpc_write_import (abfd, sec, rel) 882 bfd *abfd; 883 asection *sec; 884 arelent *rel; 885 { 886 return nlm_powerpc_write_reloc (abfd, sec, rel, -1); 887 } 888 889 #endif /* OLDFORMAT */ 890 891 /* Write a PowerPC NLM external symbol. This routine keeps a static 892 count of the symbol index. FIXME: I don't know if this is 893 necessary, and the index never gets reset. */ 894 895 static bfd_boolean 896 nlm_powerpc_write_external (abfd, count, sym, relocs) 897 bfd *abfd; 898 bfd_size_type count; 899 asymbol *sym; 900 struct reloc_and_sec *relocs; 901 { 902 unsigned int i; 903 bfd_byte len; 904 unsigned char temp[NLM_TARGET_LONG_SIZE]; 905 #ifdef OLDFORMAT 906 static int indx; 907 #endif 908 909 len = strlen (sym->name); 910 if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd) 911 != sizeof (bfd_byte)) 912 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len) 913 return FALSE; 914 915 bfd_put_32 (abfd, count, temp); 916 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp)) 917 return FALSE; 918 919 for (i = 0; i < count; i++) 920 { 921 #ifndef OLDFORMAT 922 if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel)) 923 return FALSE; 924 #else 925 if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec, 926 relocs[i].rel, indx)) 927 return FALSE; 928 #endif 929 } 930 931 #ifdef OLDFORMAT 932 ++indx; 933 #endif 934 935 return TRUE; 936 } 937 938 #ifndef OLDFORMAT 939 940 /* PowerPC Netware uses a word offset, not a byte offset, for public 941 symbols. */ 942 943 /* Set the section for a public symbol. */ 944 945 static bfd_boolean 946 nlm_powerpc_set_public_section (abfd, sym) 947 bfd *abfd; 948 nlmNAME(symbol_type) *sym; 949 { 950 if (sym->symbol.value & NLM_HIBIT) 951 { 952 sym->symbol.value &= ~NLM_HIBIT; 953 sym->symbol.flags |= BSF_FUNCTION; 954 sym->symbol.section = 955 bfd_get_section_by_name (abfd, NLM_CODE_NAME); 956 } 957 else 958 { 959 sym->symbol.section = 960 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); 961 } 962 963 sym->symbol.value <<= 2; 964 965 return TRUE; 966 } 967 968 /* Get the offset to write out for a public symbol. */ 969 970 static bfd_vma 971 nlm_powerpc_get_public_offset (abfd, sym) 972 bfd *abfd; 973 asymbol *sym; 974 { 975 bfd_vma offset; 976 asection *sec; 977 978 offset = bfd_asymbol_value (sym); 979 sec = bfd_get_section (sym); 980 if (sec->flags & SEC_CODE) 981 { 982 offset -= nlm_get_text_low (abfd); 983 offset |= NLM_HIBIT; 984 } 985 else if (sec->flags & (SEC_DATA | SEC_ALLOC)) 986 { 987 /* SEC_ALLOC is for the .bss section. */ 988 offset -= nlm_get_data_low (abfd); 989 } 990 else 991 { 992 /* We can't handle an exported symbol that is not in the code or 993 data segment. */ 994 bfd_set_error (bfd_error_invalid_operation); 995 /* FIXME: No way to return error. */ 996 abort (); 997 } 998 999 return offset; 1000 } 1001 1002 #endif /* ! defined (OLDFORMAT) */ 1003 1004 #include "nlmswap.h" 1005 1006 static const struct nlm_backend_data nlm32_powerpc_backend = 1007 { 1008 "NetWare PowerPC Module \032", 1009 sizeof (Nlm32_powerpc_External_Fixed_Header), 1010 #ifndef OLDFORMAT 1011 0, /* optional_prefix_size */ 1012 #else 1013 sizeof (struct nlm32_powerpc_external_prefix_header), 1014 #endif 1015 bfd_arch_powerpc, 1016 0, 1017 FALSE, 1018 #ifndef OLDFORMAT 1019 0, /* backend_object_p */ 1020 0, /* write_prefix */ 1021 #else 1022 nlm_powerpc_backend_object_p, 1023 nlm_powerpc_write_prefix, 1024 #endif 1025 nlm_powerpc_read_reloc, 1026 nlm_powerpc_mangle_relocs, 1027 nlm_powerpc_read_import, 1028 nlm_powerpc_write_import, 1029 #ifndef OLDFORMAT 1030 nlm_powerpc_set_public_section, 1031 nlm_powerpc_get_public_offset, 1032 #else 1033 0, /* set_public_section */ 1034 0, /* get_public_offset */ 1035 #endif 1036 nlm_swap_fixed_header_in, 1037 nlm_swap_fixed_header_out, 1038 nlm_powerpc_write_external, 1039 0, /* write_export */ 1040 }; 1041 1042 #define TARGET_BIG_NAME "nlm32-powerpc" 1043 #define TARGET_BIG_SYM nlmNAME(powerpc_vec) 1044 #define TARGET_BACKEND_DATA &nlm32_powerpc_backend 1045 1046 #include "nlm-target.h" 1047