summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilco Dijkstra <wdijkstr@arm.com>2020-05-04 15:51:56 +0100
committerNick Clifton <nickc@redhat.com>2020-05-04 15:51:56 +0100
commitcff69cf4cf97e1eb4c2cca8e985e403b1a97c059 (patch)
treee6da7c4ad676bba189e360caf912b069ed876376
parent070b775f03ebdab6d0d007787fe19b916af4439c (diff)
downloadbinutils-gdb-cff69cf4cf97e1eb4c2cca8e985e403b1a97c059.tar.gz
[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.
-rw-r--r--bfd/ChangeLog6
-rw-r--r--bfd/elfnn-aarch64.c83
-rw-r--r--ld/ChangeLog7
-rw-r--r--ld/testsuite/ld-aarch64/aarch64-elf.exp1
-rw-r--r--ld/testsuite/ld-aarch64/farcall-group.d30
-rw-r--r--ld/testsuite/ld-aarch64/farcall-group.s15
6 files changed, 115 insertions, 27 deletions
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 <wdijkstr@arm.com>
+
+ PR ld/25665
+ * elfnn-aarch64.c (group_sections): Copy implementation from
+ elf32-arm.c.
+
2020-05-01 Alan Modra <amodra@gmail.com>
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,68 +3567,97 @@ 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 <wdijkstr@arm.com>
+
+ 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 <amodra@gmail.com>
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 <end>:
+ 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