X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fcoff-alpha.c;h=4056e2ce6e7de1b5803e6371ed4a145b7d9d1a2a;hb=86fb1dece37497b267579ed4f062d280cd5760cd;hp=402c9edd5d517caa9d29eae91a15a0bf2349a64e;hpb=64ecde46199487acc4409d3593069177aaabf1ff;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c index 402c9edd5d..4056e2ce6e 100644 --- a/bfd/coff-alpha.c +++ b/bfd/coff-alpha.c @@ -1,5 +1,6 @@ /* BFD back-end for ALPHA Extended-Coff files. - Copyright 1993, 1994 Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. Modified from coff-mips.c by Steve Chamberlain and Ian Lance Taylor . @@ -28,6 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "coff/symconst.h" #include "coff/ecoff.h" #include "coff/alpha.h" +#include "aout/ar.h" #include "libcoff.h" #include "libecoff.h" @@ -46,6 +48,8 @@ static void alpha_adjust_reloc_in PARAMS ((bfd *, arelent *)); static void alpha_adjust_reloc_out PARAMS ((bfd *, const arelent *, struct internal_reloc *)); +static reloc_howto_type *alpha_bfd_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); static bfd_byte *alpha_ecoff_get_relocated_section_contents PARAMS ((bfd *abfd, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *data, boolean relocateable, asymbol **symbols)); @@ -57,6 +61,10 @@ static boolean alpha_relocate_section PARAMS ((bfd *, struct bfd_link_info *, bfd_byte *, PTR)); static boolean alpha_adjust_headers PARAMS ((bfd *, struct internal_filehdr *, struct internal_aouthdr *)); +static PTR alpha_ecoff_read_ar_hdr PARAMS ((bfd *)); +static bfd *alpha_ecoff_get_elt_at_filepos PARAMS ((bfd *, file_ptr)); +static bfd *alpha_ecoff_openr_next_archived_file PARAMS ((bfd *, bfd *)); +static bfd *alpha_ecoff_get_elt_at_index PARAMS ((bfd *, symindex)); /* ECOFF has COFF sections, but the debugging information is stored in a completely different format. ECOFF targets use some of the @@ -68,32 +76,32 @@ static boolean alpha_adjust_headers symbol, and lineno ones. Give them ecoff names. Define some accessor macros for the large sizes used for Alpha ECOFF. */ -#define GET_FILEHDR_SYMPTR bfd_h_get_64 -#define PUT_FILEHDR_SYMPTR bfd_h_put_64 -#define GET_AOUTHDR_TSIZE bfd_h_get_64 -#define PUT_AOUTHDR_TSIZE bfd_h_put_64 -#define GET_AOUTHDR_DSIZE bfd_h_get_64 -#define PUT_AOUTHDR_DSIZE bfd_h_put_64 -#define GET_AOUTHDR_BSIZE bfd_h_get_64 -#define PUT_AOUTHDR_BSIZE bfd_h_put_64 -#define GET_AOUTHDR_ENTRY bfd_h_get_64 -#define PUT_AOUTHDR_ENTRY bfd_h_put_64 -#define GET_AOUTHDR_TEXT_START bfd_h_get_64 -#define PUT_AOUTHDR_TEXT_START bfd_h_put_64 -#define GET_AOUTHDR_DATA_START bfd_h_get_64 -#define PUT_AOUTHDR_DATA_START bfd_h_put_64 -#define GET_SCNHDR_PADDR bfd_h_get_64 -#define PUT_SCNHDR_PADDR bfd_h_put_64 -#define GET_SCNHDR_VADDR bfd_h_get_64 -#define PUT_SCNHDR_VADDR bfd_h_put_64 -#define GET_SCNHDR_SIZE bfd_h_get_64 -#define PUT_SCNHDR_SIZE bfd_h_put_64 -#define GET_SCNHDR_SCNPTR bfd_h_get_64 -#define PUT_SCNHDR_SCNPTR bfd_h_put_64 -#define GET_SCNHDR_RELPTR bfd_h_get_64 -#define PUT_SCNHDR_RELPTR bfd_h_put_64 -#define GET_SCNHDR_LNNOPTR bfd_h_get_64 -#define PUT_SCNHDR_LNNOPTR bfd_h_put_64 +#define GET_FILEHDR_SYMPTR H_GET_64 +#define PUT_FILEHDR_SYMPTR H_PUT_64 +#define GET_AOUTHDR_TSIZE H_GET_64 +#define PUT_AOUTHDR_TSIZE H_PUT_64 +#define GET_AOUTHDR_DSIZE H_GET_64 +#define PUT_AOUTHDR_DSIZE H_PUT_64 +#define GET_AOUTHDR_BSIZE H_GET_64 +#define PUT_AOUTHDR_BSIZE H_PUT_64 +#define GET_AOUTHDR_ENTRY H_GET_64 +#define PUT_AOUTHDR_ENTRY H_PUT_64 +#define GET_AOUTHDR_TEXT_START H_GET_64 +#define PUT_AOUTHDR_TEXT_START H_PUT_64 +#define GET_AOUTHDR_DATA_START H_GET_64 +#define PUT_AOUTHDR_DATA_START H_PUT_64 +#define GET_SCNHDR_PADDR H_GET_64 +#define PUT_SCNHDR_PADDR H_PUT_64 +#define GET_SCNHDR_VADDR H_GET_64 +#define PUT_SCNHDR_VADDR H_PUT_64 +#define GET_SCNHDR_SIZE H_GET_64 +#define PUT_SCNHDR_SIZE H_PUT_64 +#define GET_SCNHDR_SCNPTR H_GET_64 +#define PUT_SCNHDR_SCNPTR H_PUT_64 +#define GET_SCNHDR_RELPTR H_GET_64 +#define PUT_SCNHDR_RELPTR H_PUT_64 +#define GET_SCNHDR_LNNOPTR H_GET_64 +#define PUT_SCNHDR_LNNOPTR H_PUT_64 #define ALPHAECOFF @@ -120,13 +128,13 @@ reloc_nil PARAMS ((bfd *, arelent *, asymbol *, PTR, static bfd_reloc_status_type reloc_nil (abfd, reloc, sym, data, sec, output_bfd, error_message) - bfd *abfd; - arelent *reloc; - asymbol *sym; - PTR data; - asection *sec; - bfd *output_bfd; - char **error_message; + bfd *abfd ATTRIBUTE_UNUSED; + arelent *reloc ATTRIBUTE_UNUSED; + asymbol *sym ATTRIBUTE_UNUSED; + PTR data ATTRIBUTE_UNUSED; + asection *sec ATTRIBUTE_UNUSED; + bfd *output_bfd ATTRIBUTE_UNUSED; + char **error_message ATTRIBUTE_UNUSED; { return bfd_reloc_ok; } @@ -465,7 +473,7 @@ alpha_ecoff_object_p (abfd) static boolean alpha_ecoff_bad_format_hook (abfd, filehdr) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; PTR filehdr; { struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; @@ -522,10 +530,10 @@ alpha_ecoff_swap_reloc_in (abfd, ext_ptr, intern) { const RELOC *ext = (RELOC *) ext_ptr; - intern->r_vaddr = bfd_h_get_64 (abfd, (bfd_byte *) ext->r_vaddr); - intern->r_symndx = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_symndx); + intern->r_vaddr = H_GET_64 (abfd, ext->r_vaddr); + intern->r_symndx = H_GET_32 (abfd, ext->r_symndx); - BFD_ASSERT (abfd->xvec->header_byteorder_big_p == false); + BFD_ASSERT (bfd_header_little_endian (abfd)); intern->r_type = ((ext->r_bits[0] & RELOC_BITS0_TYPE_LITTLE) >> RELOC_BITS0_TYPE_SH_LITTLE); @@ -595,10 +603,10 @@ alpha_ecoff_swap_reloc_out (abfd, intern, dst) BFD_ASSERT (intern->r_extern || (intern->r_symndx >= 0 && intern->r_symndx <= 14)); - bfd_h_put_64 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr); - bfd_h_put_32 (abfd, symndx, (bfd_byte *) ext->r_symndx); + H_PUT_64 (abfd, intern->r_vaddr, ext->r_vaddr); + H_PUT_32 (abfd, symndx, ext->r_symndx); - BFD_ASSERT (abfd->xvec->header_byteorder_big_p == false); + BFD_ASSERT (bfd_header_little_endian (abfd)); ext->r_bits[0] = ((intern->r_type << RELOC_BITS0_TYPE_SH_LITTLE) & RELOC_BITS0_TYPE_LITTLE); @@ -629,9 +637,13 @@ alpha_adjust_reloc_in (abfd, intern, rptr) case ALPHA_R_SREL16: case ALPHA_R_SREL32: case ALPHA_R_SREL64: - /* The PC relative relocs do not seem to use the section VMA as - a negative addend. */ - rptr->addend = 0; + /* This relocs appear to be fully resolved when they are against + internal symbols. Against external symbols, BRADDR at least + appears to be resolved against the next instruction. */ + if (! intern->r_extern) + rptr->addend = 0; + else + rptr->addend = - (intern->r_vaddr + 4); break; case ALPHA_R_GPREL32: @@ -696,7 +708,7 @@ alpha_adjust_reloc_in (abfd, intern, rptr) static void alpha_adjust_reloc_out (abfd, rel, intern) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; const arelent *rel; struct internal_reloc *intern; { @@ -759,12 +771,9 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, if (reloc_size < 0) goto error_return; - reloc_vector = (arelent **) malloc (reloc_size); + reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); if (reloc_vector == NULL && reloc_size != 0) - { - bfd_set_error (bfd_error_no_memory); - goto error_return; - } + goto error_return; if (! bfd_get_section_contents (input_bfd, input_section, data, (file_ptr) 0, input_section->_raw_size)) @@ -783,7 +792,8 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, /* Get the GP value for the output BFD. */ gp_undefined = false; - if (ecoff_data (abfd)->gp == 0) + gp = _bfd_get_gp_value (abfd); + if (gp == 0) { if (relocateable != false) { @@ -802,7 +812,8 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, || strcmp (sec->name, ".lita") == 0)) lo = sec->vma; } - ecoff_data (abfd)->gp = lo + 0x8000; + gp = lo + 0x8000; + _bfd_set_gp_value (abfd, gp); } else { @@ -814,12 +825,14 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, || h->type != bfd_link_hash_defined) gp_undefined = true; else - ecoff_data (abfd)->gp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); + { + gp = (h->u.def.value + + h->u.def.section->output_section->vma + + h->u.def.section->output_offset); + _bfd_set_gp_value (abfd, gp); + } } } - gp = ecoff_data (abfd)->gp; for (; *reloc_vector != (arelent *) NULL; reloc_vector++) { @@ -865,7 +878,7 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, if (r == bfd_reloc_ok && gp_undefined) { r = bfd_reloc_dangerous; - err = (char *) "GP relative relocation used when GP not defined"; + err = (char *) _("GP relative relocation used when GP not defined"); } break; @@ -902,7 +915,7 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, { r = bfd_reloc_dangerous; err = - (char *) "GP relative relocation used when GP not defined"; + (char *) _("GP relative relocation used when GP not defined"); } } break; @@ -912,21 +925,17 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, does not cause anything to happen, itself. */ rel->address += input_section->output_offset; break; - + case ALPHA_R_GPDISP: /* This marks the ldah of an ldah/lda pair which loads the gp register with the difference of the gp value and the current location. The second of the pair is r_size bytes - ahead, and is marked with an ALPHA_R_IGNORE reloc. */ + ahead; it used to be marked with an ALPHA_R_IGNORE reloc, + but that no longer happens in OSF/1 3.2. */ { unsigned long insn1, insn2; bfd_vma addend; - BFD_ASSERT (reloc_vector[1] != NULL - && reloc_vector[1]->howto->type == ALPHA_R_IGNORE - && (rel->address + rel->addend - == reloc_vector[1]->address)); - /* Get the two instructions. */ insn1 = bfd_get_32 (input_bfd, data + rel->address); insn2 = bfd_get_32 (input_bfd, data + rel->address + rel->addend); @@ -948,7 +957,7 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, /* The existing addend includes the different between the gp of the input BFD and the address in the input BFD. Subtract this out. */ - addend -= (reloc_vector[1]->addend + addend -= (ecoff_data (input_bfd)->gp - (input_section->vma + rel->address)); /* Now add in the final gp value, and subtract out the @@ -972,7 +981,7 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, rel->address += input_section->output_offset; } break; - + case ALPHA_R_OP_PUSH: /* Push a value on the reloc evaluation stack. */ { @@ -1098,7 +1107,7 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, stack[tos - 1] >>= relocation; } break; - + case ALPHA_R_GPVALUE: /* I really don't know if this does the right thing. */ gp = rel->addend; @@ -1118,17 +1127,17 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, os->reloc_count++; } - if (r != bfd_reloc_ok) + if (r != bfd_reloc_ok) { switch (r) { case bfd_reloc_undefined: if (! ((*link_info->callbacks->undefined_symbol) (link_info, bfd_asymbol_name (*rel->sym_ptr_ptr), - input_bfd, input_section, rel->address))) + input_bfd, input_section, rel->address, true))) goto error_return; break; - case bfd_reloc_dangerous: + case bfd_reloc_dangerous: if (! ((*link_info->callbacks->reloc_dangerous) (link_info, err, input_bfd, input_section, rel->address))) @@ -1167,7 +1176,7 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, static reloc_howto_type * alpha_bfd_reloc_type_lookup (abfd, code) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; bfd_reloc_code_real_type code; { int alpha_type; @@ -1241,7 +1250,7 @@ alpha_bfd_reloc_type_lookup (abfd, code) static bfd_vma alpha_convert_external_reloc (output_bfd, info, input_bfd, ext_rel, h) - bfd *output_bfd; + bfd *output_bfd ATTRIBUTE_UNUSED; struct bfd_link_info *info; bfd *input_bfd; struct external_reloc *ext_rel; @@ -1268,7 +1277,7 @@ alpha_convert_external_reloc (output_bfd, info, input_bfd, ext_rel, h) hsec = h->root.u.def.section; name = bfd_get_section_name (output_bfd, hsec->output_section); - r_symndx = -1; + r_symndx = (unsigned long) -1; switch (name[1]) { case 'A': @@ -1324,8 +1333,8 @@ alpha_convert_external_reloc (output_bfd, info, input_bfd, ext_rel, h) r_symndx = RELOC_SECTION_XDATA; break; } - - if (r_symndx == -1) + + if (r_symndx == (unsigned long) -1) abort (); /* Add the section VMA and the symbol value. */ @@ -1338,7 +1347,7 @@ alpha_convert_external_reloc (output_bfd, info, input_bfd, ext_rel, h) /* Change the symndx value to the right one for the output BFD. */ r_symndx = h->indx; - if (r_symndx == -1) + if (r_symndx == (unsigned long) -1) { /* Caller must give an error. */ r_symndx = 0; @@ -1347,8 +1356,7 @@ alpha_convert_external_reloc (output_bfd, info, input_bfd, ext_rel, h) } /* Write out the new r_symndx value. */ - bfd_h_put_32 (input_bfd, (bfd_vma) r_symndx, - (bfd_byte *) ext_rel->r_symndx); + H_PUT_32 (input_bfd, r_symndx, ext_rel->r_symndx); return relocation; } @@ -1367,7 +1375,7 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, bfd_byte *contents; PTR external_relocs; { - asection **symndx_to_section; + asection **symndx_to_section, *lita_sec; struct ecoff_link_hash_entry **sym_hashes; bfd_vma gp; boolean gp_undefined; @@ -1375,6 +1383,7 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, int tos = 0; struct external_reloc *ext_rel; struct external_reloc *ext_rel_end; + bfd_size_type amt; /* We keep a table mapping the symndx found in an internal reloc to the appropriate section. This is faster than looking up the @@ -1382,15 +1391,10 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, symndx_to_section = ecoff_data (input_bfd)->symndx_to_section; if (symndx_to_section == (asection **) NULL) { - symndx_to_section = ((asection **) - bfd_alloc (input_bfd, - (NUM_RELOC_SECTIONS - * sizeof (asection *)))); + amt = NUM_RELOC_SECTIONS * sizeof (asection *); + symndx_to_section = (asection **) bfd_alloc (input_bfd, amt); if (!symndx_to_section) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; symndx_to_section[RELOC_SECTION_NONE] = NULL; symndx_to_section[RELOC_SECTION_TEXT] = @@ -1428,14 +1432,78 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, sym_hashes = ecoff_data (input_bfd)->sym_hashes; - gp = ecoff_data (output_bfd)->gp; - if (gp == 0) - gp_undefined = true; - else - gp_undefined = false; + /* On the Alpha, the .lita section must be addressable by the global + pointer. To support large programs, we need to allow multiple + global pointers. This works as long as each input .lita section + is <64KB big. This implies that when producing relocatable + output, the .lita section is limited to 64KB. . */ + + lita_sec = symndx_to_section[RELOC_SECTION_LITA]; + gp = _bfd_get_gp_value (output_bfd); + if (! info->relocateable && lita_sec != NULL) + { + struct ecoff_section_tdata *lita_sec_data; + + /* Make sure we have a section data structure to which we can + hang on to the gp value we pick for the section. */ + lita_sec_data = ecoff_section_data (input_bfd, lita_sec); + if (lita_sec_data == NULL) + { + amt = sizeof (struct ecoff_section_tdata); + lita_sec_data = ((struct ecoff_section_tdata *) + bfd_zalloc (input_bfd, amt)); + ecoff_section_data (input_bfd, lita_sec) = lita_sec_data; + } + + if (lita_sec_data->gp != 0) + { + /* If we already assigned a gp to this section, we better + stick with that value. */ + gp = lita_sec_data->gp; + } + else + { + bfd_vma lita_vma; + bfd_size_type lita_size; - BFD_ASSERT (output_bfd->xvec->header_byteorder_big_p == false); - BFD_ASSERT (input_bfd->xvec->header_byteorder_big_p == false); + lita_vma = lita_sec->output_offset + lita_sec->output_section->vma; + lita_size = lita_sec->_cooked_size; + if (lita_size == 0) + lita_size = lita_sec->_raw_size; + + if (gp == 0 + || lita_vma < gp - 0x8000 + || lita_vma + lita_size >= gp + 0x8000) + { + /* Either gp hasn't been set at all or the current gp + cannot address this .lita section. In both cases we + reset the gp to point into the "middle" of the + current input .lita section. */ + if (gp && !ecoff_data (output_bfd)->issued_multiple_gp_warning) + { + (*info->callbacks->warning) (info, + _("using multiple gp values"), + (char *) NULL, output_bfd, + (asection *) NULL, (bfd_vma) 0); + ecoff_data (output_bfd)->issued_multiple_gp_warning = true; + } + if (lita_vma < gp - 0x8000) + gp = lita_vma + lita_size - 0x8000; + else + gp = lita_vma + 0x8000; + + } + + lita_sec_data->gp = gp; + } + + _bfd_set_gp_value (output_bfd, gp); + } + + gp_undefined = (gp == 0); + + BFD_ASSERT (bfd_header_little_endian (output_bfd)); + BFD_ASSERT (bfd_header_little_endian (input_bfd)); ext_rel = (struct external_reloc *) external_relocs; ext_rel_end = ext_rel + input_section->reloc_count; @@ -1452,8 +1520,8 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, boolean gp_usedp; bfd_vma addend; - r_vaddr = bfd_h_get_64 (input_bfd, (bfd_byte *) ext_rel->r_vaddr); - r_symndx = bfd_h_get_32 (input_bfd, (bfd_byte *) ext_rel->r_symndx); + r_vaddr = H_GET_64 (input_bfd, ext_rel->r_vaddr); + r_symndx = H_GET_32 (input_bfd, ext_rel->r_symndx); r_type = ((ext_rel->r_bits[0] & RELOC_BITS0_TYPE_LITTLE) >> RELOC_BITS0_TYPE_SH_LITTLE); @@ -1475,26 +1543,30 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, abort (); case ALPHA_R_IGNORE: - /* This reloc appears after a GPDISP reloc. It marks the - position of the second instruction to be altered by the - GPDISP reloc, but is not otherwise used for anything. - For some reason, the address of the relocation does not - appear to include the section VMA, unlike the other - relocation types. */ + /* This reloc appears after a GPDISP reloc. On earlier + versions of OSF/1, It marked the position of the second + instruction to be altered by the GPDISP reloc, but it is + not otherwise used for anything. For some reason, the + address of the relocation does not appear to include the + section VMA, unlike the other relocation types. */ if (info->relocateable) - bfd_h_put_64 (input_bfd, - input_section->output_offset + r_vaddr, - (bfd_byte *) ext_rel->r_vaddr); + H_PUT_64 (input_bfd, input_section->output_offset + r_vaddr, + ext_rel->r_vaddr); adjust_addrp = false; break; case ALPHA_R_REFLONG: case ALPHA_R_REFQUAD: - case ALPHA_R_BRADDR: case ALPHA_R_HINT: + relocatep = true; + break; + + case ALPHA_R_BRADDR: case ALPHA_R_SREL16: case ALPHA_R_SREL32: case ALPHA_R_SREL64: + if (r_extern) + addend += - (r_vaddr + 4); relocatep = true; break; @@ -1545,24 +1617,16 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, /* See ALPHA_R_LITERAL above for the uses of this reloc. It does not cause anything to happen, itself. */ break; - + case ALPHA_R_GPDISP: /* This marks the ldah of an ldah/lda pair which loads the gp register with the difference of the gp value and the current location. The second of the pair is r_symndx - bytes ahead, and is also marked with an ALPHA_R_IGNORE - reloc. */ + bytes ahead. It used to be marked with an ALPHA_R_IGNORE + reloc, but OSF/1 3.2 no longer does that. */ { unsigned long insn1, insn2; - BFD_ASSERT (ext_rel + 1 < ext_rel_end - && (((ext_rel + 1)->r_bits[0] - & RELOC_BITS0_TYPE_LITTLE) - >> RELOC_BITS0_TYPE_SH_LITTLE) == ALPHA_R_IGNORE - && (bfd_h_get_64 (input_bfd, - (bfd_byte *) (ext_rel + 1)->r_vaddr) - == r_vaddr - input_section->vma + r_symndx)); - /* Get the two instructions. */ insn1 = bfd_get_32 (input_bfd, contents + r_vaddr - input_section->vma); @@ -1613,7 +1677,7 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, gp_usedp = true; } break; - + case ALPHA_R_OP_PUSH: case ALPHA_R_OP_PSUB: case ALPHA_R_OP_PRSHIFT: @@ -1653,7 +1717,7 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, relocated. */ if (! ((*info->callbacks->undefined_symbol) (info, h->root.root.string, input_bfd, - input_section, (bfd_vma) 0))) + input_section, (bfd_vma) 0, true))) return false; addend = 0; } @@ -1684,8 +1748,7 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, if (info->relocateable) { /* Adjust r_vaddr by the addend. */ - bfd_h_put_64 (input_bfd, addend, - (bfd_byte *) ext_rel->r_vaddr); + H_PUT_64 (input_bfd, addend, ext_rel->r_vaddr); } else { @@ -1855,7 +1918,7 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, if (! ((*info->callbacks->undefined_symbol) (info, h->root.root.string, input_bfd, input_section, - r_vaddr - input_section->vma))) + r_vaddr - input_section->vma, true))) return false; relocation = 0; } @@ -1912,22 +1975,23 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, if (info->relocateable && adjust_addrp) { /* Change the address of the relocation. */ - bfd_h_put_64 (input_bfd, - (input_section->output_section->vma - + input_section->output_offset - - input_section->vma - + r_vaddr), - (bfd_byte *) ext_rel->r_vaddr); + H_PUT_64 (input_bfd, + (input_section->output_section->vma + + input_section->output_offset + - input_section->vma + + r_vaddr), + ext_rel->r_vaddr); } if (gp_usedp && gp_undefined) { if (! ((*info->callbacks->reloc_dangerous) - (info, "GP relative relocation when GP not defined", + (info, _("GP relative relocation used when GP not defined"), input_bfd, input_section, r_vaddr - input_section->vma))) return false; /* Only give the error once per link. */ - ecoff_data (output_bfd)->gp = gp = 4; + gp = 4; + _bfd_set_gp_value (output_bfd, gp); gp_undefined = false; } } @@ -1941,12 +2005,11 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section, /* Do final adjustments to the filehdr and the aouthdr. This routine sets the dynamic bits in the file header. */ -/*ARGSUSED*/ static boolean alpha_adjust_headers (abfd, fhdr, ahdr) bfd *abfd; struct internal_filehdr *fhdr; - struct internal_aouthdr *ahdr; + struct internal_aouthdr *ahdr ATTRIBUTE_UNUSED; { if ((abfd->flags & (DYNAMIC | EXEC_P)) == (DYNAMIC | EXEC_P)) fhdr->f_flags |= F_ALPHA_CALL_SHARED; @@ -1955,6 +2018,234 @@ alpha_adjust_headers (abfd, fhdr, ahdr) return true; } +/* Archive handling. In OSF/1 (or Digital Unix) v3.2, Digital + introduced archive packing, in which the elements in an archive are + optionally compressed using a simple dictionary scheme. We know + how to read such archives, but we don't write them. */ + +#define alpha_ecoff_slurp_armap _bfd_ecoff_slurp_armap +#define alpha_ecoff_slurp_extended_name_table \ + _bfd_ecoff_slurp_extended_name_table +#define alpha_ecoff_construct_extended_name_table \ + _bfd_ecoff_construct_extended_name_table +#define alpha_ecoff_truncate_arname _bfd_ecoff_truncate_arname +#define alpha_ecoff_write_armap _bfd_ecoff_write_armap +#define alpha_ecoff_generic_stat_arch_elt _bfd_ecoff_generic_stat_arch_elt +#define alpha_ecoff_update_armap_timestamp _bfd_ecoff_update_armap_timestamp + +/* A compressed file uses this instead of ARFMAG. */ + +#define ARFZMAG "Z\012" + +/* Read an archive header. This is like the standard routine, but it + also accepts ARFZMAG. */ + +static PTR +alpha_ecoff_read_ar_hdr (abfd) + bfd *abfd; +{ + struct areltdata *ret; + struct ar_hdr *h; + + ret = (struct areltdata *) _bfd_generic_read_ar_hdr_mag (abfd, ARFZMAG); + if (ret == NULL) + return NULL; + + h = (struct ar_hdr *) ret->arch_header; + if (strncmp (h->ar_fmag, ARFZMAG, 2) == 0) + { + bfd_byte ab[8]; + + /* This is a compressed file. We must set the size correctly. + The size is the eight bytes after the dummy file header. */ + if (bfd_seek (abfd, (file_ptr) FILHSZ, SEEK_CUR) != 0 + || bfd_bread (ab, (bfd_size_type) 8, abfd) != 8 + || bfd_seek (abfd, (file_ptr) (- (FILHSZ + 8)), SEEK_CUR) != 0) + return NULL; + + ret->parsed_size = H_GET_64 (abfd, ab); + } + + return (PTR) ret; +} + +/* Get an archive element at a specified file position. This is where + we uncompress the archive element if necessary. */ + +static bfd * +alpha_ecoff_get_elt_at_filepos (archive, filepos) + bfd *archive; + file_ptr filepos; +{ + bfd *nbfd = NULL; + struct areltdata *tdata; + struct ar_hdr *hdr; + bfd_byte ab[8]; + bfd_size_type size; + bfd_byte *buf, *p; + struct bfd_in_memory *bim; + + nbfd = _bfd_get_elt_at_filepos (archive, filepos); + if (nbfd == NULL) + goto error_return; + + if ((nbfd->flags & BFD_IN_MEMORY) != 0) + { + /* We have already expanded this BFD. */ + return nbfd; + } + + tdata = (struct areltdata *) nbfd->arelt_data; + hdr = (struct ar_hdr *) tdata->arch_header; + if (strncmp (hdr->ar_fmag, ARFZMAG, 2) != 0) + return nbfd; + + /* We must uncompress this element. We do this by copying it into a + memory buffer, and making bfd_bread and bfd_seek use that buffer. + This can use a lot of memory, but it's simpler than getting a + temporary file, making that work with the file descriptor caching + code, and making sure that it is deleted at all appropriate + times. It can be changed if it ever becomes important. */ + + /* The compressed file starts with a dummy ECOFF file header. */ + if (bfd_seek (nbfd, (file_ptr) FILHSZ, SEEK_SET) != 0) + goto error_return; + + /* The next eight bytes are the real file size. */ + if (bfd_bread (ab, (bfd_size_type) 8, nbfd) != 8) + goto error_return; + size = H_GET_64 (nbfd, ab); + + if (size == 0) + buf = NULL; + else + { + bfd_size_type left; + bfd_byte dict[4096]; + unsigned int h; + bfd_byte b; + + buf = (bfd_byte *) bfd_alloc (nbfd, size); + if (buf == NULL) + goto error_return; + p = buf; + + left = size; + + /* I don't know what the next eight bytes are for. */ + if (bfd_bread (ab, (bfd_size_type) 8, nbfd) != 8) + goto error_return; + + /* This is the uncompression algorithm. It's a simple + dictionary based scheme in which each character is predicted + by a hash of the previous three characters. A control byte + indicates whether the character is predicted or whether it + appears in the input stream; each control byte manages the + next eight bytes in the output stream. */ + memset (dict, 0, sizeof dict); + h = 0; + while (bfd_bread (&b, (bfd_size_type) 1, nbfd) == 1) + { + unsigned int i; + + for (i = 0; i < 8; i++, b >>= 1) + { + bfd_byte n; + + if ((b & 1) == 0) + n = dict[h]; + else + { + if (! bfd_bread (&n, (bfd_size_type) 1, nbfd)) + goto error_return; + dict[h] = n; + } + + *p++ = n; + + --left; + if (left == 0) + break; + + h <<= 4; + h ^= n; + h &= sizeof dict - 1; + } + + if (left == 0) + break; + } + } + + /* Now the uncompressed file contents are in buf. */ + bim = ((struct bfd_in_memory *) + bfd_alloc (nbfd, (bfd_size_type) sizeof (struct bfd_in_memory))); + if (bim == NULL) + goto error_return; + bim->size = size; + bim->buffer = buf; + + nbfd->mtime_set = true; + nbfd->mtime = strtol (hdr->ar_date, (char **) NULL, 10); + + nbfd->flags |= BFD_IN_MEMORY; + nbfd->iostream = (PTR) bim; + BFD_ASSERT (! nbfd->cacheable); + + return nbfd; + + error_return: + if (nbfd != NULL) + bfd_close (nbfd); + return NULL; +} + +/* Open the next archived file. */ + +static bfd * +alpha_ecoff_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + file_ptr filestart; + + if (last_file == NULL) + filestart = bfd_ardata (archive)->first_file_filepos; + else + { + struct areltdata *t; + struct ar_hdr *h; + bfd_size_type size; + + /* We can't use arelt_size here, because that uses parsed_size, + which is the uncompressed size. We need the compressed size. */ + t = (struct areltdata *) last_file->arelt_data; + h = (struct ar_hdr *) t->arch_header; + size = strtol (h->ar_size, (char **) NULL, 10); + + /* Pad to an even boundary... + Note that last_file->origin can be odd in the case of + BSD-4.4-style element with a long odd size. */ + filestart = last_file->origin + size; + filestart += filestart % 2; + } + + return alpha_ecoff_get_elt_at_filepos (archive, filestart); +} + +/* Open the archive file given an index into the armap. */ + +static bfd * +alpha_ecoff_get_elt_at_index (abfd, index) + bfd *abfd; + symindex index; +{ + carsym *entry; + + entry = bfd_ardata (abfd)->symdefs + index; + return alpha_ecoff_get_elt_at_filepos (abfd, entry->file_offset); +} + /* This is the ECOFF backend structure. The backend field of the target vector points to this. */ @@ -1971,13 +2262,14 @@ static const struct ecoff_backend_data alpha_ecoff_backend_data = (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */ alpha_ecoff_swap_filehdr_out, alpha_ecoff_swap_aouthdr_out, alpha_ecoff_swap_scnhdr_out, - FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, true, + FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, true, false, 4, false, 2, alpha_ecoff_swap_filehdr_in, alpha_ecoff_swap_aouthdr_in, alpha_ecoff_swap_scnhdr_in, NULL, alpha_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook, alpha_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags, _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL }, /* Supported architecture. */ bfd_arch_alpha, @@ -2044,7 +2336,9 @@ static const struct ecoff_backend_data alpha_ecoff_backend_data = /* Relocate section contents while linking. */ alpha_relocate_section, /* Do final adjustments to filehdr and aouthdr. */ - alpha_adjust_headers + alpha_adjust_headers, + /* Read an element from an archive at a given file position. */ + alpha_ecoff_get_elt_at_filepos }; /* Looking up a reloc type is Alpha specific. */ @@ -2060,13 +2354,15 @@ static const struct ecoff_backend_data alpha_ecoff_backend_data = /* Relaxing sections is generic. */ #define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section +#define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections +#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections const bfd_target ecoffalpha_little_vec = { "ecoff-littlealpha", /* name */ bfd_target_ecoff_flavour, - false, /* data byte order is little */ - false, /* header byte order is little */ + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ (HAS_RELOC | EXEC_P | /* object flags */ HAS_LINENO | HAS_DEBUG | @@ -2093,12 +2389,14 @@ const bfd_target ecoffalpha_little_vec = BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), BFD_JUMP_TABLE_COPY (_bfd_ecoff), BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff), + BFD_JUMP_TABLE_ARCHIVE (alpha_ecoff), BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), BFD_JUMP_TABLE_WRITE (_bfd_ecoff), BFD_JUMP_TABLE_LINK (_bfd_ecoff), BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + NULL, + (PTR) &alpha_ecoff_backend_data };