gas reloc sorting
authorAlan Modra <amodra@gmail.com>
Mon, 20 Dec 2021 14:39:13 +0000 (01:09 +1030)
committerAlan Modra <amodra@gmail.com>
Tue, 28 Dec 2021 12:30:01 +0000 (23:00 +1030)
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.

bfd/elf32-nds32.c
bfd/elf32-nds32.h
gas/config/tc-nds32.c
gas/config/tc-nds32.h
gas/config/tc-riscv.h
gas/write.c

index 5b43ca97803563dc4208e319c262fe2d74a33784..56d1d39181c1dbd11280c18baf7664c8852bb926 100644 (file)
@@ -2522,7 +2522,7 @@ nds32_put_trampoline (void *contents, const unsigned long *template,
 /* nds32_insertion_sort sorts an array with nmemb elements of size size.
    This prototype is the same as qsort ().  */
 
-void
+static void
 nds32_insertion_sort (void *base, size_t nmemb, size_t size,
                      int (*compar) (const void *lhs, const void *rhs))
 {
index 0f496361555f6fa2d7a7f97607822d1251af3d1f..0bf16974421cddd071d41a36c2484a150d5cb3cc 100644 (file)
@@ -95,8 +95,6 @@ extern int elf32_nds32_check_relax_group (bfd *, asection *);
 extern int elf32_nds32_unify_relax_group (bfd *, asection *);
 extern int nds32_elf_unify_tls_model (bfd *, asection *, bfd_byte *,
                                      struct bfd_link_info *);
-extern void nds32_insertion_sort
-(void *, size_t, size_t, int (*) (const void *, const void *));
 
 extern int        nds32_convert_32_to_16 (bfd *, uint32_t, uint16_t *, int *);
 extern int        nds32_convert_16_to_32 (bfd *, uint16_t, uint32_t *);
index 0ab436c5f19cd405ec84d731ec467b7cc2ff5507..228afa616c9f8f2341889d0e769cc871f32337b4 100644 (file)
@@ -7537,45 +7537,6 @@ nds32_allow_local_subtract (expressionS *expr_l ATTRIBUTE_UNUSED,
   return false;
 }
 
-/* Sort relocation by address.
-
-   We didn't use qsort () in stdlib, because quick-sort is not a stable
-   sorting algorithm.  Relocations at the same address (r_offset) must keep
-   their relative order.  For example, RELAX_ENTRY must be the very first
-   relocation entry.
-
-   Currently, this function implements insertion-sort.  */
-
-static int
-compar_relent (const void *lhs, const void *rhs)
-{
-  const arelent **l = (const arelent **) lhs;
-  const arelent **r = (const arelent **) rhs;
-
-  if ((*l)->address > (*r)->address)
-    return 1;
-  else if ((*l)->address == (*r)->address)
-    return 0;
-  else
-    return -1;
-}
-
-/* SET_SECTION_RELOCS ()
-
-   Although this macro is originally used to set a relocation for each section,
-   we use it to sort relocations in the same section by the address of the
-   relocation.  */
-
-void
-nds32_set_section_relocs (asection *sec ATTRIBUTE_UNUSED,
-                         arelent **relocs, unsigned int n)
-{
-  if (n <= 1)
-    return;
-
-  nds32_insertion_sort (relocs, n, sizeof (*relocs), compar_relent);
-}
-
 long
 nds32_pcrel_from_section (fixS *fixP, segT sec ATTRIBUTE_UNUSED)
 {
index da7e38c0094e70c240ef861e5dbfd493764173cc..85a1adb8eed18f5ae4740f8aab866c3cadfe2431 100644 (file)
@@ -88,7 +88,6 @@ extern void nds32_frob_file_before_fix (void);
 extern void elf_nds32_final_processing (void);
 extern int nds32_validate_fix_sub (struct fix *, segT);
 extern int nds32_force_relocation (struct fix *);
-extern void nds32_set_section_relocs (asection *, arelent ** , unsigned int);
 
 /* Fill in rs_align_code fragments.  TODO: Review this.  */
 extern void nds32_handle_align (fragS *);
@@ -110,7 +109,7 @@ extern void tc_nds32_frame_initial_instructions (void);
    || TC_FORCE_RELOCATION (FIX))
 #define TC_FORCE_RELOCATION(fix)               nds32_force_relocation (fix)
 #define TC_VALIDATE_FIX_SUB(FIX,SEG)           nds32_validate_fix_sub (FIX,SEG)
-#define SET_SECTION_RELOCS(sec, relocs, n)     nds32_set_section_relocs (sec, relocs, n)
+#define GAS_SORT_RELOCS                                1
 /* Values passed to md_apply_fix don't include the symbol value.  */
 #define MD_APPLY_SYM_VALUE(FIX)                        0
 #define HANDLE_ALIGN(f)                                nds32_handle_align (f)
index fbe5e765042577ed5c403804898c25ab7e145d5a..1ca02c0bbc6066079896dd4ade43e46c05b102d5 100644 (file)
@@ -78,6 +78,7 @@ extern int riscv_parse_long_option (const char *);
 
 #define md_pre_output_hook riscv_pre_output_hook ()
 extern void riscv_pre_output_hook (void);
+#define GAS_SORT_RELOCS 1
 
 /* Let the linker resolve all the relocs due to relaxation.  */
 #define tc_fix_adjustable(fixp) 0
index e2c7bf2924976ef886e54cb2669b02bd234e1a86..eaa9d21068f2e9c93900352fd45bff2aaffb7aaf 100644 (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