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.
This commit is contained in:
Alan Modra
2021-12-21 01:09:13 +10:30
parent 4748764aab
commit 443aa5f05e
6 changed files with 31 additions and 45 deletions

View File

@@ -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