From 9e4b9e75e33501ce81153f030c6b0c41847012f9 Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:58:25 -0400 Subject: [PATCH] Sort symbols by address, then parentage, then index (#1186) --- src/link/output.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/link/output.c b/src/link/output.c index 0407a99c..db15cd7d 100644 --- a/src/link/output.c +++ b/src/link/output.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "link/output.h" #include "link/main.h" @@ -325,7 +326,7 @@ static void printSymName(char const *name) } // Comparator function for `qsort` to sort symbols -// Symbols are ordered by address, or else by original index for a stable sort +// Symbols are ordered by address, then by parentage, or else by original index for a stable sort static int compareSymbols(void const *a, void const *b) { struct SortedSymbol const *sym1 = (struct SortedSymbol const *)a; @@ -334,6 +335,24 @@ static int compareSymbols(void const *a, void const *b) if (sym1->addr != sym2->addr) return sym1->addr < sym2->addr ? -1 : 1; + char const *sym1_name = sym1->sym->name; + char const *sym2_name = sym2->sym->name; + bool sym1_local = !!strchr(sym1_name, '.'); + bool sym2_local = !!strchr(sym2_name, '.'); + + if (sym1_local != sym2_local) { + size_t sym1_len = strlen(sym1_name); + size_t sym2_len = strlen(sym2_name); + + // Sort parent labels before their child local labels + if (!strncmp(sym1_name, sym2_name, sym1_len) && sym2_name[sym1_len] == '.') + return -1; + if (!strncmp(sym2_name, sym1_name, sym2_len) && sym1_name[sym2_len] == '.') + return 1; + // Sort local labels before unrelated global labels + return sym1_local ? -1 : 1; + } + return sym1->idx < sym2->idx ? -1 : sym1->idx > sym2->idx ? 1 : 0; }