summaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog12
-rw-r--r--bfd/elf32-mips.c84
-rw-r--r--bfd/elflink.h102
3 files changed, 138 insertions, 60 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 7bd50813abf..d2789851cb0 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,15 @@
+Sat Jul 17 02:28:28 1999 Mark P. Mitchell <mark@codesourcery.com>
+
+ * elflink.h (elf_link_adjust_relocs): New function.
+ (elf_bfd_final_link): Use it.
+ (elf_link_input_bfd): Deal with the fact that there can be
+ two relocation sections for a single section.
+ (elf_reloc_link_order): Likewise.
+
+ * elf32-mips.c (_bfd_mips_elf_final_link): Don't set GP for
+ a relocateable object.
+ (_bfd_mips_elf_relocate_section): Handle relocateable links.
+
1999-07-16 Jakub Jelinek <jj@ultra.linux.cz>
* elf64-sparc.c (sparc64_elf_info_to_howto): Use ELF64_R_TYPE_ID.
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index a9d3acf6e70..8fecccf062d 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -4388,20 +4388,6 @@ _bfd_mips_elf_final_link (abfd, info)
elf_gp (abfd) = (h->u.def.value
+ h->u.def.section->output_section->vma
+ h->u.def.section->output_offset);
- else if (info->relocateable)
- {
- bfd_vma lo;
-
- /* Find the GP-relative section with the lowest offset. */
- lo = (bfd_vma) -1;
- for (o = abfd->sections; o != (asection *) NULL; o = o->next)
- if (o->vma < lo
- && (elf_section_data (o)->this_hdr.sh_flags & SHF_MIPS_GPREL))
- lo = o->vma;
-
- /* And calculate GP relative to that. */
- elf_gp (abfd) = lo + ELF_MIPS_GP_OFFSET (abfd);
- }
else
{
/* If the relocate_section function needs to do a reloc
@@ -6429,7 +6415,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
Elf_Internal_Sym *local_syms;
asection **local_sections;
{
- const Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *rel;
const Elf_Internal_Rela *relend;
bfd_vma addend;
bfd_vma last_hi16_addend;
@@ -6445,10 +6431,13 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
bfd_vma value;
reloc_howto_type *howto;
boolean require_jalx;
+ /* True if the relocation is a RELA relocation, rather than a
+ REL relocation. */
+ boolean rela_relocation_p = true;
+ int r_type = ELF32_R_TYPE (rel->r_info);
/* Find the relocation howto for this relocation. */
- if (ELF32_R_TYPE (rel->r_info) == R_MIPS_64
- && !ABI_64_P (output_bfd))
+ if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
/* Some 32-bit code uses R_MIPS_64. In particular, people use
64-bit code, but make sure all their addresses are in the
lowermost or uppermost 32-bit section of the 64-bit address
@@ -6457,7 +6446,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
stored value is sign-extended to 64 bits. */
howto = elf_mips_howto_table + R_MIPS_32;
else
- howto = elf_mips_howto_table + ELF32_R_TYPE (rel->r_info);
+ howto = elf_mips_howto_table + r_type;
if (!use_saved_addend_p)
{
@@ -6476,8 +6465,10 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
rel_hdr = elf_section_data (input_section)->rel_hdr2;
if (rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (input_bfd))
{
- int r_type = ELF32_R_TYPE (rel->r_info);
+ /* Note that this is a REL relocation. */
+ rela_relocation_p = false;
+ /* Get the addend, which is stored in the input file. */
addend = mips_elf_obtain_contents (howto,
rel,
input_bfd,
@@ -6533,13 +6524,63 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
addend = rel->r_addend;
}
+ if (info->relocateable)
+ {
+ Elf_Internal_Sym *sym;
+ unsigned long r_symndx;
+
+ /* Since we're just relocating, all we need to do is copy
+ the relocations back out to the object file, unless they're
+ against a section symbol, in which case we need to adjust
+ by the section offset. */
+
+ if (!mips_elf_local_relocation_p (input_bfd, rel, local_sections))
+ /* A non-local relocation is never against a section. */
+ continue;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ sym = local_syms + r_symndx;
+ if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+ continue;
+
+ /* Adjust the addend appropriately. */
+ addend += local_sections[r_symndx]->output_offset;
+
+ /* If the relocation is for a R_MIPS_HI16 or R_MIPS_GOT16,
+ then we only want to write out the high-order 16 bits.
+ The subsequent R_MIPS_LO16 will handle the low-order bits. */
+ if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16)
+ addend >>= 16;
+
+ if (rela_relocation_p)
+ /* If this is a RELA relocation, just update the addend.
+ We have to cast away constness for REL. */
+ rel->r_addend = addend;
+ else
+ {
+ /* Otherwise, we have to write the value back out. Note
+ that we use the source mask, rather than the
+ destination mask because the place to which we are
+ writing will be source of the addend in the final
+ link. */
+ addend &= howto->src_mask;
+ if (!mips_elf_perform_relocation (info, howto, rel, addend,
+ input_bfd, input_section,
+ contents, false))
+ return false;
+ }
+
+ /* Go on to the next relocation. */
+ continue;
+ }
+
/* In the N32 and 64-bit ABIs there may be multiple consecutive
relocations for the same offset. In that case we are
supposed to treat the output of each relocation as the addend
for the next. */
if (rel + 1 < relend
&& rel->r_offset == rel[1].r_offset
- && ELF32_R_TYPE (rel[1].r_info) != R_MIPS_NONE)
+ && r_type != R_MIPS_NONE)
use_saved_addend_p = true;
else
use_saved_addend_p = false;
@@ -6602,8 +6643,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
continue;
}
- if (ELF32_R_TYPE (rel->r_info) == R_MIPS_64
- && !ABI_64_P (output_bfd))
+ if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
/* See the comment above about using R_MIPS_64 in the 32-bit
ABI. Until now, we've been using the HOWTO for R_MIPS_32;
that calculated the right value. Now, however, we
diff --git a/bfd/elflink.h b/bfd/elflink.h
index 9c00d1df80f..7591f6472c5 100644
--- a/bfd/elflink.h
+++ b/bfd/elflink.h
@@ -56,6 +56,9 @@ static void elf_link_output_relocs
PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *));
static boolean elf_link_size_reloc_section
PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
+static void elf_link_adjust_relocs
+ PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int,
+ struct elf_link_hash_entry **));
/* Given an ELF BFD, add symbols to the global hash table as
appropriate. */
@@ -3782,6 +3785,55 @@ elf_link_size_reloc_section (abfd, rel_hdr, o)
return true;
}
+/* When performing a relocateable link, the input relocations are
+ preserved. But, if they reference global symbols, the indices
+ referenced must be updated. Update all the relocations in
+ REL_HDR (there are COUNT of them), using the data in REL_HASH. */
+
+static void
+elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
+ bfd *abfd;
+ Elf_Internal_Shdr *rel_hdr;
+ unsigned int count;
+ struct elf_link_hash_entry **rel_hash;
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++, rel_hash++)
+ {
+ if (*rel_hash == NULL)
+ continue;
+
+ BFD_ASSERT ((*rel_hash)->indx >= 0);
+
+ if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+ {
+ Elf_External_Rel *erel;
+ Elf_Internal_Rel irel;
+
+ erel = (Elf_External_Rel *) rel_hdr->contents + i;
+ elf_swap_reloc_in (abfd, erel, &irel);
+ irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ ELF_R_TYPE (irel.r_info));
+ elf_swap_reloc_out (abfd, &irel, erel);
+ }
+ else
+ {
+ Elf_External_Rela *erela;
+ Elf_Internal_Rela irela;
+
+ BFD_ASSERT (rel_hdr->sh_entsize
+ == sizeof (Elf_External_Rela));
+
+ erela = (Elf_External_Rela *) rel_hdr->contents + i;
+ elf_swap_reloca_in (abfd, erela, &irela);
+ irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ ELF_R_TYPE (irela.r_info));
+ elf_swap_reloca_out (abfd, &irela, erela);
+ }
+ }
+}
+
/* Do the final step of an ELF link. */
boolean
@@ -4268,42 +4320,14 @@ elf_bfd_final_link (abfd, info)
if ((o->flags & SEC_RELOC) == 0)
continue;
- rel_hash = elf_section_data (o)->rel_hashes;
- rel_hdr = &elf_section_data (o)->rel_hdr;
- BFD_ASSERT (elf_section_data (o)->rel_count == o->reloc_count);
- for (i = 0; i < o->reloc_count; i++, rel_hash++)
- {
- if (*rel_hash == NULL)
- continue;
-
- BFD_ASSERT ((*rel_hash)->indx >= 0);
-
- if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
- {
- Elf_External_Rel *erel;
- Elf_Internal_Rel irel;
-
- erel = (Elf_External_Rel *) rel_hdr->contents + i;
- elf_swap_reloc_in (abfd, erel, &irel);
- irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
- ELF_R_TYPE (irel.r_info));
- elf_swap_reloc_out (abfd, &irel, erel);
- }
- else
- {
- Elf_External_Rela *erela;
- Elf_Internal_Rela irela;
-
- BFD_ASSERT (rel_hdr->sh_entsize
- == sizeof (Elf_External_Rela));
-
- erela = (Elf_External_Rela *) rel_hdr->contents + i;
- elf_swap_reloca_in (abfd, erela, &irela);
- irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
- ELF_R_TYPE (irela.r_info));
- elf_swap_reloca_out (abfd, &irela, erela);
- }
- }
+ elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr,
+ elf_section_data (o)->rel_count,
+ elf_section_data (o)->rel_hashes);
+ if (elf_section_data (o)->rel_hdr2 != NULL)
+ elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
+ elf_section_data (o)->rel_count2,
+ (elf_section_data (o)->rel_hashes
+ + elf_section_data (o)->rel_count));
/* Set the reloc_count field to 0 to prevent write_relocs from
trying to swap the relocs out itself. */
@@ -5224,7 +5248,8 @@ elf_link_input_bfd (finfo, input_bfd)
irelaend =
irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
rel_hash = (elf_section_data (o->output_section)->rel_hashes
- + elf_section_data (o->output_section)->rel_count);
+ + elf_section_data (o->output_section)->rel_count
+ + elf_section_data (o->output_section)->rel_count2);
for (; irela < irelaend; irela++, rel_hash++)
{
unsigned long r_symndx;
@@ -5414,7 +5439,8 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
/* Figure out the symbol index. */
rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
- + elf_section_data (output_section)->rel_count);
+ + elf_section_data (output_section)->rel_count
+ + elf_section_data (output_section)->rel_count2);
if (link_order->type == bfd_section_reloc_link_order)
{
indx = link_order->u.reloc.p->u.section->target_index;