150472Speter/* Support for 32-bit PowerPC NLM (NetWare Loadable Module) 237Srgrimes Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 337Srgrimes 2005 Free Software Foundation, Inc. 437Srgrimes 537Srgrimes This file is part of BFD, the Binary File Descriptor library. 637Srgrimes 737Srgrimes This program is free software; you can redistribute it and/or modify 837Srgrimes it under the terms of the GNU General Public License as published by 937Srgrimes the Free Software Foundation; either version 2 of the License, or 109306Sbde (at your option) any later version. 1137Srgrimes 12646Sdg This program is distributed in the hope that it will be useful, 139306Sbde but WITHOUT ANY WARRANTY; without even the implied warranty of 14646Sdg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 156489Sjoerg GNU General Public License for more details. 166489Sjoerg 176489Sjoerg You should have received a copy of the GNU General Public License 186489Sjoerg along with this program; if not, write to the Free Software 196489Sjoerg Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 209306Sbde 219306Sbde#include "bfd.h" 22119915Syar#include "sysdep.h" 23646Sdg#include "libbfd.h" 24646Sdg 25646Sdg/* The format of a PowerPC NLM changed. Define OLDFORMAT to get the 26119915Syar old format. */ 27646Sdg 28646Sdg#define ARCH_SIZE 32 29646Sdg 30646Sdg#include "nlm/ppc-ext.h" 31646Sdg#define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header 32646Sdg 336489Sjoerg#include "libnlm.h" 34646Sdg 35119915Syar#ifdef OLDFORMAT 36119915Syar 37646Sdg/* The prefix header is only used in the old format. */ 3837Srgrimes 3970164Sphk/* PowerPC NLM's have a prefix header before the standard NLM. This 4070164Sphk function reads it in, verifies the version, and seeks the bfd to 4137Srgrimes the location before the regular NLM header. */ 4237Srgrimes 4337Srgrimesstatic bfd_boolean 4437Srgrimesnlm_powerpc_backend_object_p (bfd *abfd) 4537Srgrimes{ 4637Srgrimes struct nlm32_powerpc_external_prefix_header s; 4737Srgrimes 4837Srgrimes if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s) 4937Srgrimes return FALSE; 5037Srgrimes 5137Srgrimes if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0 5237Srgrimes || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION) 53862Sache return FALSE; 5437Srgrimes 55862Sache return TRUE; 5637Srgrimes} 57862Sache 5837Srgrimes/* Write out the prefix. */ 59862Sache 6037Srgrimesstatic bfd_boolean 61862Sachenlm_powerpc_write_prefix (bfd *abfd) 6237Srgrimes{ 63862Sache struct nlm32_powerpc_external_prefix_header s; 6437Srgrimes 65862Sache memset (&s, 0, sizeof s); 6637Srgrimes memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature); 67862Sache H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion); 6837Srgrimes H_PUT_32 (abfd, 0, s.origins); 69862Sache 7037Srgrimes /* FIXME: What should we do about the date? */ 71862Sache 72154Srgrimes if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s) 73862Sache return FALSE; 74154Srgrimes 75862Sache return TRUE; 76154Srgrimes} 77862Sache 7837818Sphk/* This reloc handling is only applicable to the old format. */ 7937818Sphk 8037Srgrimes/* How to process the various reloc types. PowerPC NLMs use XCOFF 8137Srgrimes reloc types, and I have just copied the XCOFF reloc table here. */ 8229610Sjoerg 8329610Sjoergstatic reloc_howto_type nlm_powerpc_howto_table[] = 8429610Sjoerg{ 8529610Sjoerg /* Standard 32 bit relocation. */ 8629610Sjoerg HOWTO (0, /* Type. */ 8729610Sjoerg 0, /* Rightshift. */ 8829610Sjoerg 2, /* Size (0 = byte, 1 = short, 2 = long). */ 8929610Sjoerg 32, /* Bitsize. */ 9029610Sjoerg FALSE, /* PC relative. */ 9129610Sjoerg 0, /* Bitpos. */ 9229610Sjoerg complain_overflow_bitfield, /* Complain_on_overflow. */ 9329610Sjoerg 0, /* Special_function. */ 9429610Sjoerg "R_POS", /* Name. */ 9529610Sjoerg TRUE, /* Partial_inplace. */ 9629610Sjoerg 0xffffffff, /* Source mask. */ 9729610Sjoerg 0xffffffff, /* Dest mask. */ 9829610Sjoerg FALSE), /* PC rel offset. */ 9929610Sjoerg 10029610Sjoerg /* 32 bit relocation, but store negative value. */ 10129610Sjoerg HOWTO (1, /* Type. */ 10237Srgrimes 0, /* Rightshift. */ 10337Srgrimes -2, /* Size (0 = byte, 1 = short, 2 = long). */ 10437Srgrimes 32, /* Bitsize. */ 10537Srgrimes FALSE, /* PC relative. */ 10637Srgrimes 0, /* Bitpos. */ 10737Srgrimes complain_overflow_bitfield, /* Complain_on_overflow. */ 10837Srgrimes 0, /* Special_function. */ 10937Srgrimes "R_NEG", /* Name. */ 11037Srgrimes TRUE, /* Partial_inplace. */ 11137Srgrimes 0xffffffff, /* Source mask. */ 11237Srgrimes 0xffffffff, /* Dest mask. */ 11337Srgrimes FALSE), /* PC rel offset. */ 11437Srgrimes 11537Srgrimes /* 32 bit PC relative relocation. */ 11637Srgrimes HOWTO (2, /* Type. */ 11737Srgrimes 0, /* Rightshift. */ 11837Srgrimes 2, /* Size (0 = byte, 1 = short, 2 = long). */ 11937Srgrimes 32, /* Bitsize. */ 12037Srgrimes TRUE, /* PC relative. */ 12137Srgrimes 0, /* Bitpos. */ 12237Srgrimes complain_overflow_signed, /* Complain_on_overflow. */ 12337Srgrimes 0, /* Special_function. */ 12437Srgrimes "R_REL", /* Name. */ 12537Srgrimes TRUE, /* Partial_inplace. */ 12637Srgrimes 0xffffffff, /* Source mask. */ 12737Srgrimes 0xffffffff, /* Dest mask. */ 12837Srgrimes FALSE), /* PC rel offset. */ 12937Srgrimes 13037Srgrimes /* 16 bit TOC relative relocation. */ 13137Srgrimes HOWTO (3, /* Type. */ 13237Srgrimes 0, /* Rightshift. */ 13337Srgrimes 1, /* Size (0 = byte, 1 = short, 2 = long). */ 13437Srgrimes 16, /* Bitsize. */ 13537Srgrimes FALSE, /* PC relative. */ 13637Srgrimes 0, /* Bitpos. */ 137289Srgrimes complain_overflow_signed, /* Complain_on_overflow. */ 13837Srgrimes 0, /* Special_function. */ 13937Srgrimes "R_TOC", /* Name. */ 14037Srgrimes TRUE, /* Partial_inplace. */ 14137Srgrimes 0xffff, /* Source mask. */ 14237Srgrimes 0xffff, /* Dest mask. */ 14337Srgrimes FALSE), /* PC rel offset. */ 14437Srgrimes 14537Srgrimes /* I don't really know what this is. */ 14637Srgrimes HOWTO (4, /* Type. */ 14737Srgrimes 1, /* Rightshift. */ 14837Srgrimes 2, /* Size (0 = byte, 1 = short, 2 = long). */ 14937Srgrimes 32, /* Bitsize. */ 15037Srgrimes FALSE, /* PC relative. */ 15137Srgrimes 0, /* Bitpos. */ 15237Srgrimes complain_overflow_bitfield, /* Complain_on_overflow. */ 15337Srgrimes 0, /* Special_function. */ 15437Srgrimes "R_RTB", /* Name. */ 15537Srgrimes TRUE, /* Partial_inplace. */ 15637Srgrimes 0xffffffff, /* Source mask. */ 15737Srgrimes 0xffffffff, /* Dest mask. */ 15837Srgrimes FALSE), /* PC rel offset. */ 15937Srgrimes 16037Srgrimes /* External TOC relative symbol. */ 16137Srgrimes HOWTO (5, /* Type. */ 16237Srgrimes 0, /* Rightshift. */ 16337Srgrimes 2, /* Size (0 = byte, 1 = short, 2 = long). */ 16437Srgrimes 16, /* Bitsize. */ 1651096Sache FALSE, /* PC relative. */ 16637Srgrimes 0, /* Bitpos. */ 16737Srgrimes complain_overflow_bitfield, /* Complain_on_overflow. */ 16837Srgrimes 0, /* Special_function. */ 16937Srgrimes "R_GL", /* Name. */ 17037Srgrimes TRUE, /* Partial_inplace. */ 17137Srgrimes 0xffff, /* Source mask. */ 17237Srgrimes 0xffff, /* Dest mask. */ 17337Srgrimes FALSE), /* PC rel offset. */ 17437Srgrimes 17537Srgrimes /* Local TOC relative symbol. */ 17637Srgrimes HOWTO (6, /* Type. */ 17737Srgrimes 0, /* Rightshift. */ 17837Srgrimes 2, /* Size (0 = byte, 1 = short, 2 = long). */ 17937Srgrimes 16, /* Bitsize. */ 18037Srgrimes FALSE, /* PC relative. */ 18137Srgrimes 0, /* Bitpos. */ 18237Srgrimes complain_overflow_bitfield, /* Complain_on_overflow. */ 18337Srgrimes 0, /* Special_function. */ 18437Srgrimes "R_TCL", /* Name. */ 18537Srgrimes TRUE, /* Partial_inplace. */ 18637Srgrimes 0xffff, /* Source mask. */ 18737Srgrimes 0xffff, /* Dest mask. */ 18837Srgrimes FALSE), /* PC rel offset. */ 18937Srgrimes 19037Srgrimes { 7 }, 19137Srgrimes 19237Srgrimes /* Non modifiable absolute branch. */ 19337Srgrimes HOWTO (8, /* Type. */ 19437Srgrimes 0, /* Rightshift. */ 19537Srgrimes 2, /* Size (0 = byte, 1 = short, 2 = long). */ 19637Srgrimes 26, /* Bitsize. */ 19737Srgrimes FALSE, /* PC relative. */ 19837Srgrimes 0, /* Bitpos. */ 19937Srgrimes complain_overflow_bitfield, /* Complain_on_overflow. */ 20061513Sphk 0, /* Special_function. */ 20161513Sphk "R_BA", /* Name. */ 20261513Sphk TRUE, /* Partial_inplace. */ 20361513Sphk 0x3fffffc, /* Source mask. */ 20461513Sphk 0x3fffffc, /* Dest mask. */ 20561513Sphk FALSE), /* PC rel offset. */ 20661513Sphk 20782700Smurray { 9 }, 208130151Sschweikh 20982700Smurray /* Non modifiable relative branch. */ 21082700Smurray HOWTO (0xa, /* Type. */ 21182700Smurray 0, /* Rightshift. */ 21282700Smurray 2, /* Size (0 = byte, 1 = short, 2 = long). */ 21382700Smurray 26, /* Bitsize. */ 214154685Smatteo TRUE, /* PC relative. */ 215154685Smatteo 0, /* Bitpos. */ 21682700Smurray complain_overflow_signed, /* Complain_on_overflow. */ 21782700Smurray 0, /* Special_function. */ 21882700Smurray "R_BR", /* Name. */ 21982700Smurray TRUE, /* Partial_inplace. */ 22082700Smurray 0x3fffffc, /* Source mask. */ 22182700Smurray 0x3fffffc, /* Dest mask. */ 22282700Smurray FALSE), /* PC rel offset. */ 22382700Smurray 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 432static bfd_boolean 433nlm_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 520static 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 537static bfd_boolean 538nlm_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 599static bfd_boolean 600nlm_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 611static bfd_boolean 612nlm_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 660static bfd_boolean 661nlm_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 728static bfd_boolean 729nlm_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 830static bfd_boolean 831nlm_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 842static bfd_boolean 843nlm_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 891static bfd_boolean 892nlm_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 912static bfd_vma 913nlm_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 946static 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