From 491d01d3da18fb61fa6c7c61c091b4cb8c5773f7 Mon Sep 17 00:00:00 2001 From: Yury Usishchev Date: Tue, 22 Dec 2015 15:50:13 +0000 Subject: [PATCH] ARM: Fix exidx coverage for relocatable builds. bfd * elf-bfd.h: Add callback to count additional relocations. * elf32-arm.c (_arm_elf_section_data): Add new counter. (insert_cantunwind_after): Increment relocations counter. (elf32_arm_fix_exidx_coverage): Remove exidx entries and add terminating CANTUNWIND entry only in final builds. (elf32_arm_add_relocation): New function. (elf32_arm_write_section): Add relocations in relocatable builds. (elf32_arm_count_additional_relocs): New function. (elf_backend_count_additional_relocs): New define. * bfd/elflink.c (bfd_elf_final_link): Use callback and adjust size of .rel section. * bfd/elfxx-target.h (elf_backend_count_additional_relocs): New define. ld * emultempl/armelf.em (gld${EMULATION_NAME}_after_allocation): Call elf32_arm_fix_exidx_coverage for relocatable builds. ld/testsuite * ld-arm/arm-elf.exp: New test. * ld-arm/unwind-rel.d: New file. * ld-arm/unwind-rel1.s: New file. * ld-arm/unwind-rel2.s: New file. * ld-arm/unwind-rel3.s: New file. --- bfd/ChangeLog | 15 +++++++ bfd/elf-bfd.h | 5 +++ bfd/elf32-arm.c | 70 ++++++++++++++++++++++++++++- bfd/elflink.c | 22 ++++++++-- bfd/elfxx-target.h | 4 ++ ld/ChangeLog | 5 +++ ld/emultempl/armelf.em | 73 +++++++++++++++---------------- ld/testsuite/ChangeLog | 24 ++++++---- ld/testsuite/ld-arm/arm-elf.exp | 6 +++ ld/testsuite/ld-arm/unwind-rel.d | 31 +++++++++++++ ld/testsuite/ld-arm/unwind-rel1.s | 9 ++++ ld/testsuite/ld-arm/unwind-rel2.s | 6 +++ ld/testsuite/ld-arm/unwind-rel3.s | 9 ++++ 13 files changed, 228 insertions(+), 51 deletions(-) create mode 100644 ld/testsuite/ld-arm/unwind-rel.d create mode 100644 ld/testsuite/ld-arm/unwind-rel1.s create mode 100644 ld/testsuite/ld-arm/unwind-rel2.s create mode 100644 ld/testsuite/ld-arm/unwind-rel3.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 49baaa12d7f..e5bedae35e4 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,18 @@ +2015-12-22 Yury Usishchev + + * elf-bfd.h: Add callback to count additional relocations. + * elf32-arm.c (_arm_elf_section_data): Add new counter. + (insert_cantunwind_after): Increment relocations counter. + (elf32_arm_fix_exidx_coverage): Remove exidx entries and add + terminating CANTUNWIND entry only in final builds. + (elf32_arm_add_relocation): New function. + (elf32_arm_write_section): Add relocations in relocatable builds. + (elf32_arm_count_additional_relocs): New function. + (elf_backend_count_additional_relocs): New define. + * elflink.c (bfd_elf_final_link): Use callback and adjust size of + .rel section. + * elfxx-target.h (elf_backend_count_additional_relocs): New define. + 2015-12-22 Yoshinori Sato * archures.c: Add bfd_mach_rx_v2. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 70e33275054..129aa64ef6f 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1170,6 +1170,11 @@ struct elf_backend_data unsigned int (*elf_backend_count_relocs) (struct bfd_link_info *, asection *); + /* Count additionals relocations. Called for relocatable links if + additional relocations needs to be created. */ + unsigned int (*elf_backend_count_additional_relocs) + (asection *); + /* 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) diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 5d31ef28383..583db4d3573 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -2802,6 +2802,7 @@ typedef struct _arm_elf_section_data elf32_vfp11_erratum_list *erratumlist; unsigned int stm32l4xx_erratumcount; elf32_stm32l4xx_erratum_list *stm32l4xx_erratumlist; + unsigned int additional_reloc_count; /* Information about unwind tables. */ union { @@ -11619,6 +11620,8 @@ insert_cantunwind_after(asection *text_sec, asection *exidx_sec) &exidx_arm_data->u.exidx.unwind_edit_tail, INSERT_EXIDX_CANTUNWIND_AT_END, text_sec, UINT_MAX); + exidx_arm_data->additional_reloc_count++; + adjust_exidx_size(exidx_sec, 8); } @@ -11761,7 +11764,7 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order, else unwind_type = 2; - if (elide) + if (elide && !bfd_link_relocatable (info)) { add_unwind_table_edit (&unwind_edit_head, &unwind_edit_tail, DELETE_EXIDX_ENTRY, NULL, j / 8); @@ -11788,7 +11791,8 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order, } /* Add terminating CANTUNWIND entry. */ - if (last_exidx_sec && last_unwind_type != 0) + if (!bfd_link_relocatable (info) && last_exidx_sec + && last_unwind_type != 0) insert_cantunwind_after(last_text_sec, last_exidx_sec); return TRUE; @@ -16984,6 +16988,39 @@ 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. */ @@ -17228,6 +17265,26 @@ elf32_arm_write_section (bfd *output_bfd, usual BFD method. */ prel31_offset = (text_offset - exidx_offset) & 0x7ffffffful; + if (bfd_link_relocatable (link_info)) + { + /* Here relocation for new EXIDX_CANTUNWIND is + created, so there is no need to + 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. */ bfd_put_32 (output_bfd, prel31_offset, @@ -17742,6 +17799,14 @@ elf32_arm_lookup_section_flags (char *flag_name) return SEC_NO_FLAGS; } +static unsigned int +elf32_arm_count_additional_relocs (asection *sec) +{ + struct _arm_elf_section_data *arm_data; + arm_data = get_arm_elf_section_data (sec); + return arm_data->additional_reloc_count; +} + #define ELF_ARCH bfd_arch_arm #define ELF_TARGET_ID ARM_ELF_DATA #define ELF_MACHINE_CODE EM_ARM @@ -17796,6 +17861,7 @@ elf32_arm_lookup_section_flags (char *flag_name) #define elf_backend_output_arch_local_syms elf32_arm_output_arch_local_syms #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_can_refcount 1 #define elf_backend_can_gc_sections 1 diff --git a/bfd/elflink.c b/bfd/elflink.c index 1b41c793a97..2eeada2aeca 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -10988,6 +10988,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) 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 @@ -11016,7 +11017,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) reloc sections themselves can't have relocations. */ reloc_count = 0; else if (emit_relocs) - reloc_count = sec->reloc_count; + { + reloc_count = sec->reloc_count; + if (bed->elf_backend_count_additional_relocs) + { + int c; + c = (*bed->elf_backend_count_additional_relocs) (sec); + additional_reloc_count += c; + } + } else if (bed->elf_backend_count_relocs) reloc_count = (*bed->elf_backend_count_relocs) (info, sec); @@ -11065,14 +11074,21 @@ 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 += 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 += NUM_SHDR_ENTRIES (esdi->rela.hdr); + esdo->rela.count += additional_reloc_count; + } } else { diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index 0acecafcb29..c5bd7de8500 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -538,6 +538,9 @@ #ifndef elf_backend_count_relocs #define elf_backend_count_relocs NULL #endif +#ifndef elf_backend_count_additional_relocs +#define elf_backend_count_additional_relocs NULL +#endif #ifndef elf_backend_sort_relocs_p #define elf_backend_sort_relocs_p NULL #endif @@ -755,6 +758,7 @@ static struct elf_backend_data elfNN_bed = elf_backend_ignore_undef_symbol, elf_backend_emit_relocs, elf_backend_count_relocs, + elf_backend_count_additional_relocs, elf_backend_sort_relocs_p, elf_backend_grok_prstatus, elf_backend_grok_psinfo, diff --git a/ld/ChangeLog b/ld/ChangeLog index 576e3dcf3ca..a7014d51e82 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,8 @@ +2015-12-22 Yury Usishchev + + * emultempl/armelf.em (gld${EMULATION_NAME}_after_allocation): Call + elf32_arm_fix_exidx_coverage for relocatable builds. + 2015-12-10 Kwok Cheung Yeung PR ld/18199 diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em index 2931a49f3fb..aae45d16b21 100644 --- a/ld/emultempl/armelf.em +++ b/ld/emultempl/armelf.em @@ -293,55 +293,52 @@ gld${EMULATION_NAME}_after_allocation (void) { int ret; - if (!bfd_link_relocatable (&link_info)) + /* Build a sorted list of input text sections, then use that to process + the unwind table index. */ + unsigned int list_size = 10; + asection **sec_list = (asection **) + xmalloc (list_size * sizeof (asection *)); + unsigned int sec_count = 0; + + LANG_FOR_EACH_INPUT_STATEMENT (is) { - /* Build a sorted list of input text sections, then use that to process - the unwind table index. */ - unsigned int list_size = 10; - asection **sec_list = (asection **) - xmalloc (list_size * sizeof (asection *)); - unsigned int sec_count = 0; + bfd *abfd = is->the_bfd; + asection *sec; - LANG_FOR_EACH_INPUT_STATEMENT (is) - { - bfd *abfd = is->the_bfd; - asection *sec; + if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) + continue; - if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) - continue; - - for (sec = abfd->sections; sec != NULL; sec = sec->next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + asection *out_sec = sec->output_section; + + if (out_sec + && elf_section_data (sec) + && elf_section_type (sec) == SHT_PROGBITS + && (elf_section_flags (sec) & SHF_EXECINSTR) != 0 + && (sec->flags & SEC_EXCLUDE) == 0 + && sec->sec_info_type != SEC_INFO_TYPE_JUST_SYMS + && out_sec != bfd_abs_section_ptr) { - asection *out_sec = sec->output_section; - - if (out_sec - && elf_section_data (sec) - && elf_section_type (sec) == SHT_PROGBITS - && (elf_section_flags (sec) & SHF_EXECINSTR) != 0 - && (sec->flags & SEC_EXCLUDE) == 0 - && sec->sec_info_type != SEC_INFO_TYPE_JUST_SYMS - && out_sec != bfd_abs_section_ptr) + if (sec_count == list_size) { - if (sec_count == list_size) - { - list_size *= 2; - sec_list = (asection **) - xrealloc (sec_list, list_size * sizeof (asection *)); - } - - sec_list[sec_count++] = sec; + list_size *= 2; + sec_list = (asection **) + xrealloc (sec_list, list_size * sizeof (asection *)); } + + sec_list[sec_count++] = sec; } } + } - qsort (sec_list, sec_count, sizeof (asection *), &compare_output_sec_vma); + qsort (sec_list, sec_count, sizeof (asection *), &compare_output_sec_vma); - if (elf32_arm_fix_exidx_coverage (sec_list, sec_count, &link_info, - merge_exidx_entries)) - need_laying_out = 1; + if (elf32_arm_fix_exidx_coverage (sec_list, sec_count, &link_info, + merge_exidx_entries)) + need_laying_out = 1; - free (sec_list); - } + free (sec_list); /* bfd_elf32_discard_info just plays with debugging sections, ie. doesn't affect any code, so we can delay resizing the diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index d5982b91167..d8b2d3ce746 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,14 +1,22 @@ +2015-12-21 Yury Usishchev + + * ld-arm/arm-elf.exp: New test. + * ld-arm/unwind-rel.d: New file. + * ld-arm/unwind-rel1.s: New file. + * ld-arm/unwind-rel2.s: New file. + * ld-arm/unwind-rel3.s: New file. + 2015-12-22 Mickael Guene * ld-arm/arm-elf.exp: New tests. - * ld-arm/thumb1-input-section-flag-match.d: New - * ld-arm/thumb1-input-section-flag-match.s: New - * ld-arm/thumb1-noread-not-present-mixing-two-section.d: New - * ld-arm/thumb1-noread-not-present-mixing-two-section.s: New - * ld-arm/thumb1-noread-present-one-section.d: New - * ld-arm/thumb1-noread-present-one-section.s: New - * ld-arm/thumb1-noread-present-two-section.d: New - * ld-arm/thumb1-noread-present-two-section.s: New + * ld-arm/thumb1-input-section-flag-match.d: New. + * ld-arm/thumb1-input-section-flag-match.s: New. + * ld-arm/thumb1-noread-not-present-mixing-two-section.d: New. + * ld-arm/thumb1-noread-not-present-mixing-two-section.s: New. + * ld-arm/thumb1-noread-present-one-section.d: New. + * ld-arm/thumb1-noread-present-one-section.s: New. + * ld-arm/thumb1-noread-present-two-section.d: New. + * ld-arm/thumb1-noread-present-two-section.s: New. 2015-12-16 Mickael Guene diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp index a970dba316c..ac2abf173e0 100644 --- a/ld/testsuite/ld-arm/arm-elf.exp +++ b/ld/testsuite/ld-arm/arm-elf.exp @@ -941,3 +941,9 @@ run_dump_test "gc-hidden-1" run_dump_test "protected-data" run_dump_test "stm32l4xx-cannot-fix-it-block" run_dump_test "stm32l4xx-cannot-fix-far-ldm" +set arm_unwind_tests { + {"unwind-rel" "-r -Tarm.ld" "" "" {unwind-rel1.s unwind-rel2.s unwind-rel3.s} + {{readelf -ur unwind-rel.d}} + "unwind-rel"} +} +run_ld_link_tests $arm_unwind_tests diff --git a/ld/testsuite/ld-arm/unwind-rel.d b/ld/testsuite/ld-arm/unwind-rel.d new file mode 100644 index 00000000000..b2aa6e29a48 --- /dev/null +++ b/ld/testsuite/ld-arm/unwind-rel.d @@ -0,0 +1,31 @@ + +Relocation section '\.rel\.text' at offset .* contains 3 entries: + Offset Info Type Sym\.Value Sym\. Name +00000000 00000028 R_ARM_V4BX +00000004 00000028 R_ARM_V4BX +00000008 00000028 R_ARM_V4BX + +Relocation section '\.rel\.ARM\.exidx' at offset .* contains 5 entries: + Offset Info Type Sym\.Value Sym\. Name +00000000 0000012a R_ARM_PREL31 00000000 \.text +00000000 00000e00 R_ARM_NONE 00000000 __aeabi_unwind_cpp_pr0 +00000008 0000012a R_ARM_PREL31 00000000 \.text +00000010 0000012a R_ARM_PREL31 00000000 \.text +00000010 00000e00 R_ARM_NONE 00000000 __aeabi_unwind_cpp_pr0 + +Unwind table index '\.ARM\.exidx' at offset .* contains 3 entries: + +0x0: 0x80a8b0b0 + Compact model index: 0 + 0xa8 pop {r4, r14} + 0xb0 finish + 0xb0 finish + +0x4 : 0x1 \[cantunwind\] + +0x8 : 0x80a8b0b0 + Compact model index: 0 + 0xa8 pop {r4, r14} + 0xb0 finish + 0xb0 finish + diff --git a/ld/testsuite/ld-arm/unwind-rel1.s b/ld/testsuite/ld-arm/unwind-rel1.s new file mode 100644 index 00000000000..9efb78b95a4 --- /dev/null +++ b/ld/testsuite/ld-arm/unwind-rel1.s @@ -0,0 +1,9 @@ + .syntax unified + .text + .global _start + .type _start, %function +_start: + .fnstart + .save {r4, lr} + bx lr + .fnend diff --git a/ld/testsuite/ld-arm/unwind-rel2.s b/ld/testsuite/ld-arm/unwind-rel2.s new file mode 100644 index 00000000000..10017436191 --- /dev/null +++ b/ld/testsuite/ld-arm/unwind-rel2.s @@ -0,0 +1,6 @@ + .syntax unified + .text + .global test + .type test, %function +test: + bx lr diff --git a/ld/testsuite/ld-arm/unwind-rel3.s b/ld/testsuite/ld-arm/unwind-rel3.s new file mode 100644 index 00000000000..8511339c1da --- /dev/null +++ b/ld/testsuite/ld-arm/unwind-rel3.s @@ -0,0 +1,9 @@ + .syntax unified + .text + .global end + .type end, %function +end: + .fnstart + .save {r4, lr} + bx lr + .fnend -- 2.30.2