1 /* Support for 32-bit Alpha NLM (NetWare Loadable Module) 2 Copyright (C) 1993-2016 Free Software Foundation, Inc. 3 Written by Ian Lance Taylor, Cygnus Support. 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 3 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, 20 MA 02110-1301, USA. */ 21 22 23 /* This file describes the 32 bit Alpha NLM format. You might think 24 that an Alpha chip would use a 64 bit format, but, for some reason, 25 it doesn't. */ 26 27 #include "sysdep.h" 28 #include "bfd.h" 29 #include "libbfd.h" 30 31 #define ARCH_SIZE 32 32 33 #include "nlm/alpha-ext.h" 34 #define Nlm_External_Fixed_Header Nlm32_alpha_External_Fixed_Header 35 36 #include "libnlm.h" 37 38 /* Alpha 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_alpha_backend_object_p (bfd *abfd) 45 { 46 struct nlm32_alpha_external_prefix_header s; 47 file_ptr size; 48 49 if (bfd_bread (&s, (bfd_size_type) sizeof s, abfd) != sizeof s) 50 return FALSE; 51 52 if (H_GET_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC) 53 return FALSE; 54 55 /* FIXME: Should we check the format number? */ 56 57 /* Skip to the end of the header. */ 58 size = H_GET_32 (abfd, s.size); 59 if (bfd_seek (abfd, size, SEEK_SET) != 0) 60 return FALSE; 61 62 return TRUE; 63 } 64 65 /* Write out the prefix. */ 66 67 static bfd_boolean 68 nlm_alpha_write_prefix (bfd *abfd) 69 { 70 struct nlm32_alpha_external_prefix_header s; 71 72 memset (&s, 0, sizeof s); 73 H_PUT_32 (abfd, NLM32_ALPHA_MAGIC, s.magic); 74 H_PUT_32 (abfd, 2, s.format); 75 H_PUT_32 (abfd, sizeof s, s.size); 76 if (bfd_bwrite (&s, (bfd_size_type) sizeof s, abfd) != sizeof s) 77 return FALSE; 78 return TRUE; 79 } 80 81 #define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1) 83 84 /* How to process the various reloc types. */ 85 86 static reloc_howto_type nlm32_alpha_howto_table[] = 87 { 88 /* Reloc type 0 is ignored by itself. However, it appears after a 89 GPDISP reloc to identify the location where the low order 16 bits 90 of the gp register are loaded. */ 91 HOWTO (ALPHA_R_IGNORE, /* Type. */ 92 0, /* Rightshift. */ 93 0, /* Size (0 = byte, 1 = short, 2 = long). */ 94 8, /* Bitsize. */ 95 FALSE, /* PC_relative. */ 96 0, /* Bitpos. */ 97 complain_overflow_dont, /* Complain_on_overflow. */ 98 0, /* Special_function. */ 99 "IGNORE", /* Name. */ 100 FALSE, /* Partial_inplace. */ 101 0, /* Source mask. */ 102 0, /* Dest mask. */ 103 FALSE), /* PCrel_offset. */ 104 105 /* A 32 bit reference to a symbol. */ 106 HOWTO (ALPHA_R_REFLONG, /* Type. */ 107 0, /* Rightshift. */ 108 2, /* Size (0 = byte, 1 = short, 2 = long). */ 109 32, /* Bitsize. */ 110 FALSE, /* PC_relative. */ 111 0, /* Bitpos. */ 112 complain_overflow_bitfield, /* Complain_on_overflow. */ 113 0, /* Special_function. */ 114 "REFLONG", /* Name. */ 115 TRUE, /* Partial_inplace. */ 116 0xffffffff, /* Source mask. */ 117 0xffffffff, /* Dest mask. */ 118 FALSE), /* PCrel_offset. */ 119 120 /* A 64 bit reference to a symbol. */ 121 HOWTO (ALPHA_R_REFQUAD, /* Type. */ 122 0, /* Rightshift. */ 123 4, /* Size (0 = byte, 1 = short, 2 = long). */ 124 64, /* Bitsize. */ 125 FALSE, /* PC_relative. */ 126 0, /* Bitpos. */ 127 complain_overflow_bitfield, /* Complain_on_overflow. */ 128 0, /* Special_function. */ 129 "REFQUAD", /* Name. */ 130 TRUE, /* Partial_inplace. */ 131 ONES (64), /* Source mask. */ 132 ONES (64), /* Dest mask. */ 133 FALSE), /* PCrel_offset. */ 134 135 /* A 32 bit GP relative offset. This is just like REFLONG except 136 that when the value is used the value of the gp register will be 137 added in. */ 138 HOWTO (ALPHA_R_GPREL32, /* Type. */ 139 0, /* Rightshift. */ 140 2, /* Size (0 = byte, 1 = short, 2 = long). */ 141 32, /* Bitsize. */ 142 FALSE, /* PC_relative. */ 143 0, /* Bitpos. */ 144 complain_overflow_bitfield, /* Complain_on_overflow. */ 145 0, /* Special_function. */ 146 "GPREL32", /* Name. */ 147 TRUE, /* Partial_inplace. */ 148 0xffffffff, /* Source mask. */ 149 0xffffffff, /* Dest mask. */ 150 FALSE), /* PCrel_offset. */ 151 152 /* Used for an instruction that refers to memory off the GP 153 register. The offset is 16 bits of the 32 bit instruction. This 154 reloc always seems to be against the .lita section. */ 155 HOWTO (ALPHA_R_LITERAL, /* Type. */ 156 0, /* Rightshift. */ 157 2, /* Size (0 = byte, 1 = short, 2 = long). */ 158 16, /* Bitsize. */ 159 FALSE, /* PC_relative. */ 160 0, /* Bitpos. */ 161 complain_overflow_signed, /* Complain_on_overflow. */ 162 0, /* Special_function. */ 163 "LITERAL", /* Name. */ 164 TRUE, /* Partial_inplace. */ 165 0xffff, /* Source mask. */ 166 0xffff, /* Dest mask. */ 167 FALSE), /* PCrel_offset. */ 168 169 /* This reloc only appears immediately following a LITERAL reloc. 170 It identifies a use of the literal. It seems that the linker can 171 use this to eliminate a portion of the .lita section. The symbol 172 index is special: 1 means the literal address is in the base 173 register of a memory format instruction; 2 means the literal 174 address is in the byte offset register of a byte-manipulation 175 instruction; 3 means the literal address is in the target 176 register of a jsr instruction. This does not actually do any 177 relocation. */ 178 HOWTO (ALPHA_R_LITUSE, /* Type. */ 179 0, /* Rightshift. */ 180 2, /* Size (0 = byte, 1 = short, 2 = long). */ 181 32, /* Bitsize. */ 182 FALSE, /* PC_relative. */ 183 0, /* Bitpos. */ 184 complain_overflow_dont, /* Complain_on_overflow. */ 185 0, /* Special_function. */ 186 "LITUSE", /* Name. */ 187 FALSE, /* Partial_inplace. */ 188 0, /* Source mask. */ 189 0, /* Dest mask. */ 190 FALSE), /* PCrel_offset. */ 191 192 /* Load the gp register. This is always used for a ldah instruction 193 which loads the upper 16 bits of the gp register. The next reloc 194 will be an IGNORE reloc which identifies the location of the lda 195 instruction which loads the lower 16 bits. The symbol index of 196 the GPDISP instruction appears to actually be the number of bytes 197 between the ldah and lda instructions. This gives two different 198 ways to determine where the lda instruction is; I don't know why 199 both are used. The value to use for the relocation is the 200 difference between the GP value and the current location; the 201 load will always be done against a register holding the current 202 address. */ 203 HOWTO (ALPHA_R_GPDISP, /* Type. */ 204 16, /* Rightshift. */ 205 2, /* Size (0 = byte, 1 = short, 2 = long). */ 206 16, /* Bitsize. */ 207 TRUE, /* PC_relative. */ 208 0, /* Bitpos. */ 209 complain_overflow_dont, /* Complain_on_overflow. */ 210 0, /* Special_function. */ 211 "GPDISP", /* Name. */ 212 TRUE, /* Partial_inplace. */ 213 0xffff, /* Source mask. */ 214 0xffff, /* Dest mask. */ 215 TRUE), /* PCrel_offset. */ 216 217 /* A 21 bit branch. The native assembler generates these for 218 branches within the text segment, and also fills in the PC 219 relative offset in the instruction. It seems to me that this 220 reloc, unlike the others, is not partial_inplace. */ 221 HOWTO (ALPHA_R_BRADDR, /* Type. */ 222 2, /* Rightshift. */ 223 2, /* Size (0 = byte, 1 = short, 2 = long). */ 224 21, /* Bitsize. */ 225 TRUE, /* PC_relative. */ 226 0, /* Bitpos. */ 227 complain_overflow_signed, /* Complain_on_overflow. */ 228 0, /* Special_function. */ 229 "BRADDR", /* Name. */ 230 FALSE, /* Partial_inplace. */ 231 0, /* Source mask. */ 232 0x1fffff, /* Dest mask. */ 233 FALSE), /* PCrel_offset. */ 234 235 /* A hint for a jump to a register. */ 236 HOWTO (ALPHA_R_HINT, /* Type. */ 237 2, /* Rightshift. */ 238 2, /* Size (0 = byte, 1 = short, 2 = long). */ 239 14, /* Bitsize. */ 240 FALSE, /* PC_relative. */ 241 0, /* Bitpos. */ 242 complain_overflow_dont, /* Complain_on_overflow. */ 243 0, /* Special_function. */ 244 "HINT", /* Name. */ 245 TRUE, /* Partial_inplace. */ 246 0x3fff, /* Source mask. */ 247 0x3fff, /* Dest mask. */ 248 FALSE), /* PCrel_offset. */ 249 250 /* 16 bit PC relative offset. */ 251 HOWTO (ALPHA_R_SREL16, /* Type. */ 252 0, /* Rightshift. */ 253 1, /* Size (0 = byte, 1 = short, 2 = long). */ 254 16, /* Bitsize. */ 255 TRUE, /* PC_relative. */ 256 0, /* Bitpos. */ 257 complain_overflow_signed, /* Complain_on_overflow. */ 258 0, /* Special_function. */ 259 "SREL16", /* Name. */ 260 TRUE, /* Partial_inplace. */ 261 0xffff, /* Source mask. */ 262 0xffff, /* Dest mask. */ 263 FALSE), /* PCrel_offset. */ 264 265 /* 32 bit PC relative offset. */ 266 HOWTO (ALPHA_R_SREL32, /* Type. */ 267 0, /* Rightshift. */ 268 2, /* Size (0 = byte, 1 = short, 2 = long). */ 269 32, /* Bitsize. */ 270 TRUE, /* PC_relative. */ 271 0, /* Bitpos. */ 272 complain_overflow_signed, /* Complain_on_overflow. */ 273 0, /* Special_function. */ 274 "SREL32", /* Name. */ 275 TRUE, /* Partial_inplace. */ 276 0xffffffff, /* Source mask. */ 277 0xffffffff, /* Dest mask. */ 278 FALSE), /* PCrel_offset. */ 279 280 /* A 64 bit PC relative offset. */ 281 HOWTO (ALPHA_R_SREL64, /* Type. */ 282 0, /* Rightshift. */ 283 4, /* Size (0 = byte, 1 = short, 2 = long). */ 284 64, /* Bitsize. */ 285 TRUE, /* PC_relative. */ 286 0, /* Bitpos. */ 287 complain_overflow_signed, /* Complain_on_overflow. */ 288 0, /* Special_function. */ 289 "SREL64", /* Name. */ 290 TRUE, /* Partial_inplace. */ 291 ONES (64), /* Source mask. */ 292 ONES (64), /* Dest mask. */ 293 FALSE), /* PCrel_offset. */ 294 295 /* Push a value on the reloc evaluation stack. */ 296 HOWTO (ALPHA_R_OP_PUSH, /* Type. */ 297 0, /* Rightshift. */ 298 0, /* Size (0 = byte, 1 = short, 2 = long). */ 299 0, /* Bitsize. */ 300 FALSE, /* PC_relative. */ 301 0, /* Bitpos. */ 302 complain_overflow_dont, /* Complain_on_overflow. */ 303 0, /* Special_function. */ 304 "OP_PUSH", /* Name. */ 305 FALSE, /* Partial_inplace. */ 306 0, /* Source mask. */ 307 0, /* Dest mask. */ 308 FALSE), /* PCrel_offset. */ 309 310 /* Store the value from the stack at the given address. Store it in 311 a bitfield of size r_size starting at bit position r_offset. */ 312 HOWTO (ALPHA_R_OP_STORE, /* Type. */ 313 0, /* Rightshift. */ 314 4, /* Size (0 = byte, 1 = short, 2 = long). */ 315 64, /* Bitsize. */ 316 FALSE, /* PC_relative. */ 317 0, /* Bitpos. */ 318 complain_overflow_dont, /* Complain_on_overflow. */ 319 0, /* Special_function. */ 320 "OP_STORE", /* Name. */ 321 FALSE, /* Partial_inplace. */ 322 0, /* Source mask. */ 323 ONES (64), /* Dest mask. */ 324 FALSE), /* PCrel_offset. */ 325 326 /* Subtract the reloc address from the value on the top of the 327 relocation stack. */ 328 HOWTO (ALPHA_R_OP_PSUB, /* Type. */ 329 0, /* Rightshift. */ 330 0, /* Size (0 = byte, 1 = short, 2 = long). */ 331 0, /* Bitsize. */ 332 FALSE, /* PC_relative. */ 333 0, /* Bitpos. */ 334 complain_overflow_dont, /* Complain_on_overflow. */ 335 0, /* Special_function. */ 336 "OP_PSUB", /* Name. */ 337 FALSE, /* Partial_inplace. */ 338 0, /* Source mask. */ 339 0, /* Dest mask. */ 340 FALSE), /* PCrel_offset. */ 341 342 /* Shift the value on the top of the relocation stack right by the 343 given value. */ 344 HOWTO (ALPHA_R_OP_PRSHIFT, /* Type. */ 345 0, /* Rightshift. */ 346 0, /* Size (0 = byte, 1 = short, 2 = long). */ 347 0, /* Bitsize. */ 348 FALSE, /* PC_relative. */ 349 0, /* Bitpos. */ 350 complain_overflow_dont, /* Complain_on_overflow. */ 351 0, /* Special_function. */ 352 "OP_PRSHIFT", /* Name. */ 353 FALSE, /* Partial_inplace. */ 354 0, /* Source mask. */ 355 0, /* Dest mask. */ 356 FALSE), /* PCrel_offset. */ 357 358 /* Adjust the GP value for a new range in the object file. */ 359 HOWTO (ALPHA_R_GPVALUE, /* Type. */ 360 0, /* Rightshift. */ 361 0, /* Size (0 = byte, 1 = short, 2 = long). */ 362 0, /* Bitsize. */ 363 FALSE, /* PC_relative. */ 364 0, /* Bitpos. */ 365 complain_overflow_dont, /* Complain_on_overflow. */ 366 0, /* Special_function. */ 367 "GPVALUE", /* Name. */ 368 FALSE, /* Partial_inplace. */ 369 0, /* Source mask. */ 370 0, /* Dest mask. */ 371 FALSE) /* PCrel_offset. */ 372 }; 373 374 static reloc_howto_type nlm32_alpha_nw_howto = 375 HOWTO (ALPHA_R_NW_RELOC, /* Type. */ 376 0, /* Rightshift. */ 377 0, /* Size (0 = byte, 1 = short, 2 = long). */ 378 0, /* Bitsize. */ 379 FALSE, /* PC_relative. */ 380 0, /* Bitpos. */ 381 complain_overflow_dont, /* Complain_on_overflow. */ 382 0, /* Special_function. */ 383 "NW_RELOC", /* Name. */ 384 FALSE, /* Partial_inplace. */ 385 0, /* Source mask. */ 386 0, /* Dest mask. */ 387 FALSE); /* PCrel_offset. */ 388 389 /* Read an Alpha NLM reloc. This routine keeps some static data which 390 it uses when handling local relocs. This only works correctly 391 because all the local relocs are read at once. */ 392 393 static bfd_boolean 394 nlm_alpha_read_reloc (bfd *abfd, 395 nlmNAME (symbol_type) *sym, 396 asection **secp, 397 arelent *rel) 398 { 399 static bfd_vma gp_value; 400 static bfd_vma lita_address; 401 struct nlm32_alpha_external_reloc ext; 402 bfd_vma r_vaddr; 403 long r_symndx; 404 int r_type, r_extern, r_offset, r_size; 405 asection *code_sec, *data_sec; 406 407 /* Read the reloc from the file. */ 408 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext) 409 return FALSE; 410 411 /* Swap in the reloc information. */ 412 r_vaddr = H_GET_64 (abfd, ext.r_vaddr); 413 r_symndx = H_GET_32 (abfd, ext.r_symndx); 414 415 BFD_ASSERT (bfd_little_endian (abfd)); 416 417 r_type = ((ext.r_bits[0] & RELOC_BITS0_TYPE_LITTLE) 418 >> RELOC_BITS0_TYPE_SH_LITTLE); 419 r_extern = (ext.r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0; 420 r_offset = ((ext.r_bits[1] & RELOC_BITS1_OFFSET_LITTLE) 421 >> RELOC_BITS1_OFFSET_SH_LITTLE); 422 /* Ignore the reserved bits. */ 423 r_size = ((ext.r_bits[3] & RELOC_BITS3_SIZE_LITTLE) 424 >> RELOC_BITS3_SIZE_SH_LITTLE); 425 426 /* Fill in the BFD arelent structure. */ 427 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); 428 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); 429 if (r_extern) 430 { 431 /* External relocations are only used for imports. */ 432 BFD_ASSERT (sym != NULL); 433 /* We don't need to set sym_ptr_ptr for this case. It is set in 434 nlm_canonicalize_reloc. */ 435 rel->sym_ptr_ptr = NULL; 436 rel->addend = 0; 437 } 438 else 439 { 440 /* Internal relocations are only used for local relocation 441 fixups. If they are not NW_RELOC or GPDISP or IGNORE, they 442 must be against .text or .data. */ 443 BFD_ASSERT (r_type == ALPHA_R_NW_RELOC || sym == NULL); 444 if (r_type == ALPHA_R_NW_RELOC 445 || r_type == ALPHA_R_GPDISP 446 || r_type == ALPHA_R_IGNORE) 447 { 448 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; 449 rel->addend = 0; 450 } 451 else if (r_symndx == ALPHA_RELOC_SECTION_TEXT) 452 { 453 rel->sym_ptr_ptr = code_sec->symbol_ptr_ptr; 454 BFD_ASSERT (bfd_get_section_vma (abfd, code_sec) == 0); 455 rel->addend = 0; 456 } 457 else if (r_symndx == ALPHA_RELOC_SECTION_DATA) 458 { 459 rel->sym_ptr_ptr = data_sec->symbol_ptr_ptr; 460 rel->addend = - bfd_get_section_vma (abfd, data_sec); 461 } 462 else 463 { 464 BFD_ASSERT (0); 465 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; 466 rel->addend = 0; 467 } 468 } 469 470 /* We use the address to determine whether the reloc is in the .text 471 or .data section. R_NW_RELOC relocs don't really have a section, 472 so we put them in .text. */ 473 if (r_type == ALPHA_R_NW_RELOC 474 || r_vaddr < code_sec->size) 475 { 476 *secp = code_sec; 477 rel->address = r_vaddr; 478 } 479 else 480 { 481 *secp = data_sec; 482 rel->address = r_vaddr - code_sec->size; 483 } 484 485 /* We must adjust the addend based on the type. */ 486 BFD_ASSERT ((r_type >= 0 && r_type <= ALPHA_R_GPVALUE) 487 || r_type == ALPHA_R_NW_RELOC); 488 489 switch (r_type) 490 { 491 case ALPHA_R_BRADDR: 492 case ALPHA_R_SREL16: 493 case ALPHA_R_SREL32: 494 case ALPHA_R_SREL64: 495 /* The PC relative relocs do not seem to use the section VMA as 496 a negative addend. */ 497 rel->addend = 0; 498 break; 499 500 case ALPHA_R_GPREL32: 501 /* Copy the gp value for this object file into the addend, to 502 ensure that we are not confused by the linker. */ 503 if (! r_extern) 504 rel->addend += gp_value; 505 break; 506 507 case ALPHA_R_LITERAL: 508 BFD_ASSERT (! r_extern); 509 rel->addend += lita_address; 510 break; 511 512 case ALPHA_R_LITUSE: 513 case ALPHA_R_GPDISP: 514 /* The LITUSE and GPDISP relocs do not use a symbol, or an 515 addend, but they do use a special code. Put this code in the 516 addend field. */ 517 rel->addend = r_symndx; 518 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; 519 break; 520 521 case ALPHA_R_OP_STORE: 522 /* The STORE reloc needs the size and offset fields. We store 523 them in the addend. */ 524 BFD_ASSERT (r_offset < 256 && r_size < 256); 525 rel->addend = (r_offset << 8) + r_size; 526 break; 527 528 case ALPHA_R_OP_PUSH: 529 case ALPHA_R_OP_PSUB: 530 case ALPHA_R_OP_PRSHIFT: 531 /* The PUSH, PSUB and PRSHIFT relocs do not actually use an 532 address. I believe that the address supplied is really an 533 addend. */ 534 rel->addend = r_vaddr; 535 break; 536 537 case ALPHA_R_GPVALUE: 538 /* Record the new gp value. */ 539 gp_value += r_symndx; 540 rel->addend = gp_value; 541 break; 542 543 case ALPHA_R_IGNORE: 544 /* If the type is ALPHA_R_IGNORE, make sure this is a reference 545 to the absolute section so that the reloc is ignored. For 546 some reason the address of this reloc type is not adjusted by 547 the section vma. We record the gp value for this object file 548 here, for convenience when doing the GPDISP relocation. */ 549 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; 550 rel->address = r_vaddr; 551 rel->addend = gp_value; 552 break; 553 554 case ALPHA_R_NW_RELOC: 555 /* If this is SETGP, we set the addend to 0. Otherwise we set 556 the addend to the size of the .lita section (this is 557 r_symndx) plus 1. We have already set the address of the 558 reloc to r_vaddr. */ 559 if (r_size == ALPHA_R_NW_RELOC_SETGP) 560 { 561 gp_value = r_vaddr; 562 rel->addend = 0; 563 } 564 else if (r_size == ALPHA_R_NW_RELOC_LITA) 565 { 566 lita_address = r_vaddr; 567 rel->addend = r_symndx + 1; 568 } 569 else 570 BFD_ASSERT (0); 571 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; 572 break; 573 574 default: 575 break; 576 } 577 578 if (r_type == ALPHA_R_NW_RELOC) 579 rel->howto = &nlm32_alpha_nw_howto; 580 else 581 rel->howto = &nlm32_alpha_howto_table[r_type]; 582 583 return TRUE; 584 } 585 586 /* Mangle Alpha NLM relocs for output. */ 587 588 static bfd_boolean 589 nlm_alpha_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED, 590 asection *sec ATTRIBUTE_UNUSED, 591 const void * data ATTRIBUTE_UNUSED, 592 bfd_vma offset ATTRIBUTE_UNUSED, 593 bfd_size_type count ATTRIBUTE_UNUSED) 594 { 595 return TRUE; 596 } 597 598 /* Read an ALPHA NLM import record. */ 599 600 static bfd_boolean 601 nlm_alpha_read_import (bfd *abfd, nlmNAME (symbol_type) * sym) 602 { 603 struct nlm_relent *nlm_relocs; /* Relocation records for symbol. */ 604 bfd_size_type rcount; /* Number of relocs. */ 605 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* Temporary 32-bit value. */ 606 unsigned char symlength; /* Length of symbol name. */ 607 char *name; 608 bfd_size_type amt; 609 610 if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd) 611 != sizeof (symlength)) 612 return FALSE; 613 sym -> symbol.the_bfd = abfd; 614 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1); 615 if (name == NULL) 616 return FALSE; 617 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength) 618 return FALSE; 619 name[symlength] = '\0'; 620 sym -> symbol.name = name; 621 sym -> symbol.flags = 0; 622 sym -> symbol.value = 0; 623 sym -> symbol.section = bfd_und_section_ptr; 624 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) 625 != sizeof (temp)) 626 return FALSE; 627 rcount = H_GET_32 (abfd, temp); 628 amt = rcount * sizeof (struct nlm_relent); 629 nlm_relocs = bfd_alloc (abfd, amt); 630 if (!nlm_relocs) 631 return FALSE; 632 sym -> relocs = nlm_relocs; 633 sym -> rcnt = 0; 634 while (sym -> rcnt < rcount) 635 { 636 asection *section; 637 638 if (! nlm_alpha_read_reloc (abfd, sym, §ion, &nlm_relocs -> reloc)) 639 return FALSE; 640 nlm_relocs -> section = section; 641 nlm_relocs++; 642 sym -> rcnt++; 643 } 644 645 return TRUE; 646 } 647 648 /* Write an Alpha NLM reloc. */ 649 650 static bfd_boolean 651 nlm_alpha_write_import (bfd * abfd, asection * sec, arelent * rel) 652 { 653 asymbol *sym; 654 bfd_vma r_vaddr; 655 long r_symndx; 656 int r_type, r_extern, r_offset, r_size; 657 struct nlm32_alpha_external_reloc ext; 658 659 sym = *rel->sym_ptr_ptr; 660 661 /* Get values for the relocation fields. */ 662 r_type = rel->howto->type; 663 if (r_type != ALPHA_R_NW_RELOC) 664 { 665 r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address; 666 if ((sec->flags & SEC_CODE) == 0) 667 r_vaddr += bfd_get_section_by_name (abfd, NLM_CODE_NAME) -> size; 668 if (bfd_is_und_section (bfd_get_section (sym))) 669 { 670 r_extern = 1; 671 r_symndx = 0; 672 } 673 else 674 { 675 r_extern = 0; 676 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE) 677 r_symndx = ALPHA_RELOC_SECTION_TEXT; 678 else 679 r_symndx = ALPHA_RELOC_SECTION_DATA; 680 } 681 r_offset = 0; 682 r_size = 0; 683 684 switch (r_type) 685 { 686 case ALPHA_R_LITUSE: 687 case ALPHA_R_GPDISP: 688 r_symndx = rel->addend; 689 break; 690 691 case ALPHA_R_OP_STORE: 692 r_size = rel->addend & 0xff; 693 r_offset = (rel->addend >> 8) & 0xff; 694 break; 695 696 case ALPHA_R_OP_PUSH: 697 case ALPHA_R_OP_PSUB: 698 case ALPHA_R_OP_PRSHIFT: 699 r_vaddr = rel->addend; 700 break; 701 702 case ALPHA_R_IGNORE: 703 r_vaddr = rel->address; 704 break; 705 706 default: 707 break; 708 } 709 } 710 else 711 { 712 /* r_type == ALPHA_R_NW_RELOC. */ 713 r_vaddr = rel->address; 714 if (rel->addend == 0) 715 { 716 r_symndx = 0; 717 r_size = ALPHA_R_NW_RELOC_SETGP; 718 } 719 else 720 { 721 r_symndx = rel->addend - 1; 722 r_size = ALPHA_R_NW_RELOC_LITA; 723 } 724 r_extern = 0; 725 r_offset = 0; 726 } 727 728 /* Swap out the relocation fields. */ 729 H_PUT_64 (abfd, r_vaddr, ext.r_vaddr); 730 H_PUT_32 (abfd, r_symndx, ext.r_symndx); 731 732 BFD_ASSERT (bfd_little_endian (abfd)); 733 734 ext.r_bits[0] = ((r_type << RELOC_BITS0_TYPE_SH_LITTLE) 735 & RELOC_BITS0_TYPE_LITTLE); 736 ext.r_bits[1] = ((r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0) 737 | ((r_offset << RELOC_BITS1_OFFSET_SH_LITTLE) 738 & RELOC_BITS1_OFFSET_LITTLE)); 739 ext.r_bits[2] = 0; 740 ext.r_bits[3] = ((r_size << RELOC_BITS3_SIZE_SH_LITTLE) 741 & RELOC_BITS3_SIZE_LITTLE); 742 743 /* Write out the relocation. */ 744 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext) 745 return FALSE; 746 747 return TRUE; 748 } 749 750 /* Alpha NetWare does not use the high bit to determine whether a 752 public symbol is in the code segment or the data segment. Instead, 753 it just uses the address. The set_public_section and 754 get_public_offset routines override the default code which uses the 755 high bit. */ 756 757 /* Set the section for a public symbol. */ 758 759 static bfd_boolean 760 nlm_alpha_set_public_section (bfd * abfd, nlmNAME (symbol_type) * sym) 761 { 762 asection *code_sec, *data_sec; 763 764 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); 765 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); 766 if (sym->symbol.value < code_sec->size) 767 { 768 sym->symbol.section = code_sec; 769 sym->symbol.flags |= BSF_FUNCTION; 770 } 771 else 772 { 773 sym->symbol.section = data_sec; 774 sym->symbol.value -= code_sec->size; 775 /* The data segment had better be aligned. */ 776 BFD_ASSERT ((code_sec->size & 0xf) == 0); 777 } 778 return TRUE; 779 } 780 781 /* Get the offset to write out for a public symbol. */ 782 783 static bfd_vma 784 nlm_alpha_get_public_offset (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym) 785 { 786 return bfd_asymbol_value (sym); 787 } 788 789 /* Write an Alpha NLM external symbol. */ 791 792 static bfd_boolean 793 nlm_alpha_write_external (bfd *abfd, 794 bfd_size_type count, 795 asymbol *sym, 796 struct reloc_and_sec *relocs) 797 { 798 bfd_size_type i; 799 bfd_byte len; 800 unsigned char temp[NLM_TARGET_LONG_SIZE]; 801 arelent r; 802 803 len = strlen (sym->name); 804 if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd) 805 != sizeof (bfd_byte)) 806 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len) 807 return FALSE; 808 809 bfd_put_32 (abfd, count + 2, temp); 810 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp)) 811 return FALSE; 812 813 /* The first two relocs for each external symbol are the .lita 814 address and the GP value. */ 815 r.sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; 816 r.howto = &nlm32_alpha_nw_howto; 817 818 r.address = nlm_alpha_backend_data (abfd)->lita_address; 819 r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1; 820 if (! nlm_alpha_write_import (abfd, NULL, &r)) 821 return FALSE; 822 823 r.address = nlm_alpha_backend_data (abfd)->gp; 824 r.addend = 0; 825 if (! nlm_alpha_write_import (abfd, NULL, &r)) 826 return FALSE; 827 828 for (i = 0; i < count; i++) 829 if (! nlm_alpha_write_import (abfd, relocs[i].sec, relocs[i].rel)) 830 return FALSE; 831 832 return TRUE; 833 } 834 835 #include "nlmswap.h" 836 837 static const struct nlm_backend_data nlm32_alpha_backend = 838 { 839 "NetWare Alpha Module \032", 840 sizeof (Nlm32_alpha_External_Fixed_Header), 841 sizeof (struct nlm32_alpha_external_prefix_header), 842 bfd_arch_alpha, 843 0, 844 TRUE, /* No uninitialized data permitted by Alpha NetWare. */ 845 nlm_alpha_backend_object_p, 846 nlm_alpha_write_prefix, 847 nlm_alpha_read_reloc, 848 nlm_alpha_mangle_relocs, 849 nlm_alpha_read_import, 850 nlm_alpha_write_import, 851 nlm_alpha_set_public_section, 852 nlm_alpha_get_public_offset, 853 nlm_swap_fixed_header_in, 854 nlm_swap_fixed_header_out, 855 nlm_alpha_write_external, 856 0, /* Write_export. */ 857 }; 858 859 #define TARGET_LITTLE_NAME "nlm32-alpha" 860 #define TARGET_LITTLE_SYM alpha_nlm32_vec 861 #define TARGET_BACKEND_DATA & nlm32_alpha_backend 862 863 #include "nlm-target.h" 864