From cff69cf4cf97e1eb4c2cca8e985e403b1a97c059 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Mon, 4 May 2020 15:51:56 +0100 Subject: [PATCH] [binutils-gdb][ld][AArch64] Fix group_sections algorithm PR ld/25665 * bfd/elfnn-aarch64.c (group_sections): Copy implementation from elf32-arm.c. * testsuite/ld-aarch64/aarch64-elf.exp: Add new test. * testsuite/ld-aarch64/farcall-group.s: New large group test. * testsuite/ld-aarch64/farcall-group.d: Likewise. --- bfd/ChangeLog | 6 ++ bfd/elfnn-aarch64.c | 83 +++++++++++++++++-------- ld/ChangeLog | 7 +++ ld/testsuite/ld-aarch64/aarch64-elf.exp | 1 + ld/testsuite/ld-aarch64/farcall-group.d | 30 +++++++++ ld/testsuite/ld-aarch64/farcall-group.s | 15 +++++ 6 files changed, 115 insertions(+), 27 deletions(-) create mode 100644 ld/testsuite/ld-aarch64/farcall-group.d create mode 100644 ld/testsuite/ld-aarch64/farcall-group.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a2b0771db27..be1c985615c 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2020-05-01 Wilco Dijkstra + + PR ld/25665 + * elfnn-aarch64.c (group_sections): Copy implementation from + elf32-arm.c. + 2020-05-01 Alan Modra PR 25900 diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index 02688ccee10..4bb5707d2f4 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -3546,7 +3546,7 @@ elfNN_aarch64_next_input_section (struct bfd_link_info *info, asection *isec) { asection **list = htab->input_list + isec->output_section->index; - if (*list != bfd_abs_section_ptr) + if (*list != bfd_abs_section_ptr && (isec->flags & SEC_CODE) != 0) { /* Steal the link_sec pointer for our list. */ /* This happens to make the list in reverse order, @@ -3567,67 +3567,96 @@ elfNN_aarch64_next_input_section (struct bfd_link_info *info, asection *isec) static void group_sections (struct elf_aarch64_link_hash_table *htab, bfd_size_type stub_group_size, - bfd_boolean stubs_always_before_branch) + bfd_boolean stubs_always_after_branch) { - asection **list = htab->input_list + htab->top_index; + asection **list = htab->input_list; do { asection *tail = *list; + asection *head; if (tail == bfd_abs_section_ptr) continue; + /* Reverse the list: we must avoid placing stubs at the + beginning of the section because the beginning of the text + section may be required for an interrupt vector in bare metal + code. */ +#define NEXT_SEC PREV_SEC + head = NULL; while (tail != NULL) + { + /* Pop from tail. */ + asection *item = tail; + tail = PREV_SEC (item); + + /* Push on head. */ + NEXT_SEC (item) = head; + head = item; + } + + while (head != NULL) { asection *curr; - asection *prev; - bfd_size_type total; + asection *next; + bfd_vma stub_group_start = head->output_offset; + bfd_vma end_of_next; - curr = tail; - total = tail->size; - while ((prev = PREV_SEC (curr)) != NULL - && ((total += curr->output_offset - prev->output_offset) - < stub_group_size)) - curr = prev; + curr = head; + while (NEXT_SEC (curr) != NULL) + { + next = NEXT_SEC (curr); + end_of_next = next->output_offset + next->size; + if (end_of_next - stub_group_start >= stub_group_size) + /* End of NEXT is too far from start, so stop. */ + break; + /* Add NEXT to the group. */ + curr = next; + } - /* OK, the size from the start of CURR to the end is less + /* OK, the size from the start to the start of CURR is less than stub_group_size and thus can be handled by one stub - section. (Or the tail section is itself larger than + section. (Or the head section is itself larger than stub_group_size, in which case we may be toast.) We should really be keeping track of the total size of stubs added here, as stubs contribute to the final output section size. */ do { - prev = PREV_SEC (tail); + next = NEXT_SEC (head); /* Set up this stub group. */ - htab->stub_group[tail->id].link_sec = curr; + htab->stub_group[head->id].link_sec = curr; } - while (tail != curr && (tail = prev) != NULL); + while (head != curr && (head = next) != NULL); /* But wait, there's more! Input sections up to stub_group_size - bytes before the stub section can be handled by it too. */ - if (!stubs_always_before_branch) + bytes after the stub section can be handled by it too. */ + if (!stubs_always_after_branch) { - total = 0; - while (prev != NULL - && ((total += tail->output_offset - prev->output_offset) - < stub_group_size)) + stub_group_start = curr->output_offset + curr->size; + + while (next != NULL) { - tail = prev; - prev = PREV_SEC (tail); - htab->stub_group[tail->id].link_sec = curr; + end_of_next = next->output_offset + next->size; + if (end_of_next - stub_group_start >= stub_group_size) + /* End of NEXT is too far from stubs, so stop. */ + break; + /* Add NEXT to the stub group. */ + head = next; + next = NEXT_SEC (head); + htab->stub_group[head->id].link_sec = curr; } } - tail = prev; + head = next; } } - while (list-- != htab->input_list); + while (list++ != htab->input_list + htab->top_index); free (htab->input_list); } +#undef PREV_SEC #undef PREV_SEC #define AARCH64_BITS(x, pos, n) (((x) >> (pos)) & ((1 << (n)) - 1)) diff --git a/ld/ChangeLog b/ld/ChangeLog index 323a956c65a..63b0b769a87 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,10 @@ +2020-05-01 Wilco Dijkstra + + PR ld/25665 + * testsuite/ld-aarch64/farcall-group.s: New large group test. + * testsuite/ld-aarch64/farcall-group.d: New test driver. + * testsuite/ld-aarch64/aarch64-elf.exp: Run the new test. + 2020-05-01 Alan Modra PR 25882 diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp index fefc751b0fe..297a3e96db9 100644 --- a/ld/testsuite/ld-aarch64/aarch64-elf.exp +++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp @@ -262,6 +262,7 @@ run_dump_test "farcall-b-none-function" run_dump_test "farcall-bl-none-function" run_dump_test "farcall-b-section" run_dump_test "farcall-bl-section" +run_dump_test "farcall-group" run_dump_test "tls-relax-all" run_dump_test "tls-relax-all-ilp32" diff --git a/ld/testsuite/ld-aarch64/farcall-group.d b/ld/testsuite/ld-aarch64/farcall-group.d new file mode 100644 index 00000000000..365b6b99a11 --- /dev/null +++ b/ld/testsuite/ld-aarch64/farcall-group.d @@ -0,0 +1,30 @@ +#name: aarch64-farcall-group +#source: farcall-group.s +#as: +#ld: -Ttext=0x400078 +#objdump: -dr +#... + +Disassembly of section .text: + +0000000000400078 <_start>: + 400078: 95000008 bl 4400098 <__end_veneer> + ... + 440007c: (d503201f|1f2003d5) .word 0x(d503201f|1f2003d5) + 4400080: 1400000e b 44000b8 <__end_veneer\+0x20> + 4400084: d503201f nop + +0000000004400088 <___start_veneer>: + 4400088: 90fe0010 adrp x16, 400000 <.*> + 440008c: 9101e210 add x16, x16, #0x78 + 4400090: d61f0200 br x16 + 4400094: 00000000 udf #0 + +0000000004400098 <__end_veneer>: + 4400098: 90020010 adrp x16, 8400000 <__end_veneer\+0x3ffff68> + 440009c: 9102e210 add x16, x16, #0xb8 + 44000a0: d61f0200 br x16 + ... + +00000000084000b8 : + 84000b8: 96fffff4 bl 4400088 <___start_veneer> diff --git a/ld/testsuite/ld-aarch64/farcall-group.s b/ld/testsuite/ld-aarch64/farcall-group.s new file mode 100644 index 00000000000..7fe8f94c89c --- /dev/null +++ b/ld/testsuite/ld-aarch64/farcall-group.s @@ -0,0 +1,15 @@ + .section .text.t1 + .global _start + .global end +_start: + bl end + + .section .text.t2 + .zero 64 * 1024 * 1024 + + .section .text.t3 + .zero 64 * 1024 * 1024 + + .section .text.t4 +end: + bl _start -- 2.39.5