aboutsummaryrefslogtreecommitdiff
path: root/gas/write.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2021-12-21 01:09:13 +1030
committerAlan Modra <amodra@gmail.com>2021-12-28 23:00:01 +1030
commit443aa5f05edb58fc1774f926e9259b7c5a180926 (patch)
treeebc72377ef825f1da276fa3080f91fb49a143341 /gas/write.c
parent4748764aaba89b8515cbf8918dc0ada840cdfab7 (diff)
downloadbinutils-443aa5f05edb58fc1774f926e9259b7c5a180926.zip
binutils-443aa5f05edb58fc1774f926e9259b7c5a180926.tar.gz
binutils-443aa5f05edb58fc1774f926e9259b7c5a180926.tar.bz2
gas reloc sorting
In some cases, eg. riscv_pre_output_hook, gas generates out-of-order relocations. Various places in the linker assume relocs are sorted by increasing r_offset, which is normally the case. Provide GAS_SORT_RELOCS to handle unsorted relocs. bfd/ PR 28709 * elf32-nds32.c (nds32_insertion_sort): Make static. * elf32-nds32.h (nds32_insertion_sort): Delete declaration. gas/ PR 28709 * write.c (write_relocs): Implement reloc sorting by r_offset when GAS_SORT_RELOCS. * config/tc-nds32.c (compar_relent, nds32_set_section_relocs): Delete. * config/tc-nds32.h (nds32_set_section_relocs): Don't declare. (SET_SECTION_RELOCS): Don't define. (GAS_SORT_RELOCS): Define. * config/tc-riscv.h (GAS_SORT_RELOCS): Define.
Diffstat (limited to 'gas/write.c')
-rw-r--r--gas/write.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/gas/write.c b/gas/write.c
index e2c7bf2..eaa9d21 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -1315,7 +1315,34 @@ write_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
}
r = r->next;
}
- relocs[n++] = *reloc;
+#ifdef GAS_SORT_RELOCS
+ if (n != 0 && (*reloc)->address < relocs[n - 1]->address)
+ {
+ size_t lo = 0;
+ size_t hi = n - 1;
+ bfd_vma look = (*reloc)->address;
+ while (lo < hi)
+ {
+ size_t mid = (lo + hi) / 2;
+ if (relocs[mid]->address > look)
+ hi = mid;
+ else
+ {
+ lo = mid + 1;
+ if (relocs[mid]->address == look)
+ break;
+ }
+ }
+ while (lo < hi && relocs[lo]->address == look)
+ lo++;
+ memmove (relocs + lo + 1, relocs + lo,
+ (n - lo) * sizeof (*relocs));
+ n++;
+ relocs[lo] = *reloc;
+ }
+ else
+#endif
+ relocs[n++] = *reloc;
install_reloc (sec, *reloc, fixp->fx_frag,
fixp->fx_file, fixp->fx_line);
#ifndef RELOC_EXPANSION_POSSIBLE