From 2c4c2bc0a526e8e0c186cd7cb005e2947cac3b88 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 28 Feb 2003 00:22:46 +0000 Subject: * elfxx-ia64.c (struct elfNN_ia64_dyn_sym_info): Add want_gotx; (elfNN_ia64_check_relocs): Set it. (allocate_global_data_got): Check it. (allocate_local_got): Likewise. (allocate_dynrel_entries): Likewise. (elfNN_ia64_relax_ldxmov): New. (elfNN_ia64_relax_section): Handle LTOFF22X, LDXMOV. (elfNN_ia64_choose_gp): Split out from ... (elfNN_ia64_final_link): ... here. --- bfd/ChangeLog | 12 ++ bfd/elfxx-ia64.c | 561 ++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 358 insertions(+), 215 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 62018ee..4fd2856 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +2003-02-27 Richard Henderson + + * elfxx-ia64.c (struct elfNN_ia64_dyn_sym_info): Add want_gotx; + (elfNN_ia64_check_relocs): Set it. + (allocate_global_data_got): Check it. + (allocate_local_got): Likewise. + (allocate_dynrel_entries): Likewise. + (elfNN_ia64_relax_ldxmov): New. + (elfNN_ia64_relax_section): Handle LTOFF22X, LDXMOV. + (elfNN_ia64_choose_gp): Split out from ... + (elfNN_ia64_final_link): ... here. + 2003-02-27 Andrew Cagney * bfd.c (struct bfd): Rename "struct _bfd". diff --git a/bfd/elfxx-ia64.c b/bfd/elfxx-ia64.c index e42d7ba..22c3416 100644 --- a/bfd/elfxx-ia64.c +++ b/bfd/elfxx-ia64.c @@ -102,6 +102,7 @@ struct elfNN_ia64_dyn_sym_info /* TRUE for the different kinds of linker data we want created. */ unsigned want_got : 1; + unsigned want_gotx : 1; unsigned want_fptr : 1; unsigned want_ltoff_fptr : 1; unsigned want_plt : 1; @@ -154,6 +155,12 @@ struct elfNN_ia64_link_hash_table struct elfNN_ia64_local_hash_table loc_hash_table; }; +struct elfNN_ia64_allocate_data +{ + struct bfd_link_info *info; + bfd_size_type ofs; +}; + #define elfNN_ia64_hash_table(p) \ ((struct elfNN_ia64_link_hash_table *) ((p)->hash)) @@ -169,6 +176,8 @@ static void elfNN_ia64_info_to_howto static bfd_boolean elfNN_ia64_relax_section PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again)); +static void elfNN_ia64_relax_ldxmov + PARAMS((bfd *abfd, bfd_byte *contents, bfd_vma off)); static bfd_boolean is_unwind_section_name PARAMS ((bfd *abfd, const char *)); static bfd_boolean elfNN_ia64_section_from_shdr @@ -299,6 +308,8 @@ static bfd_vma elfNN_ia64_dtprel_base PARAMS ((struct bfd_link_info *info)); static int elfNN_ia64_unwind_entry_compare PARAMS ((const PTR, const PTR)); +static bfd_boolean elfNN_ia64_choose_gp + PARAMS ((bfd *abfd, struct bfd_link_info *info)); static bfd_boolean elfNN_ia64_final_link PARAMS ((bfd *abfd, struct bfd_link_info *info)); static bfd_boolean elfNN_ia64_relocate_section @@ -671,11 +682,7 @@ static const bfd_byte oor_ip[48] = }; #endif -/* These functions do relaxation for IA-64 ELF. - - This is primarily to support branches to targets out of range; - relaxation of R_IA64_LTOFF22X and R_IA64_LDXMOV is handled in - relocate_section directly. */ +/* These functions do relaxation for IA-64 ELF. */ static bfd_boolean elfNN_ia64_relax_section (abfd, sec, link_info, again) @@ -701,6 +708,8 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) struct one_fixup *fixups = NULL; bfd_boolean changed_contents = FALSE; bfd_boolean changed_relocs = FALSE; + bfd_boolean changed_got = FALSE; + bfd_vma gp = 0; /* Assume we're not going to change any sizes, and we'll only need one pass. */ @@ -728,24 +737,6 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) ia64_info = elfNN_ia64_hash_table (link_info); irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - unsigned long r_type = ELFNN_R_TYPE (irel->r_info); - if (r_type == R_IA64_PCREL21B - || r_type == R_IA64_PCREL21BI - || r_type == R_IA64_PCREL21M - || r_type == R_IA64_PCREL21F) - break; - } - - /* No branch-type relocations. */ - if (irel == irelend) - { - if (elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - return TRUE; - } - /* Get the section contents. */ if (elf_section_data (sec)->this_hdr.contents != NULL) contents = elf_section_data (sec)->this_hdr.contents; @@ -760,19 +751,33 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) goto error_return; } - for (; irel < irelend; irel++) + for (irel = internal_relocs; irel < irelend; irel++) { unsigned long r_type = ELFNN_R_TYPE (irel->r_info); bfd_vma symaddr, reladdr, trampoff, toff, roff; asection *tsec; struct one_fixup *f; bfd_size_type amt; + bfd_boolean is_branch; + struct elfNN_ia64_dyn_sym_info *dyn_i; - if (r_type != R_IA64_PCREL21B - && r_type != R_IA64_PCREL21BI - && r_type != R_IA64_PCREL21M - && r_type != R_IA64_PCREL21F) - continue; + switch (r_type) + { + case R_IA64_PCREL21B: + case R_IA64_PCREL21BI: + case R_IA64_PCREL21M: + case R_IA64_PCREL21F: + is_branch = TRUE; + break; + + case R_IA64_LTOFF22X: + case R_IA64_LDXMOV: + is_branch = FALSE; + break; + + default: + continue; + } /* Get the value of the symbol referred to by the reloc. */ if (ELFNN_R_SYM (irel->r_info) < symtab_hdr->sh_info) @@ -805,12 +810,12 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); toff = isym->st_value; + dyn_i = get_dyn_sym_info (ia64_info, NULL, abfd, irel, FALSE); } else { unsigned long indx; struct elf_link_hash_entry *h; - struct elfNN_ia64_dyn_sym_info *dyn_i; indx = ELFNN_R_SYM (irel->r_info) - symtab_hdr->sh_info; h = elf_sym_hashes (abfd)[indx]; @@ -824,7 +829,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) /* For branches to dynamic symbols, we're interested instead in a branch to the PLT entry. */ - if (dyn_i && dyn_i->want_plt2) + if (is_branch && dyn_i && dyn_i->want_plt2) { /* Internal branches shouldn't be sent to the PLT. Leave this for now and we'll give an error later. */ @@ -834,6 +839,11 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) tsec = ia64_info->plt_sec; toff = dyn_i->plt2_offset; } + + /* Can't do anything else with dynamic symbols. */ + else if (elfNN_ia64_dynamic_symbol_p (h, link_info)) + continue; + else { /* We can't do anthing with undefined symbols. */ @@ -852,103 +862,152 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) + irel->r_addend); roff = irel->r_offset; - reladdr = (sec->output_section->vma - + sec->output_offset - + roff) & (bfd_vma) -4; - - /* If the branch is in range, no need to do anything. */ - if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000 - && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0) - continue; - /* If the branch and target are in the same section, you've - got one honking big section and we can't help you. You'll - get an error message later. */ - if (tsec == sec) - continue; + if (is_branch) + { + reladdr = (sec->output_section->vma + + sec->output_offset + + roff) & (bfd_vma) -4; - /* Look for an existing fixup to this address. */ - for (f = fixups; f ; f = f->next) - if (f->tsec == tsec && f->toff == toff) - break; + /* If the branch is in range, no need to do anything. */ + if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000 + && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0) + continue; - if (f == NULL) - { - /* Two alternatives: If it's a branch to a PLT entry, we can - make a copy of the FULL_PLT entry. Otherwise, we'll have - to use a `brl' insn to get where we're going. */ + /* If the branch and target are in the same section, you've + got one honking big section and we can't help you. You'll + get an error message later. */ + if (tsec == sec) + continue; - size_t size; + /* Look for an existing fixup to this address. */ + for (f = fixups; f ; f = f->next) + if (f->tsec == tsec && f->toff == toff) + break; - if (tsec == ia64_info->plt_sec) - size = sizeof (plt_full_entry); - else + if (f == NULL) { + /* Two alternatives: If it's a branch to a PLT entry, we can + make a copy of the FULL_PLT entry. Otherwise, we'll have + to use a `brl' insn to get where we're going. */ + + size_t size; + + if (tsec == ia64_info->plt_sec) + size = sizeof (plt_full_entry); + else + { #ifdef USE_BRL - size = sizeof (oor_brl); + size = sizeof (oor_brl); #else - size = sizeof (oor_ip); + size = sizeof (oor_ip); #endif - } + } - /* Resize the current section to make room for the new branch. */ - trampoff = (sec->_cooked_size + 15) & (bfd_vma) -16; - amt = trampoff + size; - contents = (bfd_byte *) bfd_realloc (contents, amt); - if (contents == NULL) - goto error_return; - sec->_cooked_size = amt; + /* Resize the current section to make room for the new branch. */ + trampoff = (sec->_cooked_size + 15) & (bfd_vma) -16; + amt = trampoff + size; + contents = (bfd_byte *) bfd_realloc (contents, amt); + if (contents == NULL) + goto error_return; + sec->_cooked_size = amt; - if (tsec == ia64_info->plt_sec) - { - memcpy (contents + trampoff, plt_full_entry, size); + if (tsec == ia64_info->plt_sec) + { + memcpy (contents + trampoff, plt_full_entry, size); - /* Hijack the old relocation for use as the PLTOFF reloc. */ - irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), - R_IA64_PLTOFF22); - irel->r_offset = trampoff; - } - else - { + /* Hijack the old relocation for use as the PLTOFF reloc. */ + irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), + R_IA64_PLTOFF22); + irel->r_offset = trampoff; + } + else + { #ifdef USE_BRL - memcpy (contents + trampoff, oor_brl, size); - irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), - R_IA64_PCREL60B); - irel->r_offset = trampoff + 2; + memcpy (contents + trampoff, oor_brl, size); + irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), + R_IA64_PCREL60B); + irel->r_offset = trampoff + 2; #else - memcpy (contents + trampoff, oor_ip, size); - irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), - R_IA64_PCREL64I); - irel->r_addend -= 16; - irel->r_offset = trampoff + 2; + memcpy (contents + trampoff, oor_ip, size); + irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), + R_IA64_PCREL64I); + irel->r_addend -= 16; + irel->r_offset = trampoff + 2; #endif + } + + /* Record the fixup so we don't do it again this section. */ + f = (struct one_fixup *) + bfd_malloc ((bfd_size_type) sizeof (*f)); + f->next = fixups; + f->tsec = tsec; + f->toff = toff; + f->trampoff = trampoff; + fixups = f; } + else + { + /* Nop out the reloc, since we're finalizing things here. */ + irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE); + } + + /* Fix up the existing branch to hit the trampoline. Hope like + hell this doesn't overflow too. */ + if (elfNN_ia64_install_value (abfd, contents + roff, + f->trampoff - (roff & (bfd_vma) -4), + r_type) != bfd_reloc_ok) + goto error_return; - /* Record the fixup so we don't do it again this section. */ - f = (struct one_fixup *) bfd_malloc ((bfd_size_type) sizeof (*f)); - f->next = fixups; - f->tsec = tsec; - f->toff = toff; - f->trampoff = trampoff; - fixups = f; + changed_contents = TRUE; + changed_relocs = TRUE; } else { - /* Nop out the reloc, since we're finalizing things here. */ - irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE); - } + /* Fetch the gp. */ + if (gp == 0) + { + bfd *obfd = sec->output_section->owner; + gp = _bfd_get_gp_value (obfd); + if (gp == 0) + { + if (!elfNN_ia64_choose_gp (obfd, link_info)) + goto error_return; + gp = _bfd_get_gp_value (obfd); + } + } - /* Fix up the existing branch to hit the trampoline. Hope like - hell this doesn't overflow too. */ - if (elfNN_ia64_install_value (abfd, contents + roff, - f->trampoff - (roff & (bfd_vma) -4), - r_type) != bfd_reloc_ok) - goto error_return; + /* If the data is out of range, do nothing. */ + if ((bfd_signed_vma) (symaddr - gp) >= 0x400000 + ||(bfd_signed_vma) (symaddr - gp) < -0x400000) + continue; - changed_contents = TRUE; - changed_relocs = TRUE; + if (r_type == R_IA64_LTOFF22X) + { + irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), + R_IA64_GPREL22); + changed_relocs = TRUE; + if (dyn_i->want_gotx) + { + dyn_i->want_gotx = 0; + changed_got |= !dyn_i->want_got; + } + } + else + { + elfNN_ia64_relax_ldxmov (abfd, contents, roff); + irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE); + changed_contents = TRUE; + changed_relocs = TRUE; + } + } } + /* ??? If we created fixups, this may push the code segment large + enough that the data segment moves, which will change the GP. + Reset the GP so that we re-calculate next round. We need to + do this at the _beginning_ of the next round; now will not do. */ + /* Clean up and go home. */ while (fixups) { @@ -989,6 +1048,21 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) elf_section_data (sec)->relocs = internal_relocs; } + if (changed_got) + { + struct elfNN_ia64_allocate_data data; + data.info = link_info; + data.ofs = 0; + + elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data); + elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data); + elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data); + ia64_info->got_sec->_raw_size = data.ofs; + ia64_info->got_sec->_cooked_size = data.ofs; + + /* ??? Resize .rela.got too. */ + } + *again = changed_contents || changed_relocs; return TRUE; @@ -1003,6 +1077,39 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) free (internal_relocs); return FALSE; } + +static void +elfNN_ia64_relax_ldxmov (abfd, contents, off) + bfd *abfd; + bfd_byte *contents; + bfd_vma off; +{ + int shift, r1, r3; + bfd_vma dword, insn; + + switch ((int)off & 0x3) + { + case 0: shift = 5; break; + case 1: shift = 14; off += 3; break; + case 2: shift = 23; off += 6; break; + case 3: + abort (); + } + + dword = bfd_get_64 (abfd, contents + off); + insn = (dword >> shift) & 0x1ffffffffffLL; + + r1 = (insn >> 6) & 127; + r3 = (insn >> 20) & 127; + if (r1 == r3) + insn = 0x8000000; /* nop */ + else + insn = (insn & 0x7f01fff) | 0x10800000000LL; /* (qp) mov r1 = r3 */ + + dword &= ~(0x1ffffffffffLL << shift); + dword |= (insn << shift); + bfd_put_64 (abfd, dword, contents + off); +} /* Return TRUE if NAME is an unwind table section name. */ @@ -2125,15 +2232,16 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) { enum { NEED_GOT = 1, - NEED_FPTR = 2, - NEED_PLTOFF = 4, - NEED_MIN_PLT = 8, - NEED_FULL_PLT = 16, - NEED_DYNREL = 32, - NEED_LTOFF_FPTR = 64, - NEED_TPREL = 128, - NEED_DTPMOD = 256, - NEED_DTPREL = 512 + NEED_GOTX = 2, + NEED_FPTR = 4, + NEED_PLTOFF = 8, + NEED_MIN_PLT = 16, + NEED_FULL_PLT = 32, + NEED_DYNREL = 64, + NEED_LTOFF_FPTR = 128, + NEED_TPREL = 256, + NEED_DTPMOD = 512, + NEED_DTPREL = 1024 }; struct elf_link_hash_entry *h = NULL; @@ -2230,11 +2338,14 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) break; case R_IA64_LTOFF22: - case R_IA64_LTOFF22X: case R_IA64_LTOFF64I: need_entry = NEED_GOT; break; + case R_IA64_LTOFF22X: + need_entry = NEED_GOTX; + break; + case R_IA64_PLTOFF22: case R_IA64_PLTOFF64I: case R_IA64_PLTOFF64MSB: @@ -2316,7 +2427,8 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) dyn_i->h = h; /* Create what's needed. */ - if (need_entry & (NEED_GOT | NEED_TPREL | NEED_DTPMOD | NEED_DTPREL)) + if (need_entry & (NEED_GOT | NEED_GOTX | NEED_TPREL + | NEED_DTPMOD | NEED_DTPREL)) { if (!got) { @@ -2326,6 +2438,8 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) } if (need_entry & NEED_GOT) dyn_i->want_got = 1; + if (need_entry & NEED_GOTX) + dyn_i->want_gotx = 1; if (need_entry & NEED_TPREL) dyn_i->want_tprel = 1; if (need_entry & NEED_DTPMOD) @@ -2385,12 +2499,6 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) return TRUE; } -struct elfNN_ia64_allocate_data -{ - struct bfd_link_info *info; - bfd_size_type ofs; -}; - /* For cleanliness, and potentially faster dynamic loading, allocate external GOT entries first. */ @@ -2401,7 +2509,7 @@ allocate_global_data_got (dyn_i, data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; - if (dyn_i->want_got + if ((dyn_i->want_got || dyn_i->want_gotx) && ! dyn_i->want_fptr && (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info) || (elfNN_ia64_aix_vec (x->info->hash->creator) @@ -2473,7 +2581,7 @@ allocate_local_got (dyn_i, data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; - if (dyn_i->want_got + if ((dyn_i->want_got || dyn_i->want_gotx) && ! (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info) || elfNN_ia64_aix_vec (x->info->hash->creator))) { @@ -2699,7 +2807,7 @@ allocate_dynrel_entries (dyn_i, data) /* Take care of the GOT and PLT relocations. */ - if (((dynamic_symbol || shared) && dyn_i->want_got) + if (((dynamic_symbol || shared) && (dyn_i->want_got || dyn_i->want_gotx)) || (dyn_i->want_ltoff_fptr && dyn_i->h && dyn_i->h->dynindx != -1)) ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela); if ((dynamic_symbol || shared) && dyn_i->want_tprel) @@ -3516,125 +3624,148 @@ elfNN_ia64_unwind_entry_compare (a, b) return (av < bv ? -1 : av > bv ? 1 : 0); } +/* Make sure we've got ourselves a nice fat __gp value. */ static bfd_boolean -elfNN_ia64_final_link (abfd, info) +elfNN_ia64_choose_gp (abfd, info) bfd *abfd; struct bfd_link_info *info; { + bfd_vma min_vma = (bfd_vma) -1, max_vma = 0; + bfd_vma min_short_vma = min_vma, max_short_vma = 0; + struct elf_link_hash_entry *gp; + bfd_vma gp_val; + asection *os; struct elfNN_ia64_link_hash_table *ia64_info; - asection *unwind_output_sec; ia64_info = elfNN_ia64_hash_table (info); - /* Make sure we've got ourselves a nice fat __gp value. */ - if (!info->relocateable) + /* Find the min and max vma of all sections marked short. Also collect + min and max vma of any type, for use in selecting a nice gp. */ + for (os = abfd->sections; os ; os = os->next) { - bfd_vma min_vma = (bfd_vma) -1, max_vma = 0; - bfd_vma min_short_vma = min_vma, max_short_vma = 0; - struct elf_link_hash_entry *gp; - bfd_vma gp_val; - asection *os; + bfd_vma lo, hi; + + if ((os->flags & SEC_ALLOC) == 0) + continue; + + lo = os->vma; + hi = os->vma + os->_raw_size; + if (hi < lo) + hi = (bfd_vma) -1; - /* Find the min and max vma of all sections marked short. Also - collect min and max vma of any type, for use in selecting a - nice gp. */ - for (os = abfd->sections; os ; os = os->next) + if (min_vma > lo) + min_vma = lo; + if (max_vma < hi) + max_vma = hi; + if (os->flags & SEC_SMALL_DATA) { - bfd_vma lo, hi; + if (min_short_vma > lo) + min_short_vma = lo; + if (max_short_vma < hi) + max_short_vma = hi; + } + } - if ((os->flags & SEC_ALLOC) == 0) - continue; + /* See if the user wants to force a value. */ + gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, + FALSE, FALSE); - lo = os->vma; - hi = os->vma + os->_raw_size; - if (hi < lo) - hi = (bfd_vma) -1; + if (gp + && (gp->root.type == bfd_link_hash_defined + || gp->root.type == bfd_link_hash_defweak)) + { + asection *gp_sec = gp->root.u.def.section; + gp_val = (gp->root.u.def.value + + gp_sec->output_section->vma + + gp_sec->output_offset); + } + else + { + /* Pick a sensible value. */ - if (min_vma > lo) - min_vma = lo; - if (max_vma < hi) - max_vma = hi; - if (os->flags & SEC_SMALL_DATA) - { - if (min_short_vma > lo) - min_short_vma = lo; - if (max_short_vma < hi) - max_short_vma = hi; - } + asection *got_sec = ia64_info->got_sec; + + /* Start with just the address of the .got. */ + if (got_sec) + gp_val = got_sec->output_section->vma; + else if (max_short_vma != 0) + gp_val = min_short_vma; + else + gp_val = min_vma; + + /* If it is possible to address the entire image, but we + don't with the choice above, adjust. */ + if (max_vma - min_vma < 0x400000 + && max_vma - gp_val <= 0x200000 + && gp_val - min_vma > 0x200000) + gp_val = min_vma + 0x200000; + else if (max_short_vma != 0) + { + /* If we don't cover all the short data, adjust. */ + if (max_short_vma - gp_val >= 0x200000) + gp_val = min_short_vma + 0x200000; + + /* If we're addressing stuff past the end, adjust back. */ + if (gp_val > max_vma) + gp_val = max_vma - 0x200000 + 8; } + } - /* See if the user wants to force a value. */ - gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, - FALSE, FALSE); + /* Validate whether all SHF_IA_64_SHORT sections are within + range of the chosen GP. */ - if (gp - && (gp->root.type == bfd_link_hash_defined - || gp->root.type == bfd_link_hash_defweak)) + if (max_short_vma != 0) + { + if (max_short_vma - min_short_vma >= 0x400000) { - asection *gp_sec = gp->root.u.def.section; - gp_val = (gp->root.u.def.value - + gp_sec->output_section->vma - + gp_sec->output_offset); + (*_bfd_error_handler) + (_("%s: short data segment overflowed (0x%lx >= 0x400000)"), + bfd_get_filename (abfd), + (unsigned long) (max_short_vma - min_short_vma)); + return FALSE; } - else + else if ((gp_val > min_short_vma + && gp_val - min_short_vma > 0x200000) + || (gp_val < max_short_vma + && max_short_vma - gp_val >= 0x200000)) { - /* Pick a sensible value. */ + (*_bfd_error_handler) + (_("%s: __gp does not cover short data segment"), + bfd_get_filename (abfd)); + return FALSE; + } + } - asection *got_sec = ia64_info->got_sec; + _bfd_set_gp_value (abfd, gp_val); - /* Start with just the address of the .got. */ - if (got_sec) - gp_val = got_sec->output_section->vma; - else if (max_short_vma != 0) - gp_val = min_short_vma; - else - gp_val = min_vma; - - /* If it is possible to address the entire image, but we - don't with the choice above, adjust. */ - if (max_vma - min_vma < 0x400000 - && max_vma - gp_val <= 0x200000 - && gp_val - min_vma > 0x200000) - gp_val = min_vma + 0x200000; - else if (max_short_vma != 0) - { - /* If we don't cover all the short data, adjust. */ - if (max_short_vma - gp_val >= 0x200000) - gp_val = min_short_vma + 0x200000; + return TRUE; +} - /* If we're addressing stuff past the end, adjust back. */ - if (gp_val > max_vma) - gp_val = max_vma - 0x200000 + 8; - } - } +static bfd_boolean +elfNN_ia64_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + struct elfNN_ia64_link_hash_table *ia64_info; + asection *unwind_output_sec; - /* Validate whether all SHF_IA_64_SHORT sections are within - range of the chosen GP. */ + ia64_info = elfNN_ia64_hash_table (info); + + /* Make sure we've got ourselves a nice fat __gp value. */ + if (!info->relocateable) + { + bfd_vma gp_val = _bfd_get_gp_value (abfd); + struct elf_link_hash_entry *gp; - if (max_short_vma != 0) + if (gp_val == 0) { - if (max_short_vma - min_short_vma >= 0x400000) - { - (*_bfd_error_handler) - (_("%s: short data segment overflowed (0x%lx >= 0x400000)"), - bfd_get_filename (abfd), - (unsigned long) (max_short_vma - min_short_vma)); - return FALSE; - } - else if ((gp_val > min_short_vma - && gp_val - min_short_vma > 0x200000) - || (gp_val < max_short_vma - && max_short_vma - gp_val >= 0x200000)) - { - (*_bfd_error_handler) - (_("%s: __gp does not cover short data segment"), - bfd_get_filename (abfd)); - return FALSE; - } + if (! elfNN_ia64_choose_gp (abfd, info)) + return FALSE; + gp_val = _bfd_get_gp_value (abfd); } - _bfd_set_gp_value (abfd, gp_val); - + gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, + FALSE, FALSE); if (gp) { gp->root.type = bfd_link_hash_defined; -- cgit v1.1