diff options
-rw-r--r-- | bfd/ChangeLog | 11 | ||||
-rw-r--r-- | bfd/elf64-alpha.c | 121 |
2 files changed, 95 insertions, 37 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index fd785ee..8651b50 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,16 @@ 2005-05-22 Richard Henderson <rth@redhat.com> + * elf64-alpha.c (elf64_alpha_relax_with_lituse): Relax jsr to + undefweak to use zero register. Call elf64_alpha_relax_got_load + if not all uses removed. + (elf64_alpha_relax_got_load): Relax undefweak to lda zero. + (elf64_alpha_relax_section): Handle undefweak symbols. + (elf64_alpha_calc_dynrel_sizes): Don't add relocs for undefweak. + (elf64_alpha_size_rela_got_1): Likewise. + (elf64_alpha_relocate_section): Likewise. + +2005-05-22 Richard Henderson <rth@redhat.com> + * elf64-alpha.c (elf64_alpha_relax_section): Only operate on SEC_CODE sections. diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c index 1778b92..8662129 100644 --- a/bfd/elf64-alpha.c +++ b/bfd/elf64-alpha.c @@ -1300,9 +1300,7 @@ elf64_alpha_relax_with_lituse (info, symval, irel) /* Extract the displacement from the instruction, sign-extending it if necessary, then test whether it is within 16 or 32 bits displacement from GP. */ - insn_disp = insn & 0x0000ffff; - if (insn_disp & 0x8000) - insn_disp |= ~0xffff; /* Negative: sign-extend. */ + insn_disp = ((insn & 0xffff) ^ 0x8000) - 0x8000; xdisp = disp + insn_disp; fits16 = (xdisp >= - (bfd_signed_vma) 0x8000 && xdisp < 0x8000); @@ -1371,6 +1369,19 @@ elf64_alpha_relax_with_lituse (info, symval, irel) bfd_vma optdest, org; bfd_signed_vma odisp; + /* For undefined weak symbols, we're mostly interested in getting + rid of the got entry whenever possible, so optimize this to a + use of the zero register. */ + if (info->h && info->h->root.root.type == bfd_link_hash_undefweak) + { + insn |= 31 << 16; + bfd_put_32 (info->abfd, (bfd_vma) insn, + info->contents + urel->r_offset); + + info->changed_contents = TRUE; + break; + } + /* If not zero, place to jump without needing pv. */ optdest = elf64_alpha_relax_opt_call (info, symval); org = (info->sec->output_section->vma @@ -1474,9 +1485,11 @@ elf64_alpha_relax_with_lituse (info, symval, irel) info->contents + irel->r_offset); info->changed_contents = TRUE; } - } - return TRUE; + return TRUE; + } + else + return elf64_alpha_relax_got_load (info, symval, irel, R_ALPHA_LITERAL); } static bfd_vma @@ -1583,7 +1596,25 @@ elf64_alpha_relax_got_load (info, symval, irel, r_type) return TRUE; if (r_type == R_ALPHA_LITERAL) - disp = symval - info->gp; + { + /* Look for nice constant addresses. This includes the not-uncommon + special case of 0 for undefweak symbols. */ + if ((info->h && info->h->root.root.type == bfd_link_hash_undefweak) + || (!info->link_info->shared + && (symval >= (bfd_vma)-0x8000 || symval < 0x8000))) + { + disp = 0; + insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16); + insn |= (symval & 0xffff); + r_type = R_ALPHA_NONE; + } + else + { + disp = symval - info->gp; + insn = (OP_LDA << 26) | (insn & 0x03ff0000); + r_type = R_ALPHA_GPREL16; + } + } else { bfd_vma dtp_base, tp_base; @@ -1592,17 +1623,26 @@ elf64_alpha_relax_got_load (info, symval, irel, r_type) dtp_base = alpha_get_dtprel_base (info->link_info); tp_base = alpha_get_tprel_base (info->link_info); disp = symval - (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base); + + insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16); + + switch (r_type) + { + case R_ALPHA_GOTDTPREL: + r_type = R_ALPHA_DTPREL16; + break; + case R_ALPHA_GOTTPREL: + r_type = R_ALPHA_TPREL16; + break; + default: + BFD_ASSERT (0); + return FALSE; + } } if (disp < -0x8000 || disp >= 0x8000) return TRUE; - /* Exchange LDQ for LDA. In the case of the TLS relocs, we're loading - a constant, so force the base register to be $31. */ - if (r_type == R_ALPHA_LITERAL) - insn = (OP_LDA << 26) | (insn & 0x03ff0000); - else - insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16); bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset); info->changed_contents = TRUE; @@ -1617,22 +1657,6 @@ elf64_alpha_relax_got_load (info, symval, irel, r_type) } /* Smash the existing GOT relocation for its 16-bit immediate pair. */ - switch (r_type) - { - case R_ALPHA_LITERAL: - r_type = R_ALPHA_GPREL16; - break; - case R_ALPHA_GOTDTPREL: - r_type = R_ALPHA_DTPREL16; - break; - case R_ALPHA_GOTTPREL: - r_type = R_ALPHA_TPREL16; - break; - default: - BFD_ASSERT (0); - return FALSE; - } - irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), r_type); info->changed_relocs = TRUE; @@ -2103,13 +2127,17 @@ elf64_alpha_relax_section (abfd, sec, link_info, again) h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link; /* If the symbol is undefined, we can't do anything with it. */ - if (h->root.root.type == bfd_link_hash_undefweak - || h->root.root.type == bfd_link_hash_undefined) + if (h->root.root.type == bfd_link_hash_undefined) continue; - /* If the symbol isn't defined in the current module, again - we can't do anything. */ - if (!h->root.def_regular) + /* If the symbol isn't defined in the current module, + again we can't do anything. */ + if (h->root.root.type == bfd_link_hash_undefweak) + { + info.tsec = bfd_abs_section_ptr; + symval = 0; + } + else if (!h->root.def_regular) { /* Except for TLSGD relocs, which can sometimes be relaxed to GOTTPREL relocs. */ @@ -3860,9 +3888,14 @@ elf64_alpha_calc_dynrel_sizes (h, info) /* If the symbol is dynamic, we'll need all the relocations in their natural form. If this is a shared object, and it has been forced local, we'll need the same number of RELATIVE relocations. */ - dynamic = alpha_elf_dynamic_symbol_p (&h->root, info); + /* If the symbol is a hidden undefined weak, then we never have any + relocations. Avoid the loop which may want to add RELATIVE relocs + based on info->shared. */ + if (h->root.root.type == bfd_link_hash_undefweak && !dynamic) + return TRUE; + for (relent = h->reloc_entries; relent; relent = relent->next) { entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic, @@ -3950,9 +3983,14 @@ elf64_alpha_size_rela_got_1 (h, info) /* If the symbol is dynamic, we'll need all the relocations in their natural form. If this is a shared object, and it has been forced local, we'll need the same number of RELATIVE relocations. */ - dynamic = alpha_elf_dynamic_symbol_p (&h->root, info); + /* If the symbol is a hidden undefined weak, then we never have any + relocations. Avoid the loop which may want to add RELATIVE relocs + based on info->shared. */ + if (h->root.root.type == bfd_link_hash_undefweak && !dynamic) + return TRUE; + entries = 0; for (gotent = h->got_entries; gotent ; gotent = gotent->next) if (gotent->use_count > 0) @@ -4445,7 +4483,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, /* If the symbol has been forced local, output a RELATIVE reloc, otherwise it will be handled in finish_dynamic_symbol. */ - if (info->shared && !dynamic_symbol_p) + if (info->shared && !dynamic_symbol_p && !undef_weak_ref) elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot, gotent->got_offset, 0, R_ALPHA_RELATIVE, value); @@ -4617,7 +4655,8 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, } else if (info->shared && r_symndx != 0 - && (input_section->flags & SEC_ALLOC)) + && (input_section->flags & SEC_ALLOC) + && !undef_weak_ref) { if (r_type == R_ALPHA_REFLONG) { @@ -4650,6 +4689,14 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, input_bfd, h->root.root.root.string); ret_val = FALSE; } + else if ((info->shared || info->pie) && undef_weak_ref) + { + (*_bfd_error_handler) + (_("%B: pc-relative relocation against undefined weak symbol %s"), + input_bfd, h->root.root.root.string); + ret_val = FALSE; + } + /* ??? .eh_frame references to discarded sections will be smashed to relocations against SHN_UNDEF. The .eh_frame format allows |