aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/elf-bfd.h4
-rw-r--r--bfd/elf32-i386.c58
-rw-r--r--bfd/elf64-x86-64.c55
-rw-r--r--bfd/elflink.c23
-rw-r--r--bfd/elfxx-x86.c85
-rw-r--r--bfd/elfxx-x86.h60
-rw-r--r--ld/testsuite/ld-i386/pr27491-1a.d4
-rw-r--r--ld/testsuite/ld-x86-64/pr27491-1a.d4
8 files changed, 191 insertions, 102 deletions
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 896aa08..81f8fd4 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2632,6 +2632,10 @@ extern int bfd_elf_add_dt_needed_tag
(bfd *, struct bfd_link_info *);
extern bool _bfd_elf_link_check_relocs
(bfd *, struct bfd_link_info *);
+extern bool _bfd_elf_link_iterate_on_relocs
+ (bfd *, struct bfd_link_info *,
+ bool (*) (bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *));
extern bool bfd_elf_link_record_dynamic_symbol
(struct bfd_link_info *, struct elf_link_hash_entry *);
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 9796207..d1f61be 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -522,7 +522,7 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
Functions named elf_i386_* are called by external routines, other
functions are only called locally. elf_i386_* functions appear
in this file more or less in the order in which they are called
- from external routines. eg. elf_i386_check_relocs is called
+ from external routines. eg. elf_i386_scan_relocs is called
early in the link process, elf_i386_finish_dynamic_sections is
one of the last functions. */
@@ -1106,7 +1106,7 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
}
/* We checked the transition before when we were called from
- elf_i386_check_relocs. We only want to check the new
+ elf_i386_scan_relocs. We only want to check the new
transition which hasn't been checked before. */
check = new_to_type != to_type && from_type == to_type;
to_type = new_to_type;
@@ -1387,11 +1387,6 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
|| h->root.type == bfd_link_hash_defweak)
&& local_ref))
{
- /* Skip __start_SECNAME/__stop_SECNAME when --gc-sections
- -z start-stop-gc are used. */
- if (elf_x86_start_stop_gc_p (link_info, h))
- return true;
-
convert_load:
if (opcode == 0x8b)
{
@@ -1452,21 +1447,20 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
}
/* Look through the relocs for a section during the first phase, and
- calculate needed space in the global offset table, procedure linkage
- table, and dynamic reloc sections. */
+ calculate needed space in the global offset table, and procedure
+ linkage table. */
static bool
-elf_i386_check_relocs (bfd *abfd,
- struct bfd_link_info *info,
- asection *sec,
- const Elf_Internal_Rela *relocs)
+elf_i386_scan_relocs (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ const Elf_Internal_Rela *relocs)
{
struct elf_x86_link_hash_table *htab;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
- asection *sreloc;
bfd_byte *contents;
bool converted;
@@ -1496,8 +1490,6 @@ elf_i386_check_relocs (bfd *abfd,
converted = false;
- sreloc = NULL;
-
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
@@ -1818,18 +1810,6 @@ elf_i386_check_relocs (bfd *abfd,
struct elf_dyn_relocs *p;
struct elf_dyn_relocs **head;
- /* We must copy these reloc types into the output file.
- Create a reloc section in dynobj and make room for
- this reloc. */
- if (sreloc == NULL)
- {
- sreloc = _bfd_elf_make_dynamic_reloc_section
- (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ false);
-
- if (sreloc == NULL)
- goto error_return;
- }
-
/* If this is a global symbol, we count the number of
relocations we need for this symbol. */
if (h != NULL)
@@ -1924,6 +1904,24 @@ elf_i386_check_relocs (bfd *abfd,
return false;
}
+static bool
+elf_i386_always_size_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ bfd *abfd;
+
+ /* Scan relocations after rel_from_abs has been set on __ehdr_start. */
+ for (abfd = info->input_bfds;
+ abfd != (bfd *) NULL;
+ abfd = abfd->link.next)
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && !_bfd_elf_link_iterate_on_relocs (abfd, info,
+ elf_i386_scan_relocs))
+ return false;
+
+ return _bfd_x86_elf_always_size_sections (output_bfd, info);
+}
+
/* Set the correct type for an x86 ELF section. We do this by the
section name, which is a hack, but ought to work. */
@@ -2000,7 +1998,7 @@ elf_i386_relocate_section (bfd *output_bfd,
bool is_vxworks_tls;
unsigned plt_entry_size;
- /* Skip if check_relocs failed. */
+ /* Skip if check_relocs or scan_relocs failed. */
if (input_section->check_relocs_failed)
return false;
@@ -4390,7 +4388,7 @@ elf_i386_link_setup_gnu_properties (struct bfd_link_info *info)
#define bfd_elf32_get_synthetic_symtab elf_i386_get_synthetic_symtab
#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible
-#define elf_backend_check_relocs elf_i386_check_relocs
+#define elf_backend_always_size_sections elf_i386_always_size_sections
#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections
#define elf_backend_fake_sections elf_i386_fake_sections
#define elf_backend_finish_dynamic_sections elf_i386_finish_dynamic_sections
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 22aa3ee..ad885f8 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1309,7 +1309,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
}
/* We checked the transition before when we were called from
- elf_x86_64_check_relocs. We only want to check the new
+ elf_x86_64_scan_relocs. We only want to check the new
transition which hasn't been checked before. */
check = new_to_type != to_type && from_type == to_type;
to_type = new_to_type;
@@ -1628,11 +1628,6 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
|| h->root.type == bfd_link_hash_defweak)
&& h->root.u.def.section == bfd_und_section_ptr))))
{
- /* Skip __start_SECNAME/__stop_SECNAME when --gc-sections
- -z start-stop-gc are used. */
- if (elf_x86_start_stop_gc_p (link_info, h))
- return true;
-
/* Skip since R_X86_64_32/R_X86_64_32S may overflow. */
if (no_overflow)
return true;
@@ -1823,20 +1818,19 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
}
/* Look through the relocs for a section during the first phase, and
- calculate needed space in the global offset table, procedure
- linkage table, and dynamic reloc sections. */
+ calculate needed space in the global offset table, and procedure
+ linkage table. */
static bool
-elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
- asection *sec,
- const Elf_Internal_Rela *relocs)
+elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
+ asection *sec,
+ const Elf_Internal_Rela *relocs)
{
struct elf_x86_link_hash_table *htab;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
- asection *sreloc;
bfd_byte *contents;
bool converted;
@@ -1866,8 +1860,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
converted = false;
- sreloc = NULL;
-
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
@@ -2263,19 +2255,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
struct elf_dyn_relocs *p;
struct elf_dyn_relocs **head;
- /* We must copy these reloc types into the output file.
- Create a reloc section in dynobj and make room for
- this reloc. */
- if (sreloc == NULL)
- {
- sreloc = _bfd_elf_make_dynamic_reloc_section
- (sec, htab->elf.dynobj, ABI_64_P (abfd) ? 3 : 2,
- abfd, /*rela?*/ true);
-
- if (sreloc == NULL)
- goto error_return;
- }
-
/* If this is a global symbol, we count the number of
relocations we need for this symbol. */
if (h != NULL)
@@ -2371,6 +2350,24 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
return false;
}
+static bool
+elf_x86_64_always_size_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ bfd *abfd;
+
+ /* Scan relocations after rel_from_abs has been set on __ehdr_start. */
+ for (abfd = info->input_bfds;
+ abfd != (bfd *) NULL;
+ abfd = abfd->link.next)
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && !_bfd_elf_link_iterate_on_relocs (abfd, info,
+ elf_x86_64_scan_relocs))
+ return false;
+
+ return _bfd_x86_elf_always_size_sections (output_bfd, info);
+}
+
/* Return the relocation value for @tpoff relocation
if STT_TLS virtual address is ADDRESS. */
@@ -2413,7 +2410,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
unsigned int plt_entry_size;
bool status;
- /* Skip if check_relocs failed. */
+ /* Skip if check_relocs or scan_relocs failed. */
if (input_section->check_relocs_failed)
return false;
@@ -5238,7 +5235,7 @@ elf_x86_64_special_sections[]=
elf_x86_64_reloc_name_lookup
#define elf_backend_relocs_compatible elf_x86_64_relocs_compatible
-#define elf_backend_check_relocs elf_x86_64_check_relocs
+#define elf_backend_always_size_sections elf_x86_64_always_size_sections
#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections
#define elf_backend_finish_dynamic_sections elf_x86_64_finish_dynamic_sections
#define elf_backend_finish_dynamic_symbol elf_x86_64_finish_dynamic_symbol
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 08c1617..059461b 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -4008,10 +4008,13 @@ _bfd_elf_notice_as_needed (bfd *ibfd,
return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
}
-/* Check relocations an ELF object file. */
+/* Call ACTION on each relocation in an ELF object file. */
bool
-_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+_bfd_elf_link_iterate_on_relocs
+ (bfd *abfd, struct bfd_link_info *info,
+ bool (*action) (bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *))
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_link_hash_table *htab = elf_hash_table (info);
@@ -4035,7 +4038,6 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
different format. It probably can't be done. */
if ((abfd->flags & DYNAMIC) == 0
&& is_elf_hash_table (&htab->root)
- && bed->check_relocs != NULL
&& elf_object_id (abfd) == elf_hash_table_id (htab)
&& (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
{
@@ -4070,7 +4072,7 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
if (internal_relocs == NULL)
return false;
- ok = (*bed->check_relocs) (abfd, info, o, internal_relocs);
+ ok = action (abfd, info, o, internal_relocs);
if (elf_section_data (o)->relocs != internal_relocs)
free (internal_relocs);
@@ -4083,6 +4085,19 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
return true;
}
+/* Check relocations in an ELF object file. This is called after
+ all input files have been opened. */
+
+bool
+_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ if (bed->check_relocs != NULL)
+ return _bfd_elf_link_iterate_on_relocs (abfd, info,
+ bed->check_relocs);
+ return true;
+}
+
/* Add symbols from an ELF object file to the linker hash table. */
static bool
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index ca4b90e..25f7717 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -892,6 +892,91 @@ _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
return _bfd_elf_link_check_relocs (abfd, info);
}
+/* Look through the relocs for a section before allocation to make the
+ dynamic reloc section. */
+
+bool
+_bfd_x86_elf_check_relocs (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ const Elf_Internal_Rela *relocs)
+{
+ struct elf_x86_link_hash_table *htab;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ asection *sreloc;
+ const struct elf_backend_data *bed;
+ bool is_x86_64;
+
+ if (bfd_link_relocatable (info))
+ return true;
+
+ bed = get_elf_backend_data (abfd);
+ htab = elf_x86_hash_table (info, bed->target_id);
+ if (htab == NULL)
+ {
+ sec->check_relocs_failed = 1;
+ return false;
+ }
+
+ is_x86_64 = bed->target_id == X86_64_ELF_DATA;
+
+ symtab_hdr = &elf_symtab_hdr (abfd);
+ sym_hashes = elf_sym_hashes (abfd);
+
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ unsigned int r_type;
+ unsigned int r_symndx;
+ struct elf_link_hash_entry *h;
+
+ r_symndx = htab->r_sym (rel->r_info);
+ r_type = ELF32_R_TYPE (rel->r_info);
+
+ if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: bad symbol index: %d"),
+ abfd, r_symndx);
+ goto error_return;
+ }
+
+ if (r_symndx < symtab_hdr->sh_info)
+ h = NULL;
+ else
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+
+ if (X86_NEED_DYNAMIC_RELOC_TYPE_P (is_x86_64, r_type)
+ && NEED_DYNAMIC_RELOCATION_P (is_x86_64, info, true, h, sec,
+ r_type, htab->pointer_r_type))
+ {
+ /* We may copy these reloc types into the output file.
+ Create a reloc section in dynobj and make room for
+ this reloc. */
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, htab->elf.dynobj, ABI_64_P (abfd) ? 3 : 2,
+ abfd, sec->use_rela_p);
+
+ if (sreloc != NULL)
+ return true;
+
+ error_return:
+ sec->check_relocs_failed = 1;
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool
_bfd_elf_x86_valid_reloc_p (asection *input_section,
struct bfd_link_info *info,
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 16565a5..1bb8028 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -47,6 +47,25 @@
#define X86_SIZE_TYPE_P(IS_X86_64, TYPE) \
((IS_X86_64) ? X86_64_SIZE_TYPE_P(TYPE) : I386_SIZE_TYPE_P (TYPE))
+#define X86_64_NEED_DYNAMIC_RELOC_TYPE_P(TYPE) \
+ (X86_64_SIZE_TYPE_P (TYPE) \
+ || X86_64_PCREL_TYPE_P (TYPE) \
+ || (TYPE) == R_X86_64_8 \
+ || (TYPE) == R_X86_64_16 \
+ || (TYPE) == R_X86_64_32 \
+ || (TYPE) == R_X86_64_32S \
+ || (TYPE) == R_X86_64_64)
+#define I386_NEED_DYNAMIC_RELOC_TYPE_P(TYPE) \
+ (I386_SIZE_TYPE_P (TYPE) \
+ || I386_PCREL_TYPE_P (TYPE) \
+ || (TYPE) == R_386_32 \
+ || (TYPE) == R_386_TLS_LE \
+ || (TYPE) == R_386_TLS_LE_32)
+#define X86_NEED_DYNAMIC_RELOC_TYPE_P(IS_X86_64, TYPE) \
+ ((IS_X86_64) \
+ ? X86_64_NEED_DYNAMIC_RELOC_TYPE_P (TYPE) \
+ : I386_NEED_DYNAMIC_RELOC_TYPE_P (TYPE))
+
#define PLT_CIE_LENGTH 20
#define PLT_FDE_LENGTH 36
#define PLT_FDE_START_OFFSET 4 + PLT_CIE_LENGTH + 8
@@ -653,6 +672,10 @@ extern int _bfd_x86_elf_compare_relocs
extern bool _bfd_x86_elf_link_check_relocs
(bfd *, struct bfd_link_info *);
+extern bool _bfd_x86_elf_check_relocs
+ (bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *);
+
extern bool _bfd_elf_x86_valid_reloc_p
(asection *, struct bfd_link_info *, struct elf_x86_link_hash_table *,
const Elf_Internal_Rela *, struct elf_link_hash_entry *,
@@ -730,10 +753,10 @@ extern void _bfd_x86_elf_link_report_relative_reloc
#define bfd_elf32_bfd_link_check_relocs \
_bfd_x86_elf_link_check_relocs
+#define elf_backend_check_relocs \
+ _bfd_x86_elf_check_relocs
#define elf_backend_size_dynamic_sections \
_bfd_x86_elf_size_dynamic_sections
-#define elf_backend_always_size_sections \
- _bfd_x86_elf_always_size_sections
#define elf_backend_merge_symbol_attribute \
_bfd_x86_elf_merge_symbol_attribute
#define elf_backend_copy_indirect_symbol \
@@ -757,39 +780,6 @@ extern void _bfd_x86_elf_link_report_relative_reloc
#define ELF_P_ALIGN ELF_MINPAGESIZE
-/* Return true if H is a __start_SECNAME/__stop_SECNAME symbol for the
- SECNAME section which has been garbage collected by --gc-sections
- -z start-stop-gc. */
-
-static inline bool
-elf_x86_start_stop_gc_p (struct bfd_link_info *link_info,
- struct elf_link_hash_entry *h)
-{
- if (h->start_stop
- && link_info->gc_sections
- && link_info->start_stop_gc)
- {
- asection *s = h->root.u.def.section;
-
- do
- {
- /* Return false if any SECNAME section is kept. */
- if (s->gc_mark)
- return false;
- s = bfd_get_next_section_by_name (s->owner, s);
- }
- while (s != NULL);
-
- /* Return true only if all SECNAME sections have been garbage
- collected. */
- return true;
- }
-
- /* Return false if H isn't a __start_SECNAME/__stop_SECNAME symbol or
- --gc-sections or -z start-stop-gc isn't used. */
- return false;
-}
-
/* Allocate x86 GOT info for local symbols. */
static inline bool
diff --git a/ld/testsuite/ld-i386/pr27491-1a.d b/ld/testsuite/ld-i386/pr27491-1a.d
index 006c176..39b25f6 100644
--- a/ld/testsuite/ld-i386/pr27491-1a.d
+++ b/ld/testsuite/ld-i386/pr27491-1a.d
@@ -9,6 +9,6 @@
Disassembly of section .text:
[a-f0-9]+ <foo>:
- +[a-f0-9]+: 8b 83 ([0-9a-f]{2} ){4}[ \t]+mov +-0x[a-f0-9]+\(%ebx\),%eax
- +[a-f0-9]+: 8b 83 ([0-9a-f]{2} ){4}[ \t]+mov +-0x[a-f0-9]+\(%ebx\),%eax
+ +[a-f0-9]+: c7 c0 00 00 00 00 mov \$0x0,%eax
+ +[a-f0-9]+: c7 c0 00 00 00 00 mov \$0x0,%eax
#pass
diff --git a/ld/testsuite/ld-x86-64/pr27491-1a.d b/ld/testsuite/ld-x86-64/pr27491-1a.d
index ade5c6f..215124c 100644
--- a/ld/testsuite/ld-x86-64/pr27491-1a.d
+++ b/ld/testsuite/ld-x86-64/pr27491-1a.d
@@ -9,6 +9,6 @@
Disassembly of section .text:
[a-f0-9]+ <foo>:
- +[a-f0-9]+: 48 8b 05 ([0-9a-f]{2} ){4}[ \t]+mov +0x[a-f0-9]+\(%rip\),%rax[ \t]+# [a-f0-9]+ <_DYNAMIC\+0x[a-f0-9]+>
- +[a-f0-9]+: 48 8b 05 ([0-9a-f]{2} ){4}[ \t]+mov +0x[a-f0-9]+\(%rip\),%rax[ \t]+# [a-f0-9]+ <_DYNAMIC\+0x[a-f0-9]+>
+ +[a-f0-9]+: 48 c7 c0 00 00 00 00 mov \$0x0,%rax
+ +[a-f0-9]+: 48 c7 c0 00 00 00 00 mov \$0x0,%rax
#pass