* [PATCH] Test also relocations for ARM unwinding section
@ 2016-09-11 9:31 Akihiko Odaki
2016-09-13 6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
0 siblings, 1 reply; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-11 9:31 UTC (permalink / raw)
To: binutils; +Cc: Paul Brook, Akihiko Odaki
As reported in PR binutils/20595, BFD has a bug that it doesn't delete
relocations for deleted exidx. This change allows the testsuite to find the
flaw.
---
ld/testsuite/ld-arm/unwind-4.d | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/ld/testsuite/ld-arm/unwind-4.d b/ld/testsuite/ld-arm/unwind-4.d
index 0a4427a..0bed0dc 100644
--- a/ld/testsuite/ld-arm/unwind-4.d
+++ b/ld/testsuite/ld-arm/unwind-4.d
@@ -1,9 +1,23 @@
-#ld: -T arm.ld
-#objdump: -s
+#ld: -q -T arm.ld
+#objdump: -sr
.*: file format.*
#...
+RELOCATION RECORDS FOR \[\.ARM\.exidx\]:
+OFFSET TYPE VALUE
+00000000 R_ARM_PREL31 \.text
+00000000 R_ARM_NONE __aeabi_unwind_cpp_pr0
+00000008 R_ARM_PREL31 \.text
+00000008 R_ARM_NONE __aeabi_unwind_cpp_pr1
+0000000c R_ARM_PREL31 \.text
+00000010 R_ARM_PREL31 \.text
+00000010 R_ARM_NONE __aeabi_unwind_cpp_pr0
+00000018 R_ARM_PREL31 \.text
+
+
+Contents of section .text:
+#...
Contents of section .ARM.exidx:
8020 (e0ffff7f b0b0a880 dcffff7f e8ffff7f|7fffffe0 80a8b0b0 7fffffdc 7fffffe8) .*
8030 (d8ffff7f b0b0a880 d8ffff7f 01000000|7fffffd8 80a8b0b0 7fffffd8 00000001) .*
--
2.9.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] ARM: Fix relocation of EXIDX sections
2016-09-11 9:31 [PATCH] Test also relocations for ARM unwinding section Akihiko Odaki
@ 2016-09-13 6:48 ` Akihiko Odaki
2016-09-13 7:16 ` Andreas Schwab
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-13 6:48 UTC (permalink / raw)
To: binutils; +Cc: Paul Brook, Yury Usishchev, Akihiko Odaki
As reported in PR binutils/20595, BFD has a bug that it doesn't delete
relocations for deleted exidx. This change fixes the behavior.
bfd * elf-bfd.h: Add callback to count relocations in the final output.
* elf-arm.c (elf32_arm_add_relocation): Deleted.
(elf32_arm_write_section): Move additional relocation to emit_relocs.
(elf32_arm_count_output_relocs): New function.
(emit_relocs): New function.
(elf32_arm_emit_relocs): New function.
(elf32_arm_vxworks_emit_relocs): New function.
(elf_backend_emit_relocs): Updated to use the new functions.
(elf_backend_count_output_relocs): New define.
* bfd/elflink.c (bfd_elf_final_link): Do not add additional_reloc_count
to the relocation count.
(_bfd_elf_link_size_reloc_section): Use callback to count the
relocations which will be in output.
(_bfd_elf_default_count_output_relocs): New function.
* bfd/elfxx-target.h (elf_backend_count_output_relocs): New define.
---
bfd/elf-bfd.h | 8 ++
bfd/elf32-arm.c | 257 +++++++++++++++++++++++++++++++++++++++++++----------
bfd/elflink.c | 60 +++++++++----
bfd/elfxx-target.h | 4 +
4 files changed, 264 insertions(+), 65 deletions(-)
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 163ef35..1c7aa5a 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1176,6 +1176,11 @@ struct elf_backend_data
unsigned int (*elf_backend_count_additional_relocs)
(asection *);
+ /* Count relocations to be output. The result may be different if the
+ input relocations are expected to be modified by the backend. */
+ unsigned int (* elf_backend_count_output_relocs)
+ (struct bfd_link_info *info, asection *o);
+
/* Say whether to sort relocs output by ld -r and ld --emit-relocs,
by r_offset. If NULL, default to true. */
bfd_boolean (*sort_relocs_p)
@@ -2143,6 +2148,9 @@ extern bfd_boolean _bfd_elf_link_output_relocs
(bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *,
struct elf_link_hash_entry **);
+extern unsigned int _bfd_elf_default_count_output_relocs
+ (struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o);
+
extern bfd_boolean _bfd_elf_adjust_dynamic_copy
(struct bfd_link_info *, struct elf_link_hash_entry *, asection *);
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 3d4a458..bda1c3f 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -17365,39 +17365,6 @@ stm32l4xx_create_replacing_stub (struct elf32_arm_link_hash_table * htab,
/* End of stm32l4xx work-around. */
-static void
-elf32_arm_add_relocation (bfd *output_bfd, struct bfd_link_info *info,
- asection *output_sec, Elf_Internal_Rela *rel)
-{
- BFD_ASSERT (output_sec && rel);
- struct bfd_elf_section_reloc_data *output_reldata;
- struct elf32_arm_link_hash_table *htab;
- struct bfd_elf_section_data *oesd = elf_section_data (output_sec);
- Elf_Internal_Shdr *rel_hdr;
-
-
- if (oesd->rel.hdr)
- {
- rel_hdr = oesd->rel.hdr;
- output_reldata = &(oesd->rel);
- }
- else if (oesd->rela.hdr)
- {
- rel_hdr = oesd->rela.hdr;
- output_reldata = &(oesd->rela);
- }
- else
- {
- abort ();
- }
-
- bfd_byte *erel = rel_hdr->contents;
- erel += output_reldata->count * rel_hdr->sh_entsize;
- htab = elf32_arm_hash_table (info);
- SWAP_RELOC_OUT (htab) (output_bfd, rel, erel);
- output_reldata->count++;
-}
-
/* Do code byteswapping. Return FALSE afterwards so that the section is
written out as normal. */
@@ -17649,18 +17616,6 @@ elf32_arm_write_section (bfd *output_bfd,
adjust offset by hand. */
prel31_offset = text_sec->output_offset
+ text_sec->size;
-
- /* New relocation entity. */
- asection *text_out = text_sec->output_section;
- Elf_Internal_Rela rel;
- rel.r_addend = 0;
- rel.r_offset = exidx_offset;
- rel.r_info = ELF32_R_INFO (text_out->target_index,
- R_ARM_PREL31);
-
- elf32_arm_add_relocation (output_bfd, link_info,
- sec->output_section,
- &rel);
}
/* First address we can't unwind. */
@@ -18175,6 +18130,69 @@ elf32_arm_count_additional_relocs (asection *sec)
return arm_data->additional_reloc_count;
}
+static unsigned int
+elf32_arm_count_output_relocs (struct bfd_link_info *info, asection *o)
+{
+ struct bfd_elf_section_data *esdo;
+ struct bfd_link_order *p;
+ bfd_size_type count;
+
+ esdo = elf_section_data (o->output_section);
+ if (esdo->this_hdr.sh_type != SHT_ARM_EXIDX)
+ return _bfd_elf_default_count_output_relocs (info, o);
+
+ count = 0;
+ for (p = o->map_head.link_order; p != NULL; p = p->next)
+ {
+ struct _arm_elf_section_data *arm_data;
+ arm_unwind_table_edit *edit_list;
+ Elf_Internal_Rela *relocs;
+ asection *sec;
+ unsigned int i;
+
+ if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ {
+ count++;
+ continue;
+ }
+
+ sec = p->u.indirect.section;
+ arm_data = get_arm_elf_section_data (sec);
+
+ if (arm_data->additional_reloc_count)
+ count += arm_data->additional_reloc_count;
+
+ edit_list = arm_data->u.exidx.unwind_edit_list;
+ if (!edit_list)
+ {
+ count += sec->reloc_count;
+ continue;
+ }
+
+ relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
+ info->keep_memory);
+
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ arm_unwind_table_edit *edit_node;
+ unsigned int index;
+
+ index = (relocs[i].r_offset - sec->vma) / 8;
+
+ for (edit_node = edit_list;
+ edit_node->next && edit_node->next->index > index;
+ edit_node++);
+
+ if (edit_node->type != DELETE_EXIDX_ENTRY ||
+ edit_node->index != index)
+ count++;
+ }
+ }
+
+ return count;
+}
+
/* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
has a type >= SHT_LOOS. Returns TRUE if these fields were initialised
FALSE otherwise. ISECTION is the best guess matching section from the
@@ -18303,6 +18321,139 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
sym->flags |= BSF_KEEP;
}
+static bfd_boolean
+emit_relocs (bfd *output_bfd,
+ asection *input_section,
+ Elf_Internal_Shdr *input_rel_hdr,
+ Elf_Internal_Rela *internal_relocs,
+ struct elf_link_hash_entry **rel_hash,
+ bfd_boolean (*fallback) (bfd *, asection *,
+ Elf_Internal_Shdr *,
+ Elf_Internal_Rela *,
+ struct elf_link_hash_entry **))
+{
+ _arm_elf_section_data *arm_data;
+ struct bfd_elf_section_reloc_data *output_reldata;
+ Elf_Internal_Shdr *output_rel_hdr;
+ Elf_Internal_Rela *irela;
+ Elf_Internal_Rela *irelaend;
+ asection *output_section;
+ const struct elf_backend_data *bed;
+ void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
+ struct bfd_elf_section_data *esdo;
+ arm_unwind_table_edit *edit_list, *edit_tail;
+ bfd_byte *erel;
+ bfd_vma offset;
+
+ arm_data = get_arm_elf_section_data (input_section);
+
+ if (!arm_data || arm_data->elf.this_hdr.sh_type != SHT_ARM_EXIDX)
+ goto fallback_label;
+
+ edit_list = arm_data->u.exidx.unwind_edit_list;
+ edit_tail = arm_data->u.exidx.unwind_edit_tail;
+
+ if (!edit_list)
+ goto fallback_label;
+
+ output_section = input_section->output_section;
+ offset = output_section->vma + input_section->output_offset;
+
+ bed = get_elf_backend_data (output_bfd);
+ esdo = elf_section_data (output_section);
+ if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+ {
+ output_reldata = &esdo->rel;
+ swap_out = bed->s->swap_reloc_out;
+ }
+ else if (esdo->rela.hdr &&
+ esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+ {
+ output_reldata = &esdo->rela;
+ swap_out = bed->s->swap_reloca_out;
+ }
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%B: relocation size mismatch in %B section %A"),
+ output_bfd, input_section->owner, input_section);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ output_rel_hdr = output_reldata->hdr;
+ erel = output_rel_hdr->contents;
+ erel += output_reldata->count * input_rel_hdr->sh_entsize;
+
+ irela = internal_relocs;
+ irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+ * bed->s->int_rels_per_ext_rel);
+ while (irela < irelaend)
+ {
+ arm_unwind_table_edit *edit_node, *edit_next;
+ Elf_Internal_Rela rel;
+ bfd_vma bias;
+ bfd_vma index;
+
+ index = (irela->r_offset - offset) / 8;
+
+ bias = 0;
+ edit_node = edit_list;
+ for (edit_next = edit_list;
+ edit_next && edit_next->index <= index;
+ edit_next = edit_node->next)
+ {
+ bias++;
+ edit_node = edit_next;
+ }
+
+ if (edit_node->type != DELETE_EXIDX_ENTRY || edit_node->index != index)
+ {
+ rel.r_offset = irela->r_offset - bias * 8;
+ rel.r_info = irela->r_info;
+ rel.r_addend = irela->r_addend;
+
+ (*swap_out) (output_bfd, &rel, erel);
+ erel += output_rel_hdr->sh_entsize;
+ output_reldata->count++;
+ }
+
+ irela += bed->s->int_rels_per_ext_rel;
+ }
+
+ if (edit_tail->type == INSERT_EXIDX_CANTUNWIND_AT_END)
+ {
+ /* New relocation entity. */
+ asection *text_sec = edit_tail->linked_section;
+ asection *text_out = text_sec->output_section;
+ bfd_vma exidx_offset = offset + input_section->size - 8;
+ Elf_Internal_Rela rel;
+
+ rel.r_addend = 0;
+ rel.r_offset = exidx_offset;
+ rel.r_info = ELF32_R_INFO (text_out->target_index, R_ARM_PREL31);
+ (*swap_out) (output_bfd, &rel, erel);
+ output_reldata->count++;
+ }
+
+ return TRUE;
+
+fallback_label:
+ return fallback (output_bfd, input_section, input_rel_hdr,
+ internal_relocs, rel_hash);
+}
+
+static bfd_boolean
+elf32_arm_emit_relocs (bfd *output_bfd,
+ asection *input_section,
+ Elf_Internal_Shdr *input_rel_hdr,
+ Elf_Internal_Rela *internal_relocs,
+ struct elf_link_hash_entry **rel_hash)
+{
+ return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+ rel_hash, _bfd_elf_link_output_relocs);
+}
+
#undef elf_backend_copy_special_section_fields
#define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields
@@ -18333,6 +18484,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
#define bfd_elf32_bfd_final_link elf32_arm_final_link
#define bfd_elf32_get_synthetic_symtab elf32_arm_get_synthetic_symtab
+#define elf_backend_emit_relocs elf32_arm_emit_relocs
#define elf_backend_get_symbol_type elf32_arm_get_symbol_type
#define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook
#define elf_backend_gc_mark_extra_sections elf32_arm_gc_mark_extra_sections
@@ -18361,6 +18513,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
#define elf_backend_begin_write_processing elf32_arm_begin_write_processing
#define elf_backend_add_symbol_hook elf32_arm_add_symbol_hook
#define elf_backend_count_additional_relocs elf32_arm_count_additional_relocs
+#define elf_backend_count_output_relocs elf32_arm_count_output_relocs
#define elf_backend_symbol_processing elf32_arm_backend_symbol_processing
#define elf_backend_can_refcount 1
@@ -18527,6 +18680,17 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
elf_vxworks_final_write_processing (abfd, linker);
}
+static bfd_boolean
+elf32_arm_vxworks_emit_relocs (bfd *output_bfd,
+ asection *input_section,
+ Elf_Internal_Shdr *input_rel_hdr,
+ Elf_Internal_Rela *internal_relocs,
+ struct elf_link_hash_entry **rel_hash)
+{
+ return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+ rel_hash, elf_vxworks_emit_relocs);
+}
+
#undef elf32_bed
#define elf32_bed elf32_arm_vxworks_bed
@@ -18535,7 +18699,7 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
#undef elf_backend_final_write_processing
#define elf_backend_final_write_processing elf32_arm_vxworks_final_write_processing
#undef elf_backend_emit_relocs
-#define elf_backend_emit_relocs elf_vxworks_emit_relocs
+#define elf_backend_emit_relocs elf32_arm_vxworks_emit_relocs
#undef elf_backend_may_use_rel_p
#define elf_backend_may_use_rel_p 0
@@ -18899,6 +19063,7 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
(SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
#undef elf_backend_emit_relocs
+#define elf_backend_emit_relocs elf32_arm_emit_relocs
#undef bfd_elf32_bfd_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_create elf32_arm_symbian_link_hash_table_create
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 3e24940..0f6fae7 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2447,13 +2447,29 @@ _bfd_elf_link_read_relocs (bfd *abfd,
section header for a section containing relocations for O. */
static bfd_boolean
-_bfd_elf_link_size_reloc_section (bfd *abfd,
- struct bfd_elf_section_reloc_data *reldata)
+_bfd_elf_link_size_reloc_section (bfd *abfd, struct bfd_link_info *info,
+ asection *o)
{
- Elf_Internal_Shdr *rel_hdr = reldata->hdr;
+ struct bfd_elf_section_data *esdo;
+ const struct elf_backend_data *bed;
+ struct bfd_elf_section_reloc_data *reldata;
+ Elf_Internal_Shdr *rel_hdr;
+ unsigned int count;
+
+ esdo = elf_section_data (o);
+ if (esdo->rel.hdr)
+ reldata = &esdo->rel;
+ else if (esdo->rela.hdr)
+ reldata = &esdo->rela;
+ else
+ return TRUE;
+
+ rel_hdr = reldata->hdr;
/* That allows us to calculate the size of the section. */
- rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
+ bed = get_elf_backend_data (abfd);
+ count = (*bed->elf_backend_count_output_relocs) (info, o);
+ rel_hdr->sh_size = count * rel_hdr->sh_entsize;
/* The contents field must last into write_object_contents, so we
allocate it with bfd_alloc rather than malloc. Also since we
@@ -2541,6 +2557,24 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
return TRUE;
}
+
+unsigned int
+_bfd_elf_default_count_output_relocs (
+ struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o)
+{
+ struct bfd_elf_section_data *esdo;
+ struct bfd_elf_section_reloc_data *reldata;
+
+ esdo = elf_section_data (o);
+ if (esdo->rel.hdr)
+ reldata = &esdo->rel;
+ else if (esdo->rela.hdr)
+ reldata = &esdo->rela;
+ else
+ return TRUE;
+
+ return reldata->count;
+}
\f
/* Make weak undefined symbols in PIE dynamic. */
@@ -11182,12 +11216,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
for (o = abfd->sections; o != NULL; o = o->next)
{
struct bfd_elf_section_data *esdo = elf_section_data (o);
+ unsigned int additional_reloc_count = 0;
o->reloc_count = 0;
for (p = o->map_head.link_order; p != NULL; p = p->next)
{
unsigned int reloc_count = 0;
- unsigned int additional_reloc_count = 0;
struct bfd_elf_section_data *esdi = NULL;
if (p->type == bfd_section_reloc_link_order
@@ -11273,21 +11307,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
if (reloc_count == 0)
continue;
- reloc_count += additional_reloc_count;
o->reloc_count += reloc_count;
if (p->type == bfd_indirect_link_order && emit_relocs)
{
if (esdi->rel.hdr)
- {
esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
- esdo->rel.count += additional_reloc_count;
- }
if (esdi->rela.hdr)
- {
esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
- esdo->rela.count += additional_reloc_count;
- }
}
else
{
@@ -11298,7 +11325,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
}
}
- if (o->reloc_count > 0)
+ if (o->reloc_count > 0 || additional_reloc_count > 0)
o->flags |= SEC_RELOC;
else
{
@@ -11335,12 +11362,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
struct bfd_elf_section_data *esdo = elf_section_data (o);
if ((o->flags & SEC_RELOC) != 0)
{
- if (esdo->rel.hdr
- && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
- goto error_return;
-
- if (esdo->rela.hdr
- && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
+ if (!(_bfd_elf_link_size_reloc_section (abfd, info, o)))
goto error_return;
}
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 97aa5e6..5424cf3 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -551,6 +551,9 @@
#ifndef elf_backend_count_additional_relocs
#define elf_backend_count_additional_relocs NULL
#endif
+#ifndef elf_backend_count_output_relocs
+#define elf_backend_count_output_relocs _bfd_elf_default_count_output_relocs
+#endif
#ifndef elf_backend_sort_relocs_p
#define elf_backend_sort_relocs_p NULL
#endif
@@ -773,6 +776,7 @@ static struct elf_backend_data elfNN_bed =
elf_backend_emit_relocs,
elf_backend_count_relocs,
elf_backend_count_additional_relocs,
+ elf_backend_count_output_relocs,
elf_backend_sort_relocs_p,
elf_backend_grok_prstatus,
elf_backend_grok_psinfo,
--
2.9.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] ARM: Fix relocation of EXIDX sections
2016-09-13 6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
@ 2016-09-13 7:16 ` Andreas Schwab
2016-09-13 10:04 ` [PATH v2] " Akihiko Odaki
2016-09-23 5:46 ` [PATCH] " Akihiko Odaki
2 siblings, 0 replies; 8+ messages in thread
From: Andreas Schwab @ 2016-09-13 7:16 UTC (permalink / raw)
To: Akihiko Odaki; +Cc: binutils, Paul Brook, Yury Usishchev
On Sep 13 2016, Akihiko Odaki <akihiko.odaki.4i@stu.hosei.ac.jp> wrote:
> +unsigned int
> +_bfd_elf_default_count_output_relocs (
> + struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o)
> +{
> + struct bfd_elf_section_data *esdo;
> + struct bfd_elf_section_reloc_data *reldata;
> +
> + esdo = elf_section_data (o);
> + if (esdo->rel.hdr)
> + reldata = &esdo->rel;
> + else if (esdo->rela.hdr)
> + reldata = &esdo->rela;
> + else
> + return TRUE;
Returning TRUE in a function that returns a number doesn't make sense.
Andreas.
--
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATH v2] ARM: Fix relocation of EXIDX sections
2016-09-13 6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
2016-09-13 7:16 ` Andreas Schwab
@ 2016-09-13 10:04 ` Akihiko Odaki
2016-09-22 16:04 ` Nick Clifton
2016-09-23 5:46 ` [PATCH] " Akihiko Odaki
2 siblings, 1 reply; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-13 10:04 UTC (permalink / raw)
To: binutils; +Cc: Andreas Schwab, Paul Brook, Yury Usishchev, Akihiko Odaki
As reported in PR binutils/20595, BFD has a bug that it doesn't delete
relocations for deleted exidx. This change fixes the behavior.
bfd * elf-bfd.h: Add callback to count relocations in the final output.
* elf-arm.c (elf32_arm_add_relocation): Deleted.
(elf32_arm_write_section): Move additional relocation to emit_relocs.
(elf32_arm_count_output_relocs): New function.
(emit_relocs): New function.
(elf32_arm_emit_relocs): New function.
(elf32_arm_vxworks_emit_relocs): New function.
(elf_backend_emit_relocs): Updated to use the new functions.
(elf_backend_count_output_relocs): New define.
* bfd/elflink.c (bfd_elf_final_link): Do not add additional_reloc_count
to the relocation count.
(_bfd_elf_link_size_reloc_section): Use callback to count the
relocations which will be in output.
(_bfd_elf_default_count_output_relocs): New function.
* bfd/elfxx-target.h (elf_backend_count_output_relocs): New define.
---
bfd/elf-bfd.h | 8 ++
bfd/elf32-arm.c | 257 +++++++++++++++++++++++++++++++++++++++++++----------
bfd/elflink.c | 60 +++++++++----
bfd/elfxx-target.h | 4 +
4 files changed, 264 insertions(+), 65 deletions(-)
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 163ef35..1c7aa5a 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1176,6 +1176,11 @@ struct elf_backend_data
unsigned int (*elf_backend_count_additional_relocs)
(asection *);
+ /* Count relocations to be output. The result may be different if the
+ input relocations are expected to be modified by the backend. */
+ unsigned int (* elf_backend_count_output_relocs)
+ (struct bfd_link_info *info, asection *o);
+
/* Say whether to sort relocs output by ld -r and ld --emit-relocs,
by r_offset. If NULL, default to true. */
bfd_boolean (*sort_relocs_p)
@@ -2143,6 +2148,9 @@ extern bfd_boolean _bfd_elf_link_output_relocs
(bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *,
struct elf_link_hash_entry **);
+extern unsigned int _bfd_elf_default_count_output_relocs
+ (struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o);
+
extern bfd_boolean _bfd_elf_adjust_dynamic_copy
(struct bfd_link_info *, struct elf_link_hash_entry *, asection *);
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 3d4a458..bda1c3f 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -17365,39 +17365,6 @@ stm32l4xx_create_replacing_stub (struct elf32_arm_link_hash_table * htab,
/* End of stm32l4xx work-around. */
-static void
-elf32_arm_add_relocation (bfd *output_bfd, struct bfd_link_info *info,
- asection *output_sec, Elf_Internal_Rela *rel)
-{
- BFD_ASSERT (output_sec && rel);
- struct bfd_elf_section_reloc_data *output_reldata;
- struct elf32_arm_link_hash_table *htab;
- struct bfd_elf_section_data *oesd = elf_section_data (output_sec);
- Elf_Internal_Shdr *rel_hdr;
-
-
- if (oesd->rel.hdr)
- {
- rel_hdr = oesd->rel.hdr;
- output_reldata = &(oesd->rel);
- }
- else if (oesd->rela.hdr)
- {
- rel_hdr = oesd->rela.hdr;
- output_reldata = &(oesd->rela);
- }
- else
- {
- abort ();
- }
-
- bfd_byte *erel = rel_hdr->contents;
- erel += output_reldata->count * rel_hdr->sh_entsize;
- htab = elf32_arm_hash_table (info);
- SWAP_RELOC_OUT (htab) (output_bfd, rel, erel);
- output_reldata->count++;
-}
-
/* Do code byteswapping. Return FALSE afterwards so that the section is
written out as normal. */
@@ -17649,18 +17616,6 @@ elf32_arm_write_section (bfd *output_bfd,
adjust offset by hand. */
prel31_offset = text_sec->output_offset
+ text_sec->size;
-
- /* New relocation entity. */
- asection *text_out = text_sec->output_section;
- Elf_Internal_Rela rel;
- rel.r_addend = 0;
- rel.r_offset = exidx_offset;
- rel.r_info = ELF32_R_INFO (text_out->target_index,
- R_ARM_PREL31);
-
- elf32_arm_add_relocation (output_bfd, link_info,
- sec->output_section,
- &rel);
}
/* First address we can't unwind. */
@@ -18175,6 +18130,69 @@ elf32_arm_count_additional_relocs (asection *sec)
return arm_data->additional_reloc_count;
}
+static unsigned int
+elf32_arm_count_output_relocs (struct bfd_link_info *info, asection *o)
+{
+ struct bfd_elf_section_data *esdo;
+ struct bfd_link_order *p;
+ bfd_size_type count;
+
+ esdo = elf_section_data (o->output_section);
+ if (esdo->this_hdr.sh_type != SHT_ARM_EXIDX)
+ return _bfd_elf_default_count_output_relocs (info, o);
+
+ count = 0;
+ for (p = o->map_head.link_order; p != NULL; p = p->next)
+ {
+ struct _arm_elf_section_data *arm_data;
+ arm_unwind_table_edit *edit_list;
+ Elf_Internal_Rela *relocs;
+ asection *sec;
+ unsigned int i;
+
+ if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ {
+ count++;
+ continue;
+ }
+
+ sec = p->u.indirect.section;
+ arm_data = get_arm_elf_section_data (sec);
+
+ if (arm_data->additional_reloc_count)
+ count += arm_data->additional_reloc_count;
+
+ edit_list = arm_data->u.exidx.unwind_edit_list;
+ if (!edit_list)
+ {
+ count += sec->reloc_count;
+ continue;
+ }
+
+ relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
+ info->keep_memory);
+
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ arm_unwind_table_edit *edit_node;
+ unsigned int index;
+
+ index = (relocs[i].r_offset - sec->vma) / 8;
+
+ for (edit_node = edit_list;
+ edit_node->next && edit_node->next->index > index;
+ edit_node++);
+
+ if (edit_node->type != DELETE_EXIDX_ENTRY ||
+ edit_node->index != index)
+ count++;
+ }
+ }
+
+ return count;
+}
+
/* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
has a type >= SHT_LOOS. Returns TRUE if these fields were initialised
FALSE otherwise. ISECTION is the best guess matching section from the
@@ -18303,6 +18321,139 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
sym->flags |= BSF_KEEP;
}
+static bfd_boolean
+emit_relocs (bfd *output_bfd,
+ asection *input_section,
+ Elf_Internal_Shdr *input_rel_hdr,
+ Elf_Internal_Rela *internal_relocs,
+ struct elf_link_hash_entry **rel_hash,
+ bfd_boolean (*fallback) (bfd *, asection *,
+ Elf_Internal_Shdr *,
+ Elf_Internal_Rela *,
+ struct elf_link_hash_entry **))
+{
+ _arm_elf_section_data *arm_data;
+ struct bfd_elf_section_reloc_data *output_reldata;
+ Elf_Internal_Shdr *output_rel_hdr;
+ Elf_Internal_Rela *irela;
+ Elf_Internal_Rela *irelaend;
+ asection *output_section;
+ const struct elf_backend_data *bed;
+ void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
+ struct bfd_elf_section_data *esdo;
+ arm_unwind_table_edit *edit_list, *edit_tail;
+ bfd_byte *erel;
+ bfd_vma offset;
+
+ arm_data = get_arm_elf_section_data (input_section);
+
+ if (!arm_data || arm_data->elf.this_hdr.sh_type != SHT_ARM_EXIDX)
+ goto fallback_label;
+
+ edit_list = arm_data->u.exidx.unwind_edit_list;
+ edit_tail = arm_data->u.exidx.unwind_edit_tail;
+
+ if (!edit_list)
+ goto fallback_label;
+
+ output_section = input_section->output_section;
+ offset = output_section->vma + input_section->output_offset;
+
+ bed = get_elf_backend_data (output_bfd);
+ esdo = elf_section_data (output_section);
+ if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+ {
+ output_reldata = &esdo->rel;
+ swap_out = bed->s->swap_reloc_out;
+ }
+ else if (esdo->rela.hdr &&
+ esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+ {
+ output_reldata = &esdo->rela;
+ swap_out = bed->s->swap_reloca_out;
+ }
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%B: relocation size mismatch in %B section %A"),
+ output_bfd, input_section->owner, input_section);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ output_rel_hdr = output_reldata->hdr;
+ erel = output_rel_hdr->contents;
+ erel += output_reldata->count * input_rel_hdr->sh_entsize;
+
+ irela = internal_relocs;
+ irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+ * bed->s->int_rels_per_ext_rel);
+ while (irela < irelaend)
+ {
+ arm_unwind_table_edit *edit_node, *edit_next;
+ Elf_Internal_Rela rel;
+ bfd_vma bias;
+ bfd_vma index;
+
+ index = (irela->r_offset - offset) / 8;
+
+ bias = 0;
+ edit_node = edit_list;
+ for (edit_next = edit_list;
+ edit_next && edit_next->index <= index;
+ edit_next = edit_node->next)
+ {
+ bias++;
+ edit_node = edit_next;
+ }
+
+ if (edit_node->type != DELETE_EXIDX_ENTRY || edit_node->index != index)
+ {
+ rel.r_offset = irela->r_offset - bias * 8;
+ rel.r_info = irela->r_info;
+ rel.r_addend = irela->r_addend;
+
+ (*swap_out) (output_bfd, &rel, erel);
+ erel += output_rel_hdr->sh_entsize;
+ output_reldata->count++;
+ }
+
+ irela += bed->s->int_rels_per_ext_rel;
+ }
+
+ if (edit_tail->type == INSERT_EXIDX_CANTUNWIND_AT_END)
+ {
+ /* New relocation entity. */
+ asection *text_sec = edit_tail->linked_section;
+ asection *text_out = text_sec->output_section;
+ bfd_vma exidx_offset = offset + input_section->size - 8;
+ Elf_Internal_Rela rel;
+
+ rel.r_addend = 0;
+ rel.r_offset = exidx_offset;
+ rel.r_info = ELF32_R_INFO (text_out->target_index, R_ARM_PREL31);
+ (*swap_out) (output_bfd, &rel, erel);
+ output_reldata->count++;
+ }
+
+ return TRUE;
+
+fallback_label:
+ return fallback (output_bfd, input_section, input_rel_hdr,
+ internal_relocs, rel_hash);
+}
+
+static bfd_boolean
+elf32_arm_emit_relocs (bfd *output_bfd,
+ asection *input_section,
+ Elf_Internal_Shdr *input_rel_hdr,
+ Elf_Internal_Rela *internal_relocs,
+ struct elf_link_hash_entry **rel_hash)
+{
+ return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+ rel_hash, _bfd_elf_link_output_relocs);
+}
+
#undef elf_backend_copy_special_section_fields
#define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields
@@ -18333,6 +18484,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
#define bfd_elf32_bfd_final_link elf32_arm_final_link
#define bfd_elf32_get_synthetic_symtab elf32_arm_get_synthetic_symtab
+#define elf_backend_emit_relocs elf32_arm_emit_relocs
#define elf_backend_get_symbol_type elf32_arm_get_symbol_type
#define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook
#define elf_backend_gc_mark_extra_sections elf32_arm_gc_mark_extra_sections
@@ -18361,6 +18513,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
#define elf_backend_begin_write_processing elf32_arm_begin_write_processing
#define elf_backend_add_symbol_hook elf32_arm_add_symbol_hook
#define elf_backend_count_additional_relocs elf32_arm_count_additional_relocs
+#define elf_backend_count_output_relocs elf32_arm_count_output_relocs
#define elf_backend_symbol_processing elf32_arm_backend_symbol_processing
#define elf_backend_can_refcount 1
@@ -18527,6 +18680,17 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
elf_vxworks_final_write_processing (abfd, linker);
}
+static bfd_boolean
+elf32_arm_vxworks_emit_relocs (bfd *output_bfd,
+ asection *input_section,
+ Elf_Internal_Shdr *input_rel_hdr,
+ Elf_Internal_Rela *internal_relocs,
+ struct elf_link_hash_entry **rel_hash)
+{
+ return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+ rel_hash, elf_vxworks_emit_relocs);
+}
+
#undef elf32_bed
#define elf32_bed elf32_arm_vxworks_bed
@@ -18535,7 +18699,7 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
#undef elf_backend_final_write_processing
#define elf_backend_final_write_processing elf32_arm_vxworks_final_write_processing
#undef elf_backend_emit_relocs
-#define elf_backend_emit_relocs elf_vxworks_emit_relocs
+#define elf_backend_emit_relocs elf32_arm_vxworks_emit_relocs
#undef elf_backend_may_use_rel_p
#define elf_backend_may_use_rel_p 0
@@ -18899,6 +19063,7 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
(SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
#undef elf_backend_emit_relocs
+#define elf_backend_emit_relocs elf32_arm_emit_relocs
#undef bfd_elf32_bfd_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_create elf32_arm_symbian_link_hash_table_create
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 3e24940..1d0e3ab 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2447,13 +2447,29 @@ _bfd_elf_link_read_relocs (bfd *abfd,
section header for a section containing relocations for O. */
static bfd_boolean
-_bfd_elf_link_size_reloc_section (bfd *abfd,
- struct bfd_elf_section_reloc_data *reldata)
+_bfd_elf_link_size_reloc_section (bfd *abfd, struct bfd_link_info *info,
+ asection *o)
{
- Elf_Internal_Shdr *rel_hdr = reldata->hdr;
+ struct bfd_elf_section_data *esdo;
+ const struct elf_backend_data *bed;
+ struct bfd_elf_section_reloc_data *reldata;
+ Elf_Internal_Shdr *rel_hdr;
+ unsigned int count;
+
+ esdo = elf_section_data (o);
+ if (esdo->rel.hdr)
+ reldata = &esdo->rel;
+ else if (esdo->rela.hdr)
+ reldata = &esdo->rela;
+ else
+ return TRUE;
+
+ rel_hdr = reldata->hdr;
/* That allows us to calculate the size of the section. */
- rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
+ bed = get_elf_backend_data (abfd);
+ count = (*bed->elf_backend_count_output_relocs) (info, o);
+ rel_hdr->sh_size = count * rel_hdr->sh_entsize;
/* The contents field must last into write_object_contents, so we
allocate it with bfd_alloc rather than malloc. Also since we
@@ -2541,6 +2557,24 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
return TRUE;
}
+
+unsigned int
+_bfd_elf_default_count_output_relocs (
+ struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o)
+{
+ struct bfd_elf_section_data *esdo;
+ struct bfd_elf_section_reloc_data *reldata;
+
+ esdo = elf_section_data (o);
+ if (esdo->rel.hdr)
+ reldata = &esdo->rel;
+ else if (esdo->rela.hdr)
+ reldata = &esdo->rela;
+ else
+ abort ();
+
+ return reldata->count;
+}
\f
/* Make weak undefined symbols in PIE dynamic. */
@@ -11182,12 +11216,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
for (o = abfd->sections; o != NULL; o = o->next)
{
struct bfd_elf_section_data *esdo = elf_section_data (o);
+ unsigned int additional_reloc_count = 0;
o->reloc_count = 0;
for (p = o->map_head.link_order; p != NULL; p = p->next)
{
unsigned int reloc_count = 0;
- unsigned int additional_reloc_count = 0;
struct bfd_elf_section_data *esdi = NULL;
if (p->type == bfd_section_reloc_link_order
@@ -11273,21 +11307,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
if (reloc_count == 0)
continue;
- reloc_count += additional_reloc_count;
o->reloc_count += reloc_count;
if (p->type == bfd_indirect_link_order && emit_relocs)
{
if (esdi->rel.hdr)
- {
esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
- esdo->rel.count += additional_reloc_count;
- }
if (esdi->rela.hdr)
- {
esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
- esdo->rela.count += additional_reloc_count;
- }
}
else
{
@@ -11298,7 +11325,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
}
}
- if (o->reloc_count > 0)
+ if (o->reloc_count > 0 || additional_reloc_count > 0)
o->flags |= SEC_RELOC;
else
{
@@ -11335,12 +11362,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
struct bfd_elf_section_data *esdo = elf_section_data (o);
if ((o->flags & SEC_RELOC) != 0)
{
- if (esdo->rel.hdr
- && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
- goto error_return;
-
- if (esdo->rela.hdr
- && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
+ if (!(_bfd_elf_link_size_reloc_section (abfd, info, o)))
goto error_return;
}
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 97aa5e6..5424cf3 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -551,6 +551,9 @@
#ifndef elf_backend_count_additional_relocs
#define elf_backend_count_additional_relocs NULL
#endif
+#ifndef elf_backend_count_output_relocs
+#define elf_backend_count_output_relocs _bfd_elf_default_count_output_relocs
+#endif
#ifndef elf_backend_sort_relocs_p
#define elf_backend_sort_relocs_p NULL
#endif
@@ -773,6 +776,7 @@ static struct elf_backend_data elfNN_bed =
elf_backend_emit_relocs,
elf_backend_count_relocs,
elf_backend_count_additional_relocs,
+ elf_backend_count_output_relocs,
elf_backend_sort_relocs_p,
elf_backend_grok_prstatus,
elf_backend_grok_psinfo,
--
2.9.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATH v2] ARM: Fix relocation of EXIDX sections
2016-09-13 10:04 ` [PATH v2] " Akihiko Odaki
@ 2016-09-22 16:04 ` Nick Clifton
0 siblings, 0 replies; 8+ messages in thread
From: Nick Clifton @ 2016-09-22 16:04 UTC (permalink / raw)
To: Akihiko Odaki, binutils; +Cc: Andreas Schwab, Paul Brook, Yury Usishchev
Hi Akihiko-san,
> As reported in PR binutils/20595, BFD has a bug that it doesn't delete
> relocations for deleted exidx. This change fixes the behavior.
Unfortunately when I tried out this patch, it introduced a segmentation
fault into the linker if you build for the tic6-elf target. (Try running
the linker testcase ld-tic6x/pcrel-reloc-local to see this happen). The
TIC6X target mixes both REL and RELA type relocs, which I presume is part
of the problem. Please could you investigate and fix this issue.
Cheers
Nick
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] ARM: Fix relocation of EXIDX sections
2016-09-13 6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
2016-09-13 7:16 ` Andreas Schwab
2016-09-13 10:04 ` [PATH v2] " Akihiko Odaki
@ 2016-09-23 5:46 ` Akihiko Odaki
2016-09-23 5:49 ` Akihiko Odaki
2 siblings, 1 reply; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-23 5:46 UTC (permalink / raw)
To: binutils
Cc: Nick Clifton, Andreas Schwab, Paul Brook, Yury Usishchev, Akihiko Odaki
As reported in PR binutils/20595, BFD has a bug that it doesn't delete
relocations for deleted exidx. This change fixes the behavior.
bfd * elf-bfd.h: Add callback to count relocations in the final output.
* elf-arm.c (elf32_arm_add_relocation): Deleted.
(elf32_arm_write_section): Move additional relocation to emit_relocs.
(elf32_arm_count_output_relocs): New function.
(emit_relocs): New function.
(elf32_arm_emit_relocs): New function.
(elf32_arm_vxworks_emit_relocs): New function.
(elf_backend_emit_relocs): Updated to use the new functions.
(elf_backend_count_output_relocs): New define.
* bfd/elflink.c (bfd_elf_final_link): Do not add additional_reloc_count
to the relocation count.
(_bfd_elf_link_size_reloc_section): Use callback to count the
relocations which will be in output.
(_bfd_elf_default_count_output_relocs): New function.
* bfd/elfxx-target.h (elf_backend_count_output_relocs): New define.
---
bfd/elf-bfd.h | 8 ++
bfd/elf32-arm.c | 262 +++++++++++++++++++++++++++++++++++++++++++----------
bfd/elflink.c | 46 +++++++---
bfd/elfxx-target.h | 4 +
4 files changed, 259 insertions(+), 61 deletions(-)
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 163ef35..2f2b42c 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1176,6 +1176,11 @@ struct elf_backend_data
unsigned int (*elf_backend_count_additional_relocs)
(asection *);
+ /* Count relocations to be output. The result may be different if the
+ input relocations are expected to be modified by the backend. */
+ unsigned int (* elf_backend_count_output_relocs)
+ (struct bfd_link_info *info, asection *o, bfd_boolean rela);
+
/* Say whether to sort relocs output by ld -r and ld --emit-relocs,
by r_offset. If NULL, default to true. */
bfd_boolean (*sort_relocs_p)
@@ -2143,6 +2148,9 @@ extern bfd_boolean _bfd_elf_link_output_relocs
(bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *,
struct elf_link_hash_entry **);
+extern unsigned int _bfd_elf_default_count_output_relocs
+ (struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o, bfd_boolean rela);
+
extern bfd_boolean _bfd_elf_adjust_dynamic_copy
(struct bfd_link_info *, struct elf_link_hash_entry *, asection *);
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 3d4a458..28c6fb1 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -17365,39 +17365,6 @@ stm32l4xx_create_replacing_stub (struct elf32_arm_link_hash_table * htab,
/* End of stm32l4xx work-around. */
-static void
-elf32_arm_add_relocation (bfd *output_bfd, struct bfd_link_info *info,
- asection *output_sec, Elf_Internal_Rela *rel)
-{
- BFD_ASSERT (output_sec && rel);
- struct bfd_elf_section_reloc_data *output_reldata;
- struct elf32_arm_link_hash_table *htab;
- struct bfd_elf_section_data *oesd = elf_section_data (output_sec);
- Elf_Internal_Shdr *rel_hdr;
-
-
- if (oesd->rel.hdr)
- {
- rel_hdr = oesd->rel.hdr;
- output_reldata = &(oesd->rel);
- }
- else if (oesd->rela.hdr)
- {
- rel_hdr = oesd->rela.hdr;
- output_reldata = &(oesd->rela);
- }
- else
- {
- abort ();
- }
-
- bfd_byte *erel = rel_hdr->contents;
- erel += output_reldata->count * rel_hdr->sh_entsize;
- htab = elf32_arm_hash_table (info);
- SWAP_RELOC_OUT (htab) (output_bfd, rel, erel);
- output_reldata->count++;
-}
-
/* Do code byteswapping. Return FALSE afterwards so that the section is
written out as normal. */
@@ -17649,18 +17616,6 @@ elf32_arm_write_section (bfd *output_bfd,
adjust offset by hand. */
prel31_offset = text_sec->output_offset
+ text_sec->size;
-
- /* New relocation entity. */
- asection *text_out = text_sec->output_section;
- Elf_Internal_Rela rel;
- rel.r_addend = 0;
- rel.r_offset = exidx_offset;
- rel.r_info = ELF32_R_INFO (text_out->target_index,
- R_ARM_PREL31);
-
- elf32_arm_add_relocation (output_bfd, link_info,
- sec->output_section,
- &rel);
}
/* First address we can't unwind. */
@@ -18175,6 +18130,74 @@ elf32_arm_count_additional_relocs (asection *sec)
return arm_data->additional_reloc_count;
}
+static unsigned int
+elf32_arm_count_output_relocs (struct bfd_link_info *info, asection *o,
+ bfd_boolean rela)
+{
+ struct bfd_elf_section_data *esdo;
+ struct bfd_link_order *p;
+ bfd_size_type count;
+
+ esdo = elf_section_data (o->output_section);
+ if (esdo->this_hdr.sh_type != SHT_ARM_EXIDX)
+ return _bfd_elf_default_count_output_relocs (info, o, rela);
+
+ count = 0;
+ for (p = o->map_head.link_order; p != NULL; p = p->next)
+ {
+ struct _arm_elf_section_data *arm_data;
+ arm_unwind_table_edit *edit_list;
+ Elf_Internal_Rela *relocs;
+ asection *sec;
+ bfd_size_type num_rel;
+ bfd_size_type num_rela;
+ unsigned int i;
+
+ if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ {
+ count++;
+ continue;
+ }
+
+ sec = p->u.indirect.section;
+ arm_data = get_arm_elf_section_data (sec);
+
+ if (arm_data->additional_reloc_count)
+ count += arm_data->additional_reloc_count;
+
+ edit_list = arm_data->u.exidx.unwind_edit_list;
+ if (!edit_list)
+ {
+ count += sec->reloc_count;
+ continue;
+ }
+
+ relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
+ info->keep_memory);
+ num_rel = esdo->rel.hdr ? NUM_SHDR_ENTRIES (esdo->rel.hdr) : 0;
+ num_rela = esdo->rela.hdr ? NUM_SHDR_ENTRIES (esdo->rela.hdr) : 0;
+
+ for (i = rela ? num_rel : 0; i < (rela ? num_rela : num_rel); i++)
+ {
+ arm_unwind_table_edit *edit_node;
+ unsigned int index;
+
+ index = (relocs[i].r_offset - sec->vma) / 8;
+
+ for (edit_node = edit_list;
+ edit_node->next && edit_node->next->index > index;
+ edit_node++);
+
+ if (edit_node->type != DELETE_EXIDX_ENTRY ||
+ edit_node->index != index)
+ count++;
+ }
+ }
+
+ return count;
+}
+
/* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
has a type >= SHT_LOOS. Returns TRUE if these fields were initialised
FALSE otherwise. ISECTION is the best guess matching section from the
@@ -18303,6 +18326,139 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
sym->flags |= BSF_KEEP;
}
+static bfd_boolean
+emit_relocs (bfd *output_bfd,
+ asection *input_section,
+ Elf_Internal_Shdr *input_rel_hdr,
+ Elf_Internal_Rela *internal_relocs,
+ struct elf_link_hash_entry **rel_hash,
+ bfd_boolean (*fallback) (bfd *, asection *,
+ Elf_Internal_Shdr *,
+ Elf_Internal_Rela *,
+ struct elf_link_hash_entry **))
+{
+ _arm_elf_section_data *arm_data;
+ struct bfd_elf_section_reloc_data *output_reldata;
+ Elf_Internal_Shdr *output_rel_hdr;
+ Elf_Internal_Rela *irela;
+ Elf_Internal_Rela *irelaend;
+ asection *output_section;
+ const struct elf_backend_data *bed;
+ void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
+ struct bfd_elf_section_data *esdo;
+ arm_unwind_table_edit *edit_list, *edit_tail;
+ bfd_byte *erel;
+ bfd_vma offset;
+
+ arm_data = get_arm_elf_section_data (input_section);
+
+ if (!arm_data || arm_data->elf.this_hdr.sh_type != SHT_ARM_EXIDX)
+ goto fallback_label;
+
+ edit_list = arm_data->u.exidx.unwind_edit_list;
+ edit_tail = arm_data->u.exidx.unwind_edit_tail;
+
+ if (!edit_list)
+ goto fallback_label;
+
+ output_section = input_section->output_section;
+ offset = output_section->vma + input_section->output_offset;
+
+ bed = get_elf_backend_data (output_bfd);
+ esdo = elf_section_data (output_section);
+ if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+ {
+ output_reldata = &esdo->rel;
+ swap_out = bed->s->swap_reloc_out;
+ }
+ else if (esdo->rela.hdr &&
+ esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+ {
+ output_reldata = &esdo->rela;
+ swap_out = bed->s->swap_reloca_out;
+ }
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%B: relocation size mismatch in %B section %A"),
+ output_bfd, input_section->owner, input_section);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ output_rel_hdr = output_reldata->hdr;
+ erel = output_rel_hdr->contents;
+ erel += output_reldata->count * input_rel_hdr->sh_entsize;
+
+ irela = internal_relocs;
+ irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+ * bed->s->int_rels_per_ext_rel);
+ while (irela < irelaend)
+ {
+ arm_unwind_table_edit *edit_node, *edit_next;
+ Elf_Internal_Rela rel;
+ bfd_vma bias;
+ bfd_vma index;
+
+ index = (irela->r_offset - offset) / 8;
+
+ bias = 0;
+ edit_node = edit_list;
+ for (edit_next = edit_list;
+ edit_next && edit_next->index <= index;
+ edit_next = edit_node->next)
+ {
+ bias++;
+ edit_node = edit_next;
+ }
+
+ if (edit_node->type != DELETE_EXIDX_ENTRY || edit_node->index != index)
+ {
+ rel.r_offset = irela->r_offset - bias * 8;
+ rel.r_info = irela->r_info;
+ rel.r_addend = irela->r_addend;
+
+ (*swap_out) (output_bfd, &rel, erel);
+ erel += output_rel_hdr->sh_entsize;
+ output_reldata->count++;
+ }
+
+ irela += bed->s->int_rels_per_ext_rel;
+ }
+
+ if (edit_tail->type == INSERT_EXIDX_CANTUNWIND_AT_END)
+ {
+ /* New relocation entity. */
+ asection *text_sec = edit_tail->linked_section;
+ asection *text_out = text_sec->output_section;
+ bfd_vma exidx_offset = offset + input_section->size - 8;
+ Elf_Internal_Rela rel;
+
+ rel.r_addend = 0;
+ rel.r_offset = exidx_offset;
+ rel.r_info = ELF32_R_INFO (text_out->target_index, R_ARM_PREL31);
+ (*swap_out) (output_bfd, &rel, erel);
+ output_reldata->count++;
+ }
+
+ return TRUE;
+
+fallback_label:
+ return fallback (output_bfd, input_section, input_rel_hdr,
+ internal_relocs, rel_hash);
+}
+
+static bfd_boolean
+elf32_arm_emit_relocs (bfd *output_bfd,
+ asection *input_section,
+ Elf_Internal_Shdr *input_rel_hdr,
+ Elf_Internal_Rela *internal_relocs,
+ struct elf_link_hash_entry **rel_hash)
+{
+ return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+ rel_hash, _bfd_elf_link_output_relocs);
+}
+
#undef elf_backend_copy_special_section_fields
#define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields
@@ -18333,6 +18489,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
#define bfd_elf32_bfd_final_link elf32_arm_final_link
#define bfd_elf32_get_synthetic_symtab elf32_arm_get_synthetic_symtab
+#define elf_backend_emit_relocs elf32_arm_emit_relocs
#define elf_backend_get_symbol_type elf32_arm_get_symbol_type
#define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook
#define elf_backend_gc_mark_extra_sections elf32_arm_gc_mark_extra_sections
@@ -18361,6 +18518,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
#define elf_backend_begin_write_processing elf32_arm_begin_write_processing
#define elf_backend_add_symbol_hook elf32_arm_add_symbol_hook
#define elf_backend_count_additional_relocs elf32_arm_count_additional_relocs
+#define elf_backend_count_output_relocs elf32_arm_count_output_relocs
#define elf_backend_symbol_processing elf32_arm_backend_symbol_processing
#define elf_backend_can_refcount 1
@@ -18527,6 +18685,17 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
elf_vxworks_final_write_processing (abfd, linker);
}
+static bfd_boolean
+elf32_arm_vxworks_emit_relocs (bfd *output_bfd,
+ asection *input_section,
+ Elf_Internal_Shdr *input_rel_hdr,
+ Elf_Internal_Rela *internal_relocs,
+ struct elf_link_hash_entry **rel_hash)
+{
+ return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+ rel_hash, elf_vxworks_emit_relocs);
+}
+
#undef elf32_bed
#define elf32_bed elf32_arm_vxworks_bed
@@ -18535,7 +18704,7 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
#undef elf_backend_final_write_processing
#define elf_backend_final_write_processing elf32_arm_vxworks_final_write_processing
#undef elf_backend_emit_relocs
-#define elf_backend_emit_relocs elf_vxworks_emit_relocs
+#define elf_backend_emit_relocs elf32_arm_vxworks_emit_relocs
#undef elf_backend_may_use_rel_p
#define elf_backend_may_use_rel_p 0
@@ -18899,6 +19068,7 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
(SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
#undef elf_backend_emit_relocs
+#define elf_backend_emit_relocs elf32_arm_emit_relocs
#undef bfd_elf32_bfd_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_create elf32_arm_symbian_link_hash_table_create
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 3e24940..20e7086 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2447,13 +2447,23 @@ _bfd_elf_link_read_relocs (bfd *abfd,
section header for a section containing relocations for O. */
static bfd_boolean
-_bfd_elf_link_size_reloc_section (bfd *abfd,
- struct bfd_elf_section_reloc_data *reldata)
+_bfd_elf_link_size_reloc_section (bfd *abfd, struct bfd_link_info *info,
+ asection *o, bfd_boolean rela)
{
- Elf_Internal_Shdr *rel_hdr = reldata->hdr;
+ struct bfd_elf_section_data *esdo;
+ const struct elf_backend_data *bed;
+ struct bfd_elf_section_reloc_data *reldata;
+ Elf_Internal_Shdr *rel_hdr;
+ unsigned int count;
+
+ esdo = elf_section_data (o);
+ reldata = rela ? &esdo->rela : &esdo->rel;
+ rel_hdr = reldata->hdr;
/* That allows us to calculate the size of the section. */
- rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
+ bed = get_elf_backend_data (abfd);
+ count = (*bed->elf_backend_count_output_relocs) (info, o, rela);
+ rel_hdr->sh_size = count * rel_hdr->sh_entsize;
/* The contents field must last into write_object_contents, so we
allocate it with bfd_alloc rather than malloc. Also since we
@@ -2541,6 +2551,19 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
return TRUE;
}
+
+unsigned int
+_bfd_elf_default_count_output_relocs (
+ struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o, bfd_boolean rela)
+{
+ struct bfd_elf_section_data *esdo;
+ struct bfd_elf_section_reloc_data *reldata;
+
+ esdo = elf_section_data (o);
+ reldata = rela ? &esdo->rela : &esdo->rel;
+
+ return reldata->count;
+}
\f
/* Make weak undefined symbols in PIE dynamic. */
@@ -11182,12 +11205,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
for (o = abfd->sections; o != NULL; o = o->next)
{
struct bfd_elf_section_data *esdo = elf_section_data (o);
+ unsigned int additional_reloc_count = 0;
o->reloc_count = 0;
for (p = o->map_head.link_order; p != NULL; p = p->next)
{
unsigned int reloc_count = 0;
- unsigned int additional_reloc_count = 0;
struct bfd_elf_section_data *esdi = NULL;
if (p->type == bfd_section_reloc_link_order
@@ -11273,21 +11296,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
if (reloc_count == 0)
continue;
- reloc_count += additional_reloc_count;
o->reloc_count += reloc_count;
if (p->type == bfd_indirect_link_order && emit_relocs)
{
if (esdi->rel.hdr)
- {
esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
- esdo->rel.count += additional_reloc_count;
- }
if (esdi->rela.hdr)
- {
esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
- esdo->rela.count += additional_reloc_count;
- }
}
else
{
@@ -11298,7 +11314,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
}
}
- if (o->reloc_count > 0)
+ if (o->reloc_count > 0 || additional_reloc_count > 0)
o->flags |= SEC_RELOC;
else
{
@@ -11336,11 +11352,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
if ((o->flags & SEC_RELOC) != 0)
{
if (esdo->rel.hdr
- && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
+ && !(_bfd_elf_link_size_reloc_section (abfd, info, o, FALSE)))
goto error_return;
if (esdo->rela.hdr
- && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
+ && !(_bfd_elf_link_size_reloc_section (abfd, info, o, TRUE)))
goto error_return;
}
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 97aa5e6..5424cf3 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -551,6 +551,9 @@
#ifndef elf_backend_count_additional_relocs
#define elf_backend_count_additional_relocs NULL
#endif
+#ifndef elf_backend_count_output_relocs
+#define elf_backend_count_output_relocs _bfd_elf_default_count_output_relocs
+#endif
#ifndef elf_backend_sort_relocs_p
#define elf_backend_sort_relocs_p NULL
#endif
@@ -773,6 +776,7 @@ static struct elf_backend_data elfNN_bed =
elf_backend_emit_relocs,
elf_backend_count_relocs,
elf_backend_count_additional_relocs,
+ elf_backend_count_output_relocs,
elf_backend_sort_relocs_p,
elf_backend_grok_prstatus,
elf_backend_grok_psinfo,
--
2.9.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] ARM: Fix relocation of EXIDX sections
2016-09-23 5:46 ` [PATCH] " Akihiko Odaki
@ 2016-09-23 5:49 ` Akihiko Odaki
2016-09-23 9:55 ` Nick Clifton
0 siblings, 1 reply; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-23 5:49 UTC (permalink / raw)
To: binutils; +Cc: Nick Clifton, Andreas Schwab, Paul Brook, Yury Usishchev
Sorry, I forgot to change the subject prefix. This is v3, fixing the
issue reported by Nick Clifton:
https://sourceware.org/ml/binutils/2016-09/msg00151.html
On 2016-09-23 14:45, Akihiko Odaki wrote:
> As reported in PR binutils/20595, BFD has a bug that it doesn't delete
> relocations for deleted exidx. This change fixes the behavior.
>
> bfd * elf-bfd.h: Add callback to count relocations in the final output.
> * elf-arm.c (elf32_arm_add_relocation): Deleted.
> (elf32_arm_write_section): Move additional relocation to emit_relocs.
> (elf32_arm_count_output_relocs): New function.
> (emit_relocs): New function.
> (elf32_arm_emit_relocs): New function.
> (elf32_arm_vxworks_emit_relocs): New function.
> (elf_backend_emit_relocs): Updated to use the new functions.
> (elf_backend_count_output_relocs): New define.
> * bfd/elflink.c (bfd_elf_final_link): Do not add additional_reloc_count
> to the relocation count.
> (_bfd_elf_link_size_reloc_section): Use callback to count the
> relocations which will be in output.
> (_bfd_elf_default_count_output_relocs): New function.
> * bfd/elfxx-target.h (elf_backend_count_output_relocs): New define.
> ---
> bfd/elf-bfd.h | 8 ++
> bfd/elf32-arm.c | 262 +++++++++++++++++++++++++++++++++++++++++++----------
> bfd/elflink.c | 46 +++++++---
> bfd/elfxx-target.h | 4 +
> 4 files changed, 259 insertions(+), 61 deletions(-)
>
> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> index 163ef35..2f2b42c 100644
> --- a/bfd/elf-bfd.h
> +++ b/bfd/elf-bfd.h
> @@ -1176,6 +1176,11 @@ struct elf_backend_data
> unsigned int (*elf_backend_count_additional_relocs)
> (asection *);
>
> + /* Count relocations to be output. The result may be different if the
> + input relocations are expected to be modified by the backend. */
> + unsigned int (* elf_backend_count_output_relocs)
> + (struct bfd_link_info *info, asection *o, bfd_boolean rela);
> +
> /* Say whether to sort relocs output by ld -r and ld --emit-relocs,
> by r_offset. If NULL, default to true. */
> bfd_boolean (*sort_relocs_p)
> @@ -2143,6 +2148,9 @@ extern bfd_boolean _bfd_elf_link_output_relocs
> (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *,
> struct elf_link_hash_entry **);
>
> +extern unsigned int _bfd_elf_default_count_output_relocs
> + (struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o, bfd_boolean rela);
> +
> extern bfd_boolean _bfd_elf_adjust_dynamic_copy
> (struct bfd_link_info *, struct elf_link_hash_entry *, asection *);
>
> diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
> index 3d4a458..28c6fb1 100644
> --- a/bfd/elf32-arm.c
> +++ b/bfd/elf32-arm.c
> @@ -17365,39 +17365,6 @@ stm32l4xx_create_replacing_stub (struct elf32_arm_link_hash_table * htab,
> /* End of stm32l4xx work-around. */
>
>
> -static void
> -elf32_arm_add_relocation (bfd *output_bfd, struct bfd_link_info *info,
> - asection *output_sec, Elf_Internal_Rela *rel)
> -{
> - BFD_ASSERT (output_sec && rel);
> - struct bfd_elf_section_reloc_data *output_reldata;
> - struct elf32_arm_link_hash_table *htab;
> - struct bfd_elf_section_data *oesd = elf_section_data (output_sec);
> - Elf_Internal_Shdr *rel_hdr;
> -
> -
> - if (oesd->rel.hdr)
> - {
> - rel_hdr = oesd->rel.hdr;
> - output_reldata = &(oesd->rel);
> - }
> - else if (oesd->rela.hdr)
> - {
> - rel_hdr = oesd->rela.hdr;
> - output_reldata = &(oesd->rela);
> - }
> - else
> - {
> - abort ();
> - }
> -
> - bfd_byte *erel = rel_hdr->contents;
> - erel += output_reldata->count * rel_hdr->sh_entsize;
> - htab = elf32_arm_hash_table (info);
> - SWAP_RELOC_OUT (htab) (output_bfd, rel, erel);
> - output_reldata->count++;
> -}
> -
> /* Do code byteswapping. Return FALSE afterwards so that the section is
> written out as normal. */
>
> @@ -17649,18 +17616,6 @@ elf32_arm_write_section (bfd *output_bfd,
> adjust offset by hand. */
> prel31_offset = text_sec->output_offset
> + text_sec->size;
> -
> - /* New relocation entity. */
> - asection *text_out = text_sec->output_section;
> - Elf_Internal_Rela rel;
> - rel.r_addend = 0;
> - rel.r_offset = exidx_offset;
> - rel.r_info = ELF32_R_INFO (text_out->target_index,
> - R_ARM_PREL31);
> -
> - elf32_arm_add_relocation (output_bfd, link_info,
> - sec->output_section,
> - &rel);
> }
>
> /* First address we can't unwind. */
> @@ -18175,6 +18130,74 @@ elf32_arm_count_additional_relocs (asection *sec)
> return arm_data->additional_reloc_count;
> }
>
> +static unsigned int
> +elf32_arm_count_output_relocs (struct bfd_link_info *info, asection *o,
> + bfd_boolean rela)
> +{
> + struct bfd_elf_section_data *esdo;
> + struct bfd_link_order *p;
> + bfd_size_type count;
> +
> + esdo = elf_section_data (o->output_section);
> + if (esdo->this_hdr.sh_type != SHT_ARM_EXIDX)
> + return _bfd_elf_default_count_output_relocs (info, o, rela);
> +
> + count = 0;
> + for (p = o->map_head.link_order; p != NULL; p = p->next)
> + {
> + struct _arm_elf_section_data *arm_data;
> + arm_unwind_table_edit *edit_list;
> + Elf_Internal_Rela *relocs;
> + asection *sec;
> + bfd_size_type num_rel;
> + bfd_size_type num_rela;
> + unsigned int i;
> +
> + if (p->type == bfd_section_reloc_link_order
> + || p->type == bfd_symbol_reloc_link_order)
> + {
> + count++;
> + continue;
> + }
> +
> + sec = p->u.indirect.section;
> + arm_data = get_arm_elf_section_data (sec);
> +
> + if (arm_data->additional_reloc_count)
> + count += arm_data->additional_reloc_count;
> +
> + edit_list = arm_data->u.exidx.unwind_edit_list;
> + if (!edit_list)
> + {
> + count += sec->reloc_count;
> + continue;
> + }
> +
> + relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
> + info->keep_memory);
> + num_rel = esdo->rel.hdr ? NUM_SHDR_ENTRIES (esdo->rel.hdr) : 0;
> + num_rela = esdo->rela.hdr ? NUM_SHDR_ENTRIES (esdo->rela.hdr) : 0;
> +
> + for (i = rela ? num_rel : 0; i < (rela ? num_rela : num_rel); i++)
> + {
> + arm_unwind_table_edit *edit_node;
> + unsigned int index;
> +
> + index = (relocs[i].r_offset - sec->vma) / 8;
> +
> + for (edit_node = edit_list;
> + edit_node->next && edit_node->next->index > index;
> + edit_node++);
> +
> + if (edit_node->type != DELETE_EXIDX_ENTRY ||
> + edit_node->index != index)
> + count++;
> + }
> + }
> +
> + return count;
> +}
> +
> /* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
> has a type >= SHT_LOOS. Returns TRUE if these fields were initialised
> FALSE otherwise. ISECTION is the best guess matching section from the
> @@ -18303,6 +18326,139 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
> sym->flags |= BSF_KEEP;
> }
>
> +static bfd_boolean
> +emit_relocs (bfd *output_bfd,
> + asection *input_section,
> + Elf_Internal_Shdr *input_rel_hdr,
> + Elf_Internal_Rela *internal_relocs,
> + struct elf_link_hash_entry **rel_hash,
> + bfd_boolean (*fallback) (bfd *, asection *,
> + Elf_Internal_Shdr *,
> + Elf_Internal_Rela *,
> + struct elf_link_hash_entry **))
> +{
> + _arm_elf_section_data *arm_data;
> + struct bfd_elf_section_reloc_data *output_reldata;
> + Elf_Internal_Shdr *output_rel_hdr;
> + Elf_Internal_Rela *irela;
> + Elf_Internal_Rela *irelaend;
> + asection *output_section;
> + const struct elf_backend_data *bed;
> + void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
> + struct bfd_elf_section_data *esdo;
> + arm_unwind_table_edit *edit_list, *edit_tail;
> + bfd_byte *erel;
> + bfd_vma offset;
> +
> + arm_data = get_arm_elf_section_data (input_section);
> +
> + if (!arm_data || arm_data->elf.this_hdr.sh_type != SHT_ARM_EXIDX)
> + goto fallback_label;
> +
> + edit_list = arm_data->u.exidx.unwind_edit_list;
> + edit_tail = arm_data->u.exidx.unwind_edit_tail;
> +
> + if (!edit_list)
> + goto fallback_label;
> +
> + output_section = input_section->output_section;
> + offset = output_section->vma + input_section->output_offset;
> +
> + bed = get_elf_backend_data (output_bfd);
> + esdo = elf_section_data (output_section);
> + if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
> + {
> + output_reldata = &esdo->rel;
> + swap_out = bed->s->swap_reloc_out;
> + }
> + else if (esdo->rela.hdr &&
> + esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
> + {
> + output_reldata = &esdo->rela;
> + swap_out = bed->s->swap_reloca_out;
> + }
> + else
> + {
> + (*_bfd_error_handler)
> + (_("%B: relocation size mismatch in %B section %A"),
> + output_bfd, input_section->owner, input_section);
> + bfd_set_error (bfd_error_wrong_format);
> + return FALSE;
> + }
> +
> + output_rel_hdr = output_reldata->hdr;
> + erel = output_rel_hdr->contents;
> + erel += output_reldata->count * input_rel_hdr->sh_entsize;
> +
> + irela = internal_relocs;
> + irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
> + * bed->s->int_rels_per_ext_rel);
> + while (irela < irelaend)
> + {
> + arm_unwind_table_edit *edit_node, *edit_next;
> + Elf_Internal_Rela rel;
> + bfd_vma bias;
> + bfd_vma index;
> +
> + index = (irela->r_offset - offset) / 8;
> +
> + bias = 0;
> + edit_node = edit_list;
> + for (edit_next = edit_list;
> + edit_next && edit_next->index <= index;
> + edit_next = edit_node->next)
> + {
> + bias++;
> + edit_node = edit_next;
> + }
> +
> + if (edit_node->type != DELETE_EXIDX_ENTRY || edit_node->index != index)
> + {
> + rel.r_offset = irela->r_offset - bias * 8;
> + rel.r_info = irela->r_info;
> + rel.r_addend = irela->r_addend;
> +
> + (*swap_out) (output_bfd, &rel, erel);
> + erel += output_rel_hdr->sh_entsize;
> + output_reldata->count++;
> + }
> +
> + irela += bed->s->int_rels_per_ext_rel;
> + }
> +
> + if (edit_tail->type == INSERT_EXIDX_CANTUNWIND_AT_END)
> + {
> + /* New relocation entity. */
> + asection *text_sec = edit_tail->linked_section;
> + asection *text_out = text_sec->output_section;
> + bfd_vma exidx_offset = offset + input_section->size - 8;
> + Elf_Internal_Rela rel;
> +
> + rel.r_addend = 0;
> + rel.r_offset = exidx_offset;
> + rel.r_info = ELF32_R_INFO (text_out->target_index, R_ARM_PREL31);
> + (*swap_out) (output_bfd, &rel, erel);
> + output_reldata->count++;
> + }
> +
> + return TRUE;
> +
> +fallback_label:
> + return fallback (output_bfd, input_section, input_rel_hdr,
> + internal_relocs, rel_hash);
> +}
> +
> +static bfd_boolean
> +elf32_arm_emit_relocs (bfd *output_bfd,
> + asection *input_section,
> + Elf_Internal_Shdr *input_rel_hdr,
> + Elf_Internal_Rela *internal_relocs,
> + struct elf_link_hash_entry **rel_hash)
> +{
> + return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
> + rel_hash, _bfd_elf_link_output_relocs);
> +}
> +
> #undef elf_backend_copy_special_section_fields
> #define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields
>
> @@ -18333,6 +18489,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
> #define bfd_elf32_bfd_final_link elf32_arm_final_link
> #define bfd_elf32_get_synthetic_symtab elf32_arm_get_synthetic_symtab
>
> +#define elf_backend_emit_relocs elf32_arm_emit_relocs
> #define elf_backend_get_symbol_type elf32_arm_get_symbol_type
> #define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook
> #define elf_backend_gc_mark_extra_sections elf32_arm_gc_mark_extra_sections
> @@ -18361,6 +18518,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
> #define elf_backend_begin_write_processing elf32_arm_begin_write_processing
> #define elf_backend_add_symbol_hook elf32_arm_add_symbol_hook
> #define elf_backend_count_additional_relocs elf32_arm_count_additional_relocs
> +#define elf_backend_count_output_relocs elf32_arm_count_output_relocs
> #define elf_backend_symbol_processing elf32_arm_backend_symbol_processing
>
> #define elf_backend_can_refcount 1
> @@ -18527,6 +18685,17 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
> elf_vxworks_final_write_processing (abfd, linker);
> }
>
> +static bfd_boolean
> +elf32_arm_vxworks_emit_relocs (bfd *output_bfd,
> + asection *input_section,
> + Elf_Internal_Shdr *input_rel_hdr,
> + Elf_Internal_Rela *internal_relocs,
> + struct elf_link_hash_entry **rel_hash)
> +{
> + return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
> + rel_hash, elf_vxworks_emit_relocs);
> +}
> +
> #undef elf32_bed
> #define elf32_bed elf32_arm_vxworks_bed
>
> @@ -18535,7 +18704,7 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
> #undef elf_backend_final_write_processing
> #define elf_backend_final_write_processing elf32_arm_vxworks_final_write_processing
> #undef elf_backend_emit_relocs
> -#define elf_backend_emit_relocs elf_vxworks_emit_relocs
> +#define elf_backend_emit_relocs elf32_arm_vxworks_emit_relocs
>
> #undef elf_backend_may_use_rel_p
> #define elf_backend_may_use_rel_p 0
> @@ -18899,6 +19068,7 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
> (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
>
> #undef elf_backend_emit_relocs
> +#define elf_backend_emit_relocs elf32_arm_emit_relocs
>
> #undef bfd_elf32_bfd_link_hash_table_create
> #define bfd_elf32_bfd_link_hash_table_create elf32_arm_symbian_link_hash_table_create
> diff --git a/bfd/elflink.c b/bfd/elflink.c
> index 3e24940..20e7086 100644
> --- a/bfd/elflink.c
> +++ b/bfd/elflink.c
> @@ -2447,13 +2447,23 @@ _bfd_elf_link_read_relocs (bfd *abfd,
> section header for a section containing relocations for O. */
>
> static bfd_boolean
> -_bfd_elf_link_size_reloc_section (bfd *abfd,
> - struct bfd_elf_section_reloc_data *reldata)
> +_bfd_elf_link_size_reloc_section (bfd *abfd, struct bfd_link_info *info,
> + asection *o, bfd_boolean rela)
> {
> - Elf_Internal_Shdr *rel_hdr = reldata->hdr;
> + struct bfd_elf_section_data *esdo;
> + const struct elf_backend_data *bed;
> + struct bfd_elf_section_reloc_data *reldata;
> + Elf_Internal_Shdr *rel_hdr;
> + unsigned int count;
> +
> + esdo = elf_section_data (o);
> + reldata = rela ? &esdo->rela : &esdo->rel;
> + rel_hdr = reldata->hdr;
>
> /* That allows us to calculate the size of the section. */
> - rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
> + bed = get_elf_backend_data (abfd);
> + count = (*bed->elf_backend_count_output_relocs) (info, o, rela);
> + rel_hdr->sh_size = count * rel_hdr->sh_entsize;
>
> /* The contents field must last into write_object_contents, so we
> allocate it with bfd_alloc rather than malloc. Also since we
> @@ -2541,6 +2551,19 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
>
> return TRUE;
> }
> +
> +unsigned int
> +_bfd_elf_default_count_output_relocs (
> + struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o, bfd_boolean rela)
> +{
> + struct bfd_elf_section_data *esdo;
> + struct bfd_elf_section_reloc_data *reldata;
> +
> + esdo = elf_section_data (o);
> + reldata = rela ? &esdo->rela : &esdo->rel;
> +
> + return reldata->count;
> +}
> \f
> /* Make weak undefined symbols in PIE dynamic. */
>
> @@ -11182,12 +11205,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
> for (o = abfd->sections; o != NULL; o = o->next)
> {
> struct bfd_elf_section_data *esdo = elf_section_data (o);
> + unsigned int additional_reloc_count = 0;
> o->reloc_count = 0;
>
> for (p = o->map_head.link_order; p != NULL; p = p->next)
> {
> unsigned int reloc_count = 0;
> - unsigned int additional_reloc_count = 0;
> struct bfd_elf_section_data *esdi = NULL;
>
> if (p->type == bfd_section_reloc_link_order
> @@ -11273,21 +11296,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
> if (reloc_count == 0)
> continue;
>
> - reloc_count += additional_reloc_count;
> o->reloc_count += reloc_count;
>
> if (p->type == bfd_indirect_link_order && emit_relocs)
> {
> if (esdi->rel.hdr)
> - {
> esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
> - esdo->rel.count += additional_reloc_count;
> - }
> if (esdi->rela.hdr)
> - {
> esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
> - esdo->rela.count += additional_reloc_count;
> - }
> }
> else
> {
> @@ -11298,7 +11314,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
> }
> }
>
> - if (o->reloc_count > 0)
> + if (o->reloc_count > 0 || additional_reloc_count > 0)
> o->flags |= SEC_RELOC;
> else
> {
> @@ -11336,11 +11352,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
> if ((o->flags & SEC_RELOC) != 0)
> {
> if (esdo->rel.hdr
> - && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
> + && !(_bfd_elf_link_size_reloc_section (abfd, info, o, FALSE)))
> goto error_return;
>
> if (esdo->rela.hdr
> - && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
> + && !(_bfd_elf_link_size_reloc_section (abfd, info, o, TRUE)))
> goto error_return;
> }
>
> diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
> index 97aa5e6..5424cf3 100644
> --- a/bfd/elfxx-target.h
> +++ b/bfd/elfxx-target.h
> @@ -551,6 +551,9 @@
> #ifndef elf_backend_count_additional_relocs
> #define elf_backend_count_additional_relocs NULL
> #endif
> +#ifndef elf_backend_count_output_relocs
> +#define elf_backend_count_output_relocs _bfd_elf_default_count_output_relocs
> +#endif
> #ifndef elf_backend_sort_relocs_p
> #define elf_backend_sort_relocs_p NULL
> #endif
> @@ -773,6 +776,7 @@ static struct elf_backend_data elfNN_bed =
> elf_backend_emit_relocs,
> elf_backend_count_relocs,
> elf_backend_count_additional_relocs,
> + elf_backend_count_output_relocs,
> elf_backend_sort_relocs_p,
> elf_backend_grok_prstatus,
> elf_backend_grok_psinfo,
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] ARM: Fix relocation of EXIDX sections
2016-09-23 5:49 ` Akihiko Odaki
@ 2016-09-23 9:55 ` Nick Clifton
0 siblings, 0 replies; 8+ messages in thread
From: Nick Clifton @ 2016-09-23 9:55 UTC (permalink / raw)
To: Akihiko Odaki, binutils; +Cc: Andreas Schwab, Paul Brook, Yury Usishchev
Hi Akihiko-san,
> Sorry, I forgot to change the subject prefix. This is v3, fixing the issue reported by Nick Clifton:
Thank you for fixing this problem. It seems that the new patch however does not work. :-(
Specifically it fails to fix the unwind-4 linker test (with your patch applied to that test)
and it introduces a new linker testsuite regression unwind-rel:
Running /work/sources/binutils/current/ld/testsuite/ld-arm/arm-elf.exp ...
[...]
FAIL: ld-arm/unwind-4
[...]
FAIL: unwind-rel
[...]
This is with any ELF based ARM toolchain.
Please could you have a look at these.
Cheers
Nick
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2016-09-23 9:55 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-11 9:31 [PATCH] Test also relocations for ARM unwinding section Akihiko Odaki
2016-09-13 6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
2016-09-13 7:16 ` Andreas Schwab
2016-09-13 10:04 ` [PATH v2] " Akihiko Odaki
2016-09-22 16:04 ` Nick Clifton
2016-09-23 5:46 ` [PATCH] " Akihiko Odaki
2016-09-23 5:49 ` Akihiko Odaki
2016-09-23 9:55 ` Nick Clifton
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).