* 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> 2003-03-25 Stan Cox <scox@redhat.com>
Nick Clifton <nickc@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_canonicalize_reloc mips_elf64_canonicalize_reloc
#define bfd_elf64_get_dynamic_reloc_upper_bound mips_elf64_get_dynamic_reloc_upper_bound #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_canonicalize_dynamic_reloc mips_elf64_canonicalize_dynamic_reloc
#define bfd_elf64_bfd_relax_section _bfd_mips_relax_section
/* MIPS ELF64 archive functions. */ /* MIPS ELF64 archive functions. */
#define bfd_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_set_private_flags _bfd_mips_elf_set_private_flags
#define bfd_elf32_bfd_print_private_bfd_data \ #define bfd_elf32_bfd_print_private_bfd_data \
_bfd_mips_elf_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. */ /* 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; 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 /* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to 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 **)); PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
extern unsigned long _bfd_elf_mips_mach extern unsigned long _bfd_elf_mips_mach
PARAMS ((flagword)); PARAMS ((flagword));
extern bfd_boolean _bfd_mips_relax_section (bfd *, asection *,
struct bfd_link_info *,
bfd_boolean *);