* 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.
This commit is contained in:
Mark Mitchell 1999-07-18 06:31:29 +00:00
parent c2c594b87d
commit 31367b81b7
3 changed files with 138 additions and 60 deletions

View file

@ -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.

View file

@ -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

View file

@ -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;