* elfxx-mips.c (_bfd_mips_relax_section): New function.

* elfxx-mips.h (_bfd_mips_relax_section): Declare.
* elfn32-mips.c, elf64-mips.c: Use it.
This commit is contained in:
Alexandre Oliva 2003-03-26 01:04:22 +00:00
parent 3185fd28d1
commit d06471104a
5 changed files with 190 additions and 0 deletions

View File

@ -1,3 +1,9 @@
2003-03-25 Alexandre Oliva <aoliva@redhat.com>
* elfxx-mips.c (_bfd_mips_relax_section): New function.
* elfxx-mips.h (_bfd_mips_relax_section): Declare.
* elfn32-mips.c, elf64-mips.c: Use it.
2003-03-25 Stan Cox <scox@redhat.com>
Nick Clifton <nickc@redhat.com>

View File

@ -2887,6 +2887,7 @@ const struct elf_size_info mips_elf64_size_info =
#define bfd_elf64_canonicalize_reloc mips_elf64_canonicalize_reloc
#define bfd_elf64_get_dynamic_reloc_upper_bound mips_elf64_get_dynamic_reloc_upper_bound
#define bfd_elf64_canonicalize_dynamic_reloc mips_elf64_canonicalize_dynamic_reloc
#define bfd_elf64_bfd_relax_section _bfd_mips_relax_section
/* MIPS ELF64 archive functions. */
#define bfd_elf64_archive_functions

View File

@ -2211,6 +2211,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
#define bfd_elf32_bfd_set_private_flags _bfd_mips_elf_set_private_flags
#define bfd_elf32_bfd_print_private_bfd_data \
_bfd_mips_elf_print_private_bfd_data
#define bfd_elf32_bfd_relax_section _bfd_mips_relax_section
/* Support for SGI-ish mips targets using n32 ABI. */

View File

@ -5451,6 +5451,185 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
return TRUE;
}
bfd_boolean
_bfd_mips_relax_section (abfd, sec, link_info, again)
bfd *abfd;
asection *sec;
struct bfd_link_info *link_info;
bfd_boolean *again;
{
Elf_Internal_Rela *internal_relocs;
Elf_Internal_Rela *irel, *irelend;
Elf_Internal_Shdr *symtab_hdr;
bfd_byte *contents = NULL;
bfd_byte *free_contents = NULL;
size_t extsymoff;
bfd_boolean changed_contents = FALSE;
bfd_vma sec_start = sec->output_section->vma + sec->output_offset;
Elf_Internal_Sym *isymbuf = NULL;
/* We are not currently changing any sizes, so only one pass. */
*again = FALSE;
if (link_info->relocateable)
return TRUE;
internal_relocs = (MNAME(abfd,_bfd_elf,link_read_relocs)
(abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
return TRUE;
irelend = internal_relocs + sec->reloc_count
* get_elf_backend_data (abfd)->s->int_rels_per_ext_rel;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
for (irel = internal_relocs; irel < irelend; irel++)
{
bfd_vma symval;
bfd_signed_vma sym_offset;
unsigned int r_type;
unsigned long r_symndx;
asection *sym_sec;
unsigned long instruction;
/* Turn jalr into bgezal, and jr into beq, if they're marked
with a JALR relocation, that indicate where they jump to.
This saves some pipeline bubbles. */
r_type = ELF_R_TYPE (abfd, irel->r_info);
if (r_type != R_MIPS_JALR)
continue;
r_symndx = ELF_R_SYM (abfd, irel->r_info);
/* Compute the address of the jump target. */
if (r_symndx >= extsymoff)
{
struct mips_elf_link_hash_entry *h
= ((struct mips_elf_link_hash_entry *)
elf_sym_hashes (abfd) [r_symndx - extsymoff]);
while (h->root.root.type == bfd_link_hash_indirect
|| h->root.root.type == bfd_link_hash_warning)
h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
/* If a symbol is undefined, or if it may be overridden,
skip it. */
if (! ((h->root.root.type == bfd_link_hash_defined
|| h->root.root.type == bfd_link_hash_defweak)
&& h->root.root.u.def.section)
|| (link_info->shared && ! link_info->symbolic
&& ! (h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)))
continue;
sym_sec = h->root.root.u.def.section;
if (sym_sec->output_section)
symval = (h->root.root.u.def.value
+ sym_sec->output_section->vma
+ sym_sec->output_offset);
else
symval = h->root.root.u.def.value;
}
else
{
Elf_Internal_Sym *isym;
/* Read this BFD's symbols if we haven't done so already. */
if (isymbuf == NULL && symtab_hdr->sh_info != 0)
{
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL)
isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
symtab_hdr->sh_info, 0,
NULL, NULL, NULL);
if (isymbuf == NULL)
goto relax_return;
}
isym = isymbuf + r_symndx;
if (isym->st_shndx == SHN_UNDEF)
continue;
else if (isym->st_shndx == SHN_ABS)
sym_sec = bfd_abs_section_ptr;
else if (isym->st_shndx == SHN_COMMON)
sym_sec = bfd_com_section_ptr;
else
sym_sec
= bfd_section_from_elf_index (abfd, isym->st_shndx);
symval = isym->st_value
+ sym_sec->output_section->vma
+ sym_sec->output_offset;
}
/* Compute branch offset, from delay slot of the jump to the
branch target. */
sym_offset = (symval + irel->r_addend)
- (sec_start + irel->r_offset + 4);
/* Branch offset must be properly aligned. */
if ((sym_offset & 3) != 0)
continue;
sym_offset >>= 2;
/* Check that it's in range. */
if (sym_offset < -0x8000 || sym_offset >= 0x8000)
continue;
/* Get the section contents if we haven't done so already. */
if (contents == NULL)
{
/* Get cached copy if it exists. */
if (elf_section_data (sec)->this_hdr.contents != NULL)
contents = elf_section_data (sec)->this_hdr.contents;
else
{
contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
if (contents == NULL)
goto relax_return;
free_contents = contents;
if (! bfd_get_section_contents (abfd, sec, contents,
(file_ptr) 0, sec->_raw_size))
goto relax_return;
}
}
instruction = bfd_get_32 (abfd, contents + irel->r_offset);
/* If it was jalr <reg>, turn it into bgezal $zero, <target>. */
if ((instruction & 0xfc1fffff) == 0x0000f809)
instruction = 0x04110000;
/* If it was jr <reg>, turn it into b <target>. */
else if ((instruction & 0xfc1fffff) == 0x00000008)
instruction = 0x10000000;
else
continue;
instruction |= (sym_offset & 0xffff);
bfd_put_32 (abfd, instruction, contents + irel->r_offset);
changed_contents = TRUE;
}
if (contents != NULL
&& elf_section_data (sec)->this_hdr.contents != contents)
{
if (!changed_contents && !link_info->keep_memory)
free (contents);
else
{
/* Cache the section contents for elf_link_input_bfd. */
elf_section_data (sec)->this_hdr.contents = contents;
}
}
return TRUE;
relax_return:
if (free_contents != NULL)
free (free_contents);
return FALSE;
}
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to

View File

@ -108,3 +108,6 @@ extern bfd_reloc_status_type _bfd_mips_elf32_gprel16_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
extern unsigned long _bfd_elf_mips_mach
PARAMS ((flagword));
extern bfd_boolean _bfd_mips_relax_section (bfd *, asection *,
struct bfd_link_info *,
bfd_boolean *);