aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/elf32-i386.c305
1 files changed, 211 insertions, 94 deletions
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 4d5324a..b3e3478 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1,5 +1,5 @@
/* Intel 80386/80486-specific support for 32-bit ELF
- Copyright 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Copyright 1993-1997, 1998 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
@@ -52,45 +52,7 @@ static boolean elf_i386_finish_dynamic_sections
#define USE_REL 1 /* 386 uses REL relocations instead of RELA */
-enum reloc_type
- {
- R_386_NONE = 0,
- R_386_32,
- R_386_PC32,
- R_386_GOT32,
- R_386_PLT32,
- R_386_COPY,
- R_386_GLOB_DAT,
- R_386_JUMP_SLOT,
- R_386_RELATIVE,
- R_386_GOTOFF,
- R_386_GOTPC,
- FIRST_INVALID_RELOC,
- LAST_INVALID_RELOC = 19,
- /* The remaining relocs are a GNU extension. */
- R_386_16 = 20,
- R_386_PC16,
- R_386_8,
- R_386_PC8,
- R_386_max
- };
-
-#if 0
-static CONST char *CONST reloc_type_names[] =
-{
- "R_386_NONE",
- "R_386_32",
- "R_386_PC32",
- "R_386_GOT32",
- "R_386_PLT32",
- "R_386_COPY",
- "R_386_GLOB_DAT",
- "R_386_JUMP_SLOT",
- "R_386_RELATIVE",
- "R_386_GOTOFF",
- "R_386_GOTPC",
-};
-#endif
+#include "elf/i386.h"
static reloc_howto_type elf_howto_table[]=
{
@@ -121,6 +83,38 @@ static reloc_howto_type elf_howto_table[]=
HOWTO(R_386_PC8, 0,0,8,true, 0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PC8", true,0xff,0xff,true),
};
+/* GNU extension to record C++ vtable hierarchy. */
+static reloc_howto_type elf32_i386_vtinherit_howto =
+ HOWTO (R_386_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_386_GNU_VTINHERIT", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false);
+
+/* GNU extension to record C++ vtable member usage. */
+static reloc_howto_type elf32_i386_vtentry_howto =
+ HOWTO (R_386_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 */
+ _bfd_elf_rel_vtable_reloc_fn, /* special_function */
+ "R_386_GNU_VTENTRY", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false);
+
#ifdef DEBUG_GEN_RELOC
#define TRACE(str) fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str)
#else
@@ -195,6 +189,14 @@ elf_i386_reloc_type_lookup (abfd, code)
TRACE ("BFD_RELOC_8_PCREL");
return &elf_howto_table[(int) R_386_PC8];
+ case BFD_RELOC_VTABLE_INHERIT:
+ TRACE ("BFD_RELOC_VTABLE_INHERIT");
+ return &elf32_i386_vtinherit_howto;
+
+ case BFD_RELOC_VTABLE_ENTRY:
+ TRACE ("BFD_RELOC_VTABLE_ENTRY");
+ return &elf32_i386_vtentry_howto;
+
default:
break;
}
@@ -218,13 +220,19 @@ elf_i386_info_to_howto_rel (abfd, cache_ptr, dst)
arelent *cache_ptr;
Elf32_Internal_Rel *dst;
{
- enum reloc_type type;
+ enum elf_i386_reloc_type type;
- type = (enum reloc_type) ELF32_R_TYPE (dst->r_info);
- BFD_ASSERT (type < R_386_max);
- BFD_ASSERT (type < FIRST_INVALID_RELOC || type > LAST_INVALID_RELOC);
-
- cache_ptr->howto = &elf_howto_table[(int) type];
+ type = (enum elf_i386_reloc_type) ELF32_R_TYPE (dst->r_info);
+ if (type == R_386_GNU_VTINHERIT)
+ cache_ptr->howto = &elf32_i386_vtinherit_howto;
+ else if (type == R_386_GNU_VTENTRY)
+ cache_ptr->howto = &elf32_i386_vtentry_howto;
+ else
+ {
+ BFD_ASSERT (type < R_386_max);
+ BFD_ASSERT (type < FIRST_INVALID_RELOC || type > LAST_INVALID_RELOC);
+ cache_ptr->howto = &elf_howto_table[(int) type];
+ }
}
/* Return whether a symbol name implies a local label. The UnixWare
@@ -488,10 +496,14 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
if (srelgot == NULL
&& (h != NULL || info->shared))
{
- srelgot = bfd_get_section_by_name (dynobj, ".rel.got");
+ const char *srelgot_name;
+
+ srelgot_name = info->combine_reloc ? ".gnu.reloc" : ".rel.got";
+
+ srelgot = bfd_get_section_by_name (dynobj, srelgot_name);
if (srelgot == NULL)
{
- srelgot = bfd_make_section (dynobj, ".rel.got");
+ srelgot = bfd_make_section (dynobj, srelgot_name);
if (srelgot == NULL
|| ! bfd_set_section_flags (dynobj, srelgot,
(SEC_ALLOC
@@ -507,12 +519,12 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
if (h != NULL)
{
- if (h->got_offset != (bfd_vma) -1)
+ if (h->got.offset != (bfd_vma) -1)
{
/* We have already allocated space in the .got. */
break;
}
- h->got_offset = sgot->_raw_size;
+ h->got.offset = sgot->_raw_size;
/* Make sure this symbol is output as a dynamic symbol. */
if (h->dynindx == -1)
@@ -592,6 +604,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
possibility below by storing information in the
pcrel_relocs_copied field of the hash table entry. */
if (info->shared
+ && (sec->flags & SEC_ALLOC) != 0
&& (ELF32_R_TYPE (rel->r_info) != R_386_PC32
|| (h != NULL
&& (! info->symbolic
@@ -616,6 +629,11 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
&& strcmp (bfd_get_section_name (abfd, sec),
name + 4) == 0);
+ if (info->combine_reloc)
+ /* If we combine the relocation sections use change
+ the name here. */
+ name = ".gnu.reloc";
+
sreloc = bfd_get_section_by_name (dynobj, name);
if (sreloc == NULL)
{
@@ -673,6 +691,20 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
break;
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_386_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_386_GNU_VTENTRY:
+ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+ return false;
+ break;
+
default:
break;
}
@@ -681,6 +713,67 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
return true;
}
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+elf_i386_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;
+{
+ if (h != NULL)
+ {
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_386_GNU_VTINHERIT:
+ case R_386_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
+elf_i386_gc_sweep_hook (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ /* ??? It would seem that the existing i386 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. */
+
+ 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
@@ -755,7 +848,7 @@ elf_i386_adjust_dynamic_symbol (info, h)
h->root.u.def.value = s->_raw_size;
}
- h->plt_offset = s->_raw_size;
+ h->plt.offset = s->_raw_size;
/* Make room for this entry. */
s->_raw_size += PLT_ENTRY_SIZE;
@@ -818,8 +911,9 @@ elf_i386_adjust_dynamic_symbol (info, h)
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
{
asection *srel;
+ const char *srel_name = info->combine_reloc ? ".gnu.reloc" : ".rel.bss";
- srel = bfd_get_section_by_name (dynobj, ".rel.bss");
+ srel = bfd_get_section_by_name (dynobj, srel_name);
BFD_ASSERT (srel != NULL);
srel->_raw_size += sizeof (Elf32_External_Rel);
h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
@@ -884,7 +978,9 @@ elf_i386_size_dynamic_sections (output_bfd, info)
not actually use these entries. Reset the size of .rel.got,
which will cause it to get stripped from the output file
below. */
- s = bfd_get_section_by_name (dynobj, ".rel.got");
+ const char *s_name = info->combine_reloc ? ".gnu.reloc" : ".rel.got";
+
+ s = bfd_get_section_by_name (dynobj, s_name);
if (s != NULL)
s->_raw_size = 0;
}
@@ -932,7 +1028,8 @@ elf_i386_size_dynamic_sections (output_bfd, info)
plt = true;
}
}
- else if (strncmp (name, ".rel", 4) == 0)
+ else if (strncmp (name, ".rel", 4) == 0
+ || strcmp (name, ".gnu.reloc") == 0)
{
if (s->_raw_size == 0)
{
@@ -968,7 +1065,8 @@ elf_i386_size_dynamic_sections (output_bfd, info)
s->output_section);
target = bfd_get_section_by_name (output_bfd, outname + 4);
if (target != NULL
- && (target->flags & SEC_READONLY) != 0)
+ && (target->flags & SEC_READONLY) != 0
+ && (target->flags & SEC_ALLOC) != 0)
reltext = true;
}
@@ -1116,6 +1214,9 @@ elf_i386_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_386_GNU_VTINHERIT
+ || r_type == R_386_GNU_VTENTRY)
+ continue;
if (r_type < 0
|| r_type >= (int) R_386_max
|| (r_type >= (int) FIRST_INVALID_RELOC
@@ -1175,7 +1276,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
sec = h->root.u.def.section;
if (r_type == R_386_GOTPC
|| (r_type == R_386_PLT32
- && h->plt_offset != (bfd_vma) -1)
+ && h->plt.offset != (bfd_vma) -1)
|| (r_type == R_386_GOT32
&& elf_hash_table (info)->dynamic_sections_created
&& (! info->shared
@@ -1188,7 +1289,12 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
& ELF_LINK_HASH_DEF_REGULAR) == 0)
&& (r_type == R_386_32
|| r_type == R_386_PC32)
- && (input_section->flags & SEC_ALLOC) != 0))
+ && ((input_section->flags & SEC_ALLOC) != 0
+ /* DWARF will emit R_386_32 relocations in its
+ sections against symbols defined externally
+ in shared libraries. We can't do anything
+ with them here. */
+ || (input_section->flags & SEC_DEBUGGING) != 0)))
{
/* In these cases, we don't need the relocation
value. We check specially because in some
@@ -1198,7 +1304,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
else if (sec->output_section == NULL)
{
(*_bfd_error_handler)
- ("%s: warning: unresolvable relocation against symbol `%s' from %s section",
+ (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
bfd_get_filename (input_bfd), h->root.root.string,
bfd_get_section_name (input_bfd, input_section));
relocation = 0;
@@ -1237,7 +1343,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
{
bfd_vma off;
- off = h->got_offset;
+ off = h->got.offset;
BFD_ASSERT (off != (bfd_vma) -1);
if (! elf_hash_table (info)->dynamic_sections_created
@@ -1263,7 +1369,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
{
bfd_put_32 (output_bfd, relocation,
sgot->contents + off);
- h->got_offset |= 1;
+ h->got.offset |= 1;
}
}
@@ -1291,8 +1397,12 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
{
asection *srelgot;
Elf_Internal_Rel outrel;
+ const char *srelgot_name;
+
+ srelgot_name = (info->combine_reloc
+ ? ".gnu.reloc" : ".rel.got");
- srelgot = bfd_get_section_by_name (dynobj, ".rel.got");
+ srelgot = bfd_get_section_by_name (dynobj, srelgot_name);
BFD_ASSERT (srelgot != NULL);
outrel.r_offset = (sgot->output_section->vma
@@ -1355,7 +1465,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
if (h == NULL)
break;
- if (h->plt_offset == (bfd_vma) -1)
+ if (h->plt.offset == (bfd_vma) -1)
{
/* We didn't make a PLT entry for this symbol. This
happens when statically linking PIC code, or when
@@ -1371,15 +1481,17 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
relocation = (splt->output_section->vma
+ splt->output_offset
- + h->plt_offset);
+ + h->plt.offset);
break;
case R_386_32:
case R_386_PC32:
if (info->shared
+ && (input_section->flags & SEC_ALLOC) != 0
&& (r_type != R_386_PC32
|| (h != NULL
+ && h->dynindx != -1
&& (! info->symbolic
|| (h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR) == 0))))
@@ -1402,10 +1514,14 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
if (name == NULL)
return false;
- BFD_ASSERT (strncmp (name, ".rel", 4) == 0
- && strcmp (bfd_get_section_name (input_bfd,
- input_section),
- name + 4) == 0);
+ if (info->combine_reloc)
+ name = ".gnu.reloc";
+
+ BFD_ASSERT ((strncmp (name, ".rel", 4) == 0
+ && strcmp (bfd_get_section_name (input_bfd,
+ input_section),
+ name + 4) == 0)
+ || strcmp (name, ".gnu.reloc") == 0);
sreloc = bfd_get_section_by_name (dynobj, name);
BFD_ASSERT (sreloc != NULL);
@@ -1440,10 +1556,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
else if (r_type == R_386_PC32)
{
BFD_ASSERT (h != NULL && h->dynindx != -1);
- if ((input_section->flags & SEC_ALLOC) != 0)
- relocate = false;
- else
- relocate = true;
+ relocate = false;
outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_PC32);
}
else
@@ -1461,10 +1574,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
else
{
BFD_ASSERT (h->dynindx != -1);
- if ((input_section->flags & SEC_ALLOC) != 0)
- relocate = false;
- else
- relocate = true;
+ relocate = false;
outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_32);
}
}
@@ -1543,7 +1653,7 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
dynobj = elf_hash_table (info)->dynobj;
- if (h->plt_offset != (bfd_vma) -1)
+ if (h->plt.offset != (bfd_vma) -1)
{
asection *splt;
asection *sgot;
@@ -1566,7 +1676,7 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
corresponds to this symbol. This is the index of this symbol
in all the symbols for which we are making plt entries. The
first entry in the procedure linkage table is reserved. */
- plt_index = h->plt_offset / PLT_ENTRY_SIZE - 1;
+ plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
/* Get the offset into the .got table of the entry that
corresponds to this function. Each .got entry is 4 bytes.
@@ -1576,32 +1686,32 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
/* Fill in the entry in the procedure linkage table. */
if (! info->shared)
{
- memcpy (splt->contents + h->plt_offset, elf_i386_plt_entry,
+ memcpy (splt->contents + h->plt.offset, elf_i386_plt_entry,
PLT_ENTRY_SIZE);
bfd_put_32 (output_bfd,
(sgot->output_section->vma
+ sgot->output_offset
+ got_offset),
- splt->contents + h->plt_offset + 2);
+ splt->contents + h->plt.offset + 2);
}
else
{
- memcpy (splt->contents + h->plt_offset, elf_i386_pic_plt_entry,
+ memcpy (splt->contents + h->plt.offset, elf_i386_pic_plt_entry,
PLT_ENTRY_SIZE);
bfd_put_32 (output_bfd, got_offset,
- splt->contents + h->plt_offset + 2);
+ splt->contents + h->plt.offset + 2);
}
bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
- splt->contents + h->plt_offset + 7);
- bfd_put_32 (output_bfd, - (h->plt_offset + PLT_ENTRY_SIZE),
- splt->contents + h->plt_offset + 12);
+ splt->contents + h->plt.offset + 7);
+ bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
+ splt->contents + h->plt.offset + 12);
/* Fill in the entry in the global offset table. */
bfd_put_32 (output_bfd,
(splt->output_section->vma
+ splt->output_offset
- + h->plt_offset
+ + h->plt.offset
+ 6),
sgot->contents + got_offset);
@@ -1622,22 +1732,23 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
}
}
- if (h->got_offset != (bfd_vma) -1)
+ if (h->got.offset != (bfd_vma) -1)
{
asection *sgot;
asection *srel;
Elf_Internal_Rel rel;
+ const char *srel_name = info->combine_reloc ? ".gnu.reloc" : ".rel.got";
/* This symbol has an entry in the global offset table. Set it
up. */
sgot = bfd_get_section_by_name (dynobj, ".got");
- srel = bfd_get_section_by_name (dynobj, ".rel.got");
+ srel = bfd_get_section_by_name (dynobj, srel_name);
BFD_ASSERT (sgot != NULL && srel != NULL);
rel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
- + (h->got_offset &~ 1));
+ + (h->got.offset &~ 1));
/* If this is a -Bsymbolic link, and the symbol is defined
locally, we just want to emit a RELATIVE reloc. Likewise if
@@ -1650,7 +1761,7 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
else
{
- bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got_offset);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT);
}
@@ -1664,6 +1775,7 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
{
asection *s;
Elf_Internal_Rel rel;
+ const char *s_name = info->combine_reloc ? ".gnu.reloc" : ".rel.bss";
/* This symbol needs a copy reloc. Set it up. */
@@ -1671,8 +1783,7 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak));
- s = bfd_get_section_by_name (h->root.u.def.section->owner,
- ".rel.bss");
+ s = bfd_get_section_by_name (h->root.u.def.section->owner, s_name);
BFD_ASSERT (s != NULL);
rel.r_offset = (h->root.u.def.value
@@ -1842,8 +1953,14 @@ elf_i386_finish_dynamic_sections (output_bfd, info)
elf_i386_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
elf_i386_finish_dynamic_sections
-#define elf_backend_want_got_plt 1
-#define elf_backend_plt_readonly 1
-#define elf_backend_want_plt_sym 0
+#define elf_backend_gc_mark_hook elf_i386_gc_mark_hook
+#define elf_backend_gc_sweep_hook elf_i386_gc_sweep_hook
+
+#define elf_backend_can_gc_sections 1
+#define elf_backend_want_got_plt 1
+#define elf_backend_plt_readonly 1
+#define elf_backend_want_plt_sym 0
+#define elf_backend_got_header_size 12
+#define elf_backend_plt_header_size PLT_ENTRY_SIZE
#include "elf32-target.h"