aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-i386.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2001-09-25 04:34:50 +0000
committerAlan Modra <amodra@gmail.com>2001-09-25 04:34:50 +0000
commit0c715baa724c70f3b8da8239e8c69bdaca8b05c9 (patch)
treebcbf60f47d938e3ac663b954c93efcb724074caa /bfd/elf32-i386.c
parent4f3379724d512db262eee1a6a8dc8938f11ee4a1 (diff)
downloadgdb-0c715baa724c70f3b8da8239e8c69bdaca8b05c9.zip
gdb-0c715baa724c70f3b8da8239e8c69bdaca8b05c9.tar.gz
gdb-0c715baa724c70f3b8da8239e8c69bdaca8b05c9.tar.bz2
* elf-bfd.h (struct bfd_elf_section_data): Add "local_dynrel"
and "sreloc" fields. * elf32-i386.c (struct elf_i386_dyn_relocs): Add "sec", and "pc_count" fields. Remove "section" field. (elf_i386_check_relocs): Don't set DF_TEXTREL here. Don't allocate space for dynamic relocs here. Instead, record all needed dynamic relocs via dyn_relocs and local_dynrel. Cache pointer to "sreloc" section in elf_section_data. (elf_i386_gc_sweep_hook): Sweep dyn_relocs and local_dynrel. (allocate_plt_and_got_and_discard_relocs): Rename to allocate_dynrelocs. Allocate rather than discarding dyn relocs. (readonly_dynrelocs): New function. (elf_i386_size_dynamic_sections): Call readonly_dynrelocs. Rename "i" to "ibfd". Allocate space for local dyn relocs. (elf_i386_relocate_section): Make use of cached sreloc.
Diffstat (limited to 'bfd/elf32-i386.c')
-rw-r--r--bfd/elf32-i386.c303
1 files changed, 186 insertions, 117 deletions
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 211f93a..cf4798e 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -49,7 +49,9 @@ static boolean elf_i386_gc_sweep_hook
const Elf_Internal_Rela *));
static boolean elf_i386_adjust_dynamic_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
-static boolean allocate_plt_and_got_and_discard_relocs
+static boolean allocate_dynrelocs
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean readonly_dynrelocs
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_i386_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
@@ -378,12 +380,16 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] =
struct elf_i386_dyn_relocs
{
- /* Next section. */
struct elf_i386_dyn_relocs *next;
- /* A section in dynobj. */
- asection *section;
- /* Number of relocs copied in this section. */
+
+ /* The input section of the reloc. */
+ asection *sec;
+
+ /* Total number of relocs copied for the input section. */
bfd_size_type count;
+
+ /* Number of pc-relative relocs copied for the input section. */
+ bfd_size_type pc_count;
};
/* i386 ELF linker hash entry. */
@@ -392,7 +398,7 @@ struct elf_i386_link_hash_entry
{
struct elf_link_hash_entry root;
- /* Number of PC relative relocs copied for this symbol. */
+ /* Track dynamic relocs copied for this symbol. */
struct elf_i386_dyn_relocs *dyn_relocs;
};
@@ -743,9 +749,9 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
|| strcmp (bfd_get_section_name (abfd, sec),
name + 4) != 0)
{
- (*_bfd_error_handler) (_("%s: bad relocation section name `%s\'"),
- bfd_archive_filename (abfd),
- name);
+ (*_bfd_error_handler)
+ (_("%s: bad relocation section name `%s\'"),
+ bfd_archive_filename (abfd), name);
}
sreloc = bfd_get_section_by_name (dynobj, name);
@@ -763,32 +769,20 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
|| ! bfd_set_section_alignment (dynobj, sreloc, 2))
return false;
}
- if (sec->flags & SEC_READONLY)
- info->flags |= DF_TEXTREL;
+ elf_section_data (sec)->sreloc = sreloc;
}
- sreloc->_raw_size += sizeof (Elf32_External_Rel);
-
- /* If this is a global symbol, we count the number of PC
- relative relocations we have entered for this symbol,
- so that we can discard them later as necessary. Note
- that this function is only called if we are using an
- elf_i386 linker hash table, which means that h is
- really a pointer to an elf_i386_link_hash_entry. */
- if (!info->shared
- || (h != NULL
- && ELF32_R_TYPE (rel->r_info) == R_386_PC32))
+ /* If this is a global symbol, we count the number of
+ relocations we need for this symbol. */
+ if (h != NULL)
{
struct elf_i386_link_hash_entry *eh;
struct elf_i386_dyn_relocs *p;
eh = (struct elf_i386_link_hash_entry *) h;
+ p = eh->dyn_relocs;
- for (p = eh->dyn_relocs; p != NULL; p = p->next)
- if (p->section == sreloc)
- break;
-
- if (p == NULL)
+ if (p == NULL || p->sec != sec)
{
p = ((struct elf_i386_dyn_relocs *)
bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
@@ -796,11 +790,19 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
return false;
p->next = eh->dyn_relocs;
eh->dyn_relocs = p;
- p->section = sreloc;
+ p->sec = sec;
p->count = 0;
+ p->pc_count = 0;
}
- ++p->count;
+ p->count += 1;
+ if (ELF32_R_TYPE (rel->r_info) == R_386_PC32)
+ p->pc_count += 1;
+ }
+ else
+ {
+ /* Track dynamic relocs needed for local syms too. */
+ elf_section_data (sec)->local_dynrel += 1;
}
}
@@ -893,6 +895,8 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs)
struct elf_link_hash_entry *h;
bfd *dynobj;
+ elf_section_data (sec)->local_dynrel = 0;
+
dynobj = elf_hash_table (info)->dynobj;
if (dynobj == NULL)
return true;
@@ -924,9 +928,32 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs)
case R_386_32:
case R_386_PC32:
- if (info->shared)
- break;
- /* Fall through. */
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ struct elf_i386_link_hash_entry *eh;
+ struct elf_i386_dyn_relocs **pp;
+ struct elf_i386_dyn_relocs *p;
+
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+ if (!info->shared && h->plt.refcount > 0)
+ h->plt.refcount -= 1;
+
+ eh = (struct elf_i386_link_hash_entry *) h;
+
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+ if (p->sec == sec)
+ {
+ if (ELF32_R_TYPE (rel->r_info) == R_386_PC32)
+ p->pc_count -= 1;
+ p->count -= 1;
+ if (p->count == 0)
+ *pp = p->next;
+ break;
+ }
+ }
+ break;
case R_386_PLT32:
r_symndx = ELF32_R_SYM (rel->r_info);
@@ -1087,12 +1114,10 @@ elf_i386_adjust_dynamic_symbol (info, h)
|| ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0))
/* Allocate space in .plt, .got and associated reloc sections for
- global syms. Also discards space allocated for relocs in the
- check_relocs function that we subsequently have found to be
- unneeded. */
+ dynamic relocs. */
static boolean
-allocate_plt_and_got_and_discard_relocs (h, inf)
+allocate_dynrelocs (h, inf)
struct elf_link_hash_entry *h;
PTR inf;
{
@@ -1100,6 +1125,7 @@ allocate_plt_and_got_and_discard_relocs (h, inf)
struct elf_i386_link_hash_table *htab;
asection *s;
struct elf_i386_link_hash_entry *eh;
+ struct elf_i386_dyn_relocs *p;
if (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
@@ -1191,53 +1217,106 @@ allocate_plt_and_got_and_discard_relocs (h, inf)
else
h->got.offset = (bfd_vma) -1;
- /* In the shared -Bsymbolic case, discard space allocated for
- dynamic relocs against symbols which turn out to be defined
- in regular objects. For the normal shared case, discard space
- for relocs that have become local due to symbol visibility
- changes. For the non-shared case, discard space for symbols
- which turn out to need copy relocs or are not dynamic. */
-
eh = (struct elf_i386_link_hash_entry *) h;
if (eh->dyn_relocs == NULL)
return true;
- if (!info->shared
- && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
- && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
- || (htab->root.dynamic_sections_created
- && (h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_undefined))))
+ /* In the shared -Bsymbolic case, discard space allocated for
+ dynamic pc-relative relocs against symbols which turn out to be
+ defined in regular objects. For the normal shared case, discard
+ space for relocs that have become local due to symbol visibility
+ changes. */
+
+ if (info->shared)
{
- /* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- if (h->dynindx == -1
- && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+ && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
+ || info->symbolic))
{
- if (! bfd_elf32_link_record_dynamic_symbol (info, h))
- return false;
+ struct elf_i386_dyn_relocs **pp;
+
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ {
+ p->count -= p->pc_count;
+ p->pc_count = 0;
+ if (p->count == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
}
+ }
+ else
+ {
+ /* For the non-shared case, discard space for relocs against
+ symbols which turn out to need copy relocs or are not
+ dynamic. */
+
+ if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
+ && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ || (htab->root.dynamic_sections_created
+ && (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined))))
+ {
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1
+ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ {
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
- /* If that succeeded, we know we'll be keeping all the relocs. */
- if (h->dynindx != -1)
- return true;
+ /* If that succeeded, we know we'll be keeping all the
+ relocs. */
+ if (h->dynindx != -1)
+ goto keep;
+ }
+
+ eh->dyn_relocs = NULL;
+
+ keep:
}
- if (!info->shared
- || ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
- && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
- || info->symbolic)))
+ /* Finally, allocate space. */
+ for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
- struct elf_i386_dyn_relocs *c;
-
- for (c = eh->dyn_relocs; c != NULL; c = c->next)
- c->section->_raw_size -= c->count * sizeof (Elf32_External_Rel);
+ asection *sreloc = elf_section_data (p->sec)->sreloc;
+ sreloc->_raw_size += p->count * sizeof (Elf32_External_Rel);
}
return true;
}
+/* Find any dynamic relocs that apply to read-only sections. */
+
+static boolean
+readonly_dynrelocs (h, inf)
+ struct elf_link_hash_entry *h;
+ PTR inf;
+{
+ struct elf_i386_link_hash_entry *eh;
+ struct elf_i386_dyn_relocs *p;
+
+ eh = (struct elf_i386_link_hash_entry *) h;
+ for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ {
+ asection *s = p->sec->output_section;
+
+ if (s != NULL && (s->flags & SEC_READONLY) != 0)
+ {
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
+ info->flags |= DF_TEXTREL;
+
+ /* Not an error, just cut short the traversal. */
+ return false;
+ }
+ }
+ return true;
+}
+
/* Set the sizes of the dynamic sections. */
static boolean
@@ -1249,7 +1328,7 @@ elf_i386_size_dynamic_sections (output_bfd, info)
bfd *dynobj;
asection *s;
boolean relocs;
- bfd *i;
+ bfd *ibfd;
htab = elf_i386_hash_table (info);
dynobj = htab->root.dynobj;
@@ -1269,8 +1348,9 @@ elf_i386_size_dynamic_sections (output_bfd, info)
}
}
- /* Set up .got offsets for local syms. */
- for (i = info->input_bfds; i; i = i->link_next)
+ /* Set up .got offsets for local syms, and space for local dynamic
+ relocs. */
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
bfd_signed_vma *local_got;
bfd_signed_vma *end_local_got;
@@ -1278,14 +1358,25 @@ elf_i386_size_dynamic_sections (output_bfd, info)
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
- if (bfd_get_flavour (i) != bfd_target_elf_flavour)
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
continue;
- local_got = elf_local_got_refcounts (i);
+ for (s = ibfd->sections; s != NULL; s = s->next)
+ {
+ bfd_size_type count = elf_section_data (s)->local_dynrel;
+
+ if (count != 0)
+ {
+ srel = elf_section_data (s)->sreloc;
+ srel->_raw_size += count * sizeof (Elf32_External_Rel);
+ }
+ }
+
+ local_got = elf_local_got_refcounts (ibfd);
if (!local_got)
continue;
- symtab_hdr = &elf_tdata (i)->symtab_hdr;
+ symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
s = htab->sgot;
@@ -1304,11 +1395,9 @@ elf_i386_size_dynamic_sections (output_bfd, info)
}
}
- /* Allocate global sym .plt and .got entries. Also discard all
- unneeded relocs. */
- elf_link_hash_traverse (&htab->root,
- allocate_plt_and_got_and_discard_relocs,
- (PTR) info);
+ /* Allocate global sym .plt and .got entries, and space for global
+ sym dynamic relocs. */
+ elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (PTR) info);
/* We now have determined the sizes of the various dynamic sections.
Allocate memory for them. */
@@ -1402,12 +1491,16 @@ elf_i386_size_dynamic_sections (output_bfd, info)
|| !add_dynamic_entry (DT_RELSZ, 0)
|| !add_dynamic_entry (DT_RELENT, sizeof (Elf32_External_Rel)))
return false;
- }
- if ((info->flags & DF_TEXTREL) != 0)
- {
- if (!add_dynamic_entry (DT_TEXTREL, 0))
- return false;
+ /* If any dynamic relocs apply to a read-only section,
+ then we need a DT_TEXTREL entry. */
+ elf_link_hash_traverse (&htab->root, readonly_dynrelocs, (PTR) info);
+
+ if ((info->flags & DF_TEXTREL) != 0)
+ {
+ if (!add_dynamic_entry (DT_TEXTREL, 0))
+ return false;
+ }
}
}
#undef add_dynamic_entry
@@ -1434,7 +1527,6 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
bfd_vma *local_got_offsets;
- asection *sreloc;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
@@ -1444,7 +1536,6 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
sym_hashes = elf_sym_hashes (input_bfd);
local_got_offsets = elf_local_got_offsets (input_bfd);
- sreloc = NULL;
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
@@ -1712,38 +1803,13 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
{
Elf_Internal_Rel outrel;
boolean skip, relocate;
+ asection *sreloc;
+ Elf32_External_Rel *loc;
/* When generating a shared object, these relocations
are copied into the output file to be resolved at run
time. */
- if (sreloc == NULL)
- {
- const char *name;
-
- name = (bfd_elf_string_from_elf_section
- (input_bfd,
- elf_elfheader (input_bfd)->e_shstrndx,
- elf_section_data (input_section)->rel_hdr.sh_name));
- if (name == NULL)
- return false;
-
- if (strncmp (name, ".rel", 4) != 0
- || strcmp (bfd_get_section_name (input_bfd,
- input_section),
- name + 4) != 0)
- {
- (*_bfd_error_handler)
- (_("%s: bad relocation section name `%s\'"),
- bfd_archive_filename (input_bfd), name);
- return false;
- }
-
- sreloc = bfd_get_section_by_name (dynobj, name);
- if (sreloc == NULL)
- abort ();
- }
-
skip = false;
if (elf_section_data (input_section)->stab_info == NULL)
@@ -1786,11 +1852,14 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
}
- bfd_elf32_swap_reloc_out (output_bfd, &outrel,
- (((Elf32_External_Rel *)
- sreloc->contents)
- + sreloc->reloc_count));
- ++sreloc->reloc_count;
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (sreloc == NULL)
+ abort ();
+
+ loc = ((Elf32_External_Rel *) sreloc->contents
+ + sreloc->reloc_count);
+ sreloc->reloc_count += 1;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
/* If this reloc is against an external symbol, we do
not want to fiddle with the addend. Otherwise, we