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