aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-mips.c
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>1998-06-30 10:02:22 +0000
committerRichard Henderson <rth@redhat.com>1998-06-30 10:02:22 +0000
commit303b4cc64fa823bde77776b05503b39dc513e644 (patch)
treebba8b7aa0ced2c0a7a22ddee4cc5b89832d72ebb /bfd/elf32-mips.c
parentd40d5880c209617e3e4c951ed70b083c76b4cc37 (diff)
downloadgdb-303b4cc64fa823bde77776b05503b39dc513e644.zip
gdb-303b4cc64fa823bde77776b05503b39dc513e644.tar.gz
gdb-303b4cc64fa823bde77776b05503b39dc513e644.tar.bz2
ELF Section-level Garbage Collection.
Diffstat (limited to 'bfd/elf32-mips.c')
-rw-r--r--bfd/elf32-mips.c263
1 files changed, 218 insertions, 45 deletions
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index 854fa27..60a0275 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -317,12 +317,15 @@ enum reloc_type
R_MIPS_max,
/* These relocs are used for the mips16. */
R_MIPS16_26 = 100,
- R_MIPS16_GPREL = 101
+ R_MIPS16_GPREL = 101,
/* start-sanitize-sky */
/* These relocs are for the dvp. */
- , R_MIPS_DVP_11_PCREL = 120,
- R_MIPS_DVP_27_S4 = 121
+ R_MIPS_DVP_11_PCREL = 120,
+ R_MIPS_DVP_27_S4 = 121,
/* end-sanitize-sky */
+ /* These are GNU extensions to enable C++ vtable garbage collection. */
+ R_MIPS_GNU_VTINHERIT = 253,
+ R_MIPS_GNU_VTENTRY = 254
};
static reloc_howto_type elf_mips_howto_table[] =
@@ -814,6 +817,38 @@ static reloc_howto_type elf_mips_dvp_27_s4_howto =
false); /* pcrel_offset */
/* end-sanitize-sky */
+/* GNU extension to record C++ vtable hierarchy */
+static reloc_howto_type elf_mips_gnu_vtinherit_howto =
+ HOWTO (R_MIPS_GNU_VTINHERIT, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ NULL, /* special_function */
+ "R_MIPS_GNU_VTINHERIT", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false); /* pcrel_offset */
+
+/* GNU extension to record C++ vtable member usage */
+static reloc_howto_type elf_mips_gnu_vtentry_howto =
+ HOWTO (R_MIPS_GNU_VTENTRY, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ NULL, /* special_function */
+ "R_MIPS_GNU_VTENTRY", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false); /* pcrel_offset */
+
/* Do a R_MIPS_HI16 relocation. This has to be done in combination
with a R_MIPS_LO16 reloc, because there is a carry from the LO16 to
the HI16. Here we just save the information we need; we do the
@@ -1662,30 +1697,32 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val];
}
- /* We need to handle BFD_RELOC_CTOR specially.
-
- Select the right relocation (R_MIPS_32 or R_MIPS_64) based on the
- size of addresses on this architecture. */
- if (code == BFD_RELOC_CTOR)
+ switch (code)
{
+ case BFD_RELOC_CTOR:
+ /* We need to handle BFD_RELOC_CTOR specially.
+ Select the right relocation (R_MIPS_32 or R_MIPS_64) based on the
+ size of addresses on this architecture. */
if (bfd_arch_bits_per_address (abfd) == 32)
return &elf_mips_howto_table[(int) R_MIPS_32];
else
return &elf_mips_ctor64_howto;
- }
- /* Special handling for the MIPS16 relocs, since they are made up
- reloc types with a large value. */
- if (code == BFD_RELOC_MIPS16_JMP)
- return &elf_mips16_jump_howto;
- else if (code == BFD_RELOC_MIPS16_GPREL)
- return &elf_mips16_gprel_howto;
+ case BFD_RELOC_MIPS16_JMP:
+ return &elf_mips16_jump_howto;
+ case BFD_RELOC_MIPS16_GPREL:
+ return &elf_mips16_gprel_howto;
/* start-sanitize-sky */
- else if (code == BFD_RELOC_MIPS_DVP_11_PCREL)
- return &elf_mips_dvp_11_pcrel_howto;
- else if (code == BFD_RELOC_MIPS_DVP_27_S4)
- return &elf_mips_dvp_27_s4_howto;
+ case BFD_RELOC_MIPS_DVP_11_PCREL:
+ return &elf_mips_dvp_11_pcrel_howto;
+ case BFD_RELOC_MIPS_DVP_27_S4:
+ return &elf_mips_dvp_27_s4_howto;
/* end-sanitize-sky */
+ case BFD_RELOC_VTABLE_INHERIT:
+ return &elf_mips_gnu_vtinherit_howto;
+ case BFD_RELOC_VTABLE_ENTRY:
+ return &elf_mips_gnu_vtentry_howto;
+ }
return NULL;
}
@@ -1701,20 +1738,33 @@ mips_info_to_howto_rel (abfd, cache_ptr, dst)
unsigned int r_type;
r_type = ELF32_R_TYPE (dst->r_info);
- if (r_type == R_MIPS16_26)
- cache_ptr->howto = &elf_mips16_jump_howto;
- else if (r_type == R_MIPS16_GPREL)
- cache_ptr->howto = &elf_mips16_gprel_howto;
+ switch (r_type)
+ {
+ case R_MIPS16_26:
+ cache_ptr->howto = &elf_mips16_jump_howto;
+ break;
+ case R_MIPS16_GPREL:
+ cache_ptr->howto = &elf_mips16_gprel_howto;
+ break;
/* start-sanitize-sky */
- else if (r_type == R_MIPS_DVP_11_PCREL)
- cache_ptr->howto = &elf_mips_dvp_11_pcrel_howto;
- else if (r_type == R_MIPS_DVP_27_S4)
- cache_ptr->howto = &elf_mips_dvp_27_s4_howto;
+ case R_MIPS_DVP_11_PCREL:
+ cache_ptr->howto = &elf_mips_dvp_11_pcrel_howto;
+ break;
+ case R_MIPS_DVP_27_S4:
+ cache_ptr->howto = &elf_mips_dvp_27_s4_howto;
+ break;
/* end-sanitize-sky */
- else
- {
+ case R_MIPS_GNU_VTINHERIT:
+ cache_ptr->howto = &elf_mips_gnu_vtinherit_howto;
+ break;
+ case R_MIPS_GNU_VTENTRY:
+ cache_ptr->howto = &elf_mips_gnu_vtentry_howto;
+ break;
+
+ default:
BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
cache_ptr->howto = &elf_mips_howto_table[r_type];
+ break;
}
/* The addend for a GPREL16 or LITERAL relocation comes from the GP
@@ -2558,7 +2608,7 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec)
else if (strcmp (name, SHNAME_DVP_OVERLAY_TABLE) == 0)
{
hdr->sh_type = SHT_DVP_OVERLAY_TABLE;
- hdr->sh_entsize = sizeof (Elf64_Dvp_External_Overlay);
+ hdr->sh_entsize = sizeof (Elf32_Dvp_External_Overlay);
/* The sh_link field is set in final_write_processing. */
}
else if (strcmp (name, SHNAME_DVP_OVERLAY_STRTAB) == 0)
@@ -3792,7 +3842,7 @@ mips_elf_output_extsym (h, data)
{
output_section = sec->output_section;
if (output_section != NULL)
- h->esym.asym.value = (h->root.plt_offset
+ h->esym.asym.value = (h->root.plt.offset
+ sec->output_offset
+ output_section->vma);
else
@@ -4815,6 +4865,9 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
bfd_reloc_status_type r;
r_type = ELF32_R_TYPE (rel->r_info);
+ if (r_type == R_MIPS_GNU_VTINHERIT
+ || r_type == R_MIPS_GNU_VTENTRY)
+ continue;
if ((r_type < 0 || r_type >= (int) R_MIPS_max)
/* start-sanitize-sky */
&& r_type != R_MIPS_DVP_11_PCREL
@@ -5239,7 +5292,7 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
/* This symbol must be registered as a global symbol
having the corresponding got entry. */
- BFD_ASSERT (h->got_offset != (bfd_vma) -1);
+ BFD_ASSERT (h->got.offset != (bfd_vma) -1);
offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4;
BFD_ASSERT (g->local_gotno <= offset
@@ -5259,7 +5312,7 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
/* This must be a global symbol with a got entry. The
next reloc must be the corresponding LO16 reloc. */
- BFD_ASSERT (h != NULL && h->got_offset != (bfd_vma) -1);
+ BFD_ASSERT (h != NULL && h->got.offset != (bfd_vma) -1);
BFD_ASSERT ((rel + 1) < relend);
BFD_ASSERT ((int) ELF32_R_TYPE ((rel + 1)->r_info)
== (r_type == R_MIPS_CALL_HI16
@@ -6210,7 +6263,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
return false;
}
- if (h->got_offset != (bfd_vma) -1)
+ if (h->got.offset != (bfd_vma) -1)
{
/* We have already allocated space in the .got. */
break;
@@ -6222,7 +6275,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
g->global_gotsym = h->dynindx;
/* Make this symbol to have the corresponding got entry. */
- h->got_offset = 0;
+ h->got.offset = 0;
/* We need a stub, not a plt entry for the undefined
function. But we record it as if it needs plt. See
@@ -6246,7 +6299,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
return false;
}
- if (h->got_offset != (bfd_vma) -1)
+ if (h->got.offset != (bfd_vma) -1)
{
/* We have already allocated space in the .got. */
break;
@@ -6258,7 +6311,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
g->global_gotsym = h->dynindx;
/* Make this symbol to be the global got symbol. */
- h->got_offset = 0;
+ h->got.offset = 0;
}
break;
@@ -6329,6 +6382,20 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
sizeof (Elf32_External_crinfo);
break;
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_MIPS_GNU_VTINHERIT:
+ if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+ return false;
+ break;
+
+ /* This relocation describes which C++ vtable entries are actually
+ used. Record for later use during GC. */
+ case R_MIPS_GNU_VTENTRY:
+ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+ return false;
+ break;
+
default:
break;
}
@@ -6355,6 +6422,98 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
return true;
}
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+mips_elf_gc_mark_hook (abfd, info, rel, h, sym)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ Elf_Internal_Rela *rel;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+{
+ /* ??? Do mips16 stub sections need to be handled special? */
+
+ if (h != NULL)
+ {
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_MIPS_GNU_VTINHERIT:
+ case R_MIPS_GNU_VTENTRY:
+ break;
+
+ default:
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->root.u.def.section;
+
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section;
+ }
+ }
+ }
+ else
+ {
+ if (!(elf_bad_symtab (abfd)
+ && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
+ && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
+ && sym->st_shndx != SHN_COMMON))
+ {
+ return bfd_section_from_elf_index (abfd, sym->st_shndx);
+ }
+ }
+
+ return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed. */
+
+static boolean
+mips_elf_gc_sweep_hook (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+#if 0
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_signed_vma *local_got_refcounts;
+ const Elf_Internal_Rela *rel, *relend;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+
+ relend = relocs + sec->reloc_count;
+ for (rel = relocs; rel < relend; rel++)
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_CALL_LO16:
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_GOT_LO16:
+ /* ??? It would seem that the existing MIPS code does no sort
+ of reference counting or whatnot on its GOT and PLT entries,
+ so it is not possible to garbage collect them at this time. */
+ break;
+
+ default:
+ break;
+ }
+#endif
+
+ return true;
+}
+
+
/* 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
@@ -6424,7 +6583,7 @@ mips_elf_adjust_dynamic_symbol (info, h)
h->root.u.def.value = s->_raw_size;
/* XXX Write this stub address somewhere. */
- h->plt_offset = s->_raw_size;
+ h->plt.offset = s->_raw_size;
/* Make room for this stub code. */
s->_raw_size += MIPS_FUNCTION_STUB_SIZE;
@@ -6608,7 +6767,18 @@ mips_elf_size_dynamic_sections (output_bfd, info)
if (strncmp (name, ".rel", 4) == 0)
{
if (s->_raw_size == 0)
- strip = true;
+ {
+ /* We only strip the section if the output section name
+ has the same name. Otherwise, there might be several
+ input sections for this output section. FIXME: This
+ code is probably not needed these days anyhow, since
+ the linker now does not create empty output sections. */
+ if (s->output_section != NULL
+ && strcmp (name,
+ bfd_get_section_name (s->output_section->owner,
+ s->output_section)) == 0)
+ strip = true;
+ }
else
{
const char *outname;
@@ -6917,7 +7087,7 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
dynobj = elf_hash_table (info)->dynobj;
gval = sym->st_value;
- if (h->plt_offset != (bfd_vma) -1)
+ if (h->plt.offset != (bfd_vma) -1)
{
asection *s;
bfd_byte *p;
@@ -6945,17 +7115,17 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
p += 4;
bfd_put_32 (output_bfd, STUB_LI16 + h->dynindx, p);
- BFD_ASSERT (h->plt_offset <= s->_raw_size);
- memcpy (s->contents + h->plt_offset, stub, MIPS_FUNCTION_STUB_SIZE);
+ BFD_ASSERT (h->plt.offset <= s->_raw_size);
+ memcpy (s->contents + h->plt.offset, stub, MIPS_FUNCTION_STUB_SIZE);
- /* Mark the symbol as undefined. plt_offset != -1 occurs
+ /* Mark the symbol as undefined. plt.offset != -1 occurs
only for the referenced symbol. */
sym->st_shndx = SHN_UNDEF;
/* The run-time linker uses the st_value field of the symbol
to reset the global offset table entry for this external
to its stub address when unlinking a shared object. */
- gval = s->output_section->vma + s->output_offset + h->plt_offset;
+ gval = s->output_section->vma + s->output_offset + h->plt.offset;
sym->st_value = gval;
}
@@ -6973,7 +7143,7 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
/* This symbol has an entry in the global offset table. Set its
value to the corresponding got entry, if needed. */
- if (h->got_offset == (bfd_vma) -1)
+ if (h->got.offset == (bfd_vma) -1)
{
offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4;
BFD_ASSERT (g->local_gotno * 4 <= offset
@@ -7612,6 +7782,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
#define elf_backend_collect true
#define elf_backend_type_change_ok true
+#define elf_backend_can_gc_sections true
#define elf_info_to_howto 0
#define elf_info_to_howto_rel mips_info_to_howto_rel
#define elf_backend_sym_is_global mips_elf_sym_is_global
@@ -7658,5 +7829,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
mips_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
mips_elf_finish_dynamic_sections
+#define elf_backend_gc_mark_hook mips_elf_gc_mark_hook
+#define elf_backend_gc_sweep_hook mips_elf_gc_sweep_hook
#include "elf32-target.h"