From bcc1e584483c8246b651290b0c2d696bd57006a9 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 5 Jan 2025 17:13:22 -0800 Subject: [PATCH] [ELF] Allow --symbol-ordering-file and call graph profile to be used together Port https://reviews.llvm.org/D117354 from the MachO port. If both --symbol-ordering-file and call graph profile are present, the --symbol-ordering-file takes precedence, but the call graph profile is still used for symbols that don't appear in the order file. In addition, call graph profile described sections are now ordered before other sections. --- lld/ELF/CallGraphSort.cpp | 4 +-- lld/ELF/Driver.cpp | 7 +---- lld/ELF/Writer.cpp | 15 ++++++----- lld/test/ELF/cgprofile-orderfile.s | 41 ++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 lld/test/ELF/cgprofile-orderfile.s diff --git a/lld/ELF/CallGraphSort.cpp b/lld/ELF/CallGraphSort.cpp index 0b1b4196de37..9caba5c316ea 100644 --- a/lld/ELF/CallGraphSort.cpp +++ b/lld/ELF/CallGraphSort.cpp @@ -235,7 +235,7 @@ DenseMap CallGraphSort::run() { }); DenseMap orderMap; - int curOrder = 1; + int curOrder = -clusters.size(); for (int leader : sorted) { for (int i = leader;;) { orderMap[sections[i]] = curOrder++; @@ -328,7 +328,7 @@ computeCacheDirectedSortOrder(Ctx &ctx) { // Create the final order. DenseMap orderMap; - int curOrder = 1; + int curOrder = -sortedSections.size(); for (uint64_t secIdx : sortedSections) orderMap[sections[secIdx]] = curOrder++; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index e8e99fa874b5..13e8f8ce6df2 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1746,13 +1746,8 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) { if (args.hasArg(OPT_call_graph_ordering_file)) ErrAlways(ctx) << "--symbol-ordering-file and --call-graph-order-file " "may not be used together"; - if (std::optional buffer = - readFile(ctx, arg->getValue())) { + if (auto buffer = readFile(ctx, arg->getValue())) ctx.arg.symbolOrderingFile = getSymbolOrderingFile(ctx, *buffer); - // Also need to disable CallGraphProfileSort to prevent - // LLD order symbols with CGProfile - ctx.arg.callGraphProfileSort = CGProfileSortKind::None; - } } assert(ctx.arg.versionDefinitions.empty()); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 0ea2e60d8482..fe4a0a15ae83 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1080,11 +1080,14 @@ static void maybeShuffle(Ctx &ctx, } } -// Builds section order for handling --symbol-ordering-file. +// Return section order within an InputSectionDescription. +// If both --symbol-ordering-file and call graph profile are present, the order +// file takes precedence, but the call graph profile is still used for symbols +// that don't appear in the order file. static DenseMap buildSectionOrder(Ctx &ctx) { DenseMap sectionOrder; if (!ctx.arg.callGraphProfile.empty()) - return computeCallGraphProfileOrder(ctx); + sectionOrder = computeCallGraphProfileOrder(ctx); if (ctx.arg.symbolOrderingFile.empty()) return sectionOrder; @@ -1098,7 +1101,7 @@ static DenseMap buildSectionOrder(Ctx &ctx) { // appear in the symbol ordering file have the lowest priority 0. // All explicitly mentioned symbols have negative (higher) priorities. DenseMap symbolOrder; - int priority = -ctx.arg.symbolOrderingFile.size(); + int priority = -sectionOrder.size() - ctx.arg.symbolOrderingFile.size(); for (StringRef s : ctx.arg.symbolOrderingFile) symbolOrder.insert({CachedHashStringRef(s), {priority++, false}}); @@ -1254,11 +1257,11 @@ static void sortSection(Ctx &ctx, OutputSection &osec, } } -// If no layout was provided by linker script, we want to apply default -// sorting for special input sections. This also handles --symbol-ordering-file. +// Sort sections within each InputSectionDescription. template void Writer::sortInputSections() { - // Build the order once since it is expensive. + // Assign negative priorities. DenseMap order = buildSectionOrder(ctx); + // Assign non-negative priorities due to --shuffle-sections. maybeShuffle(ctx, order); for (SectionCommand *cmd : ctx.script->sectionCommands) if (auto *osd = dyn_cast(cmd)) diff --git a/lld/test/ELF/cgprofile-orderfile.s b/lld/test/ELF/cgprofile-orderfile.s new file mode 100644 index 000000000000..584b2ecbe293 --- /dev/null +++ b/lld/test/ELF/cgprofile-orderfile.s @@ -0,0 +1,41 @@ +# REQUIRES: x86 + +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o + +# RUN: ld.lld -e A a.o --symbol-ordering-file=order --call-graph-profile-sort=hfsort -o out +# RUN: llvm-nm --numeric-sort out | FileCheck %s +# RUN: ld.lld -e A a.o --call-graph-profile-sort=hfsort -o out1 +# RUN: llvm-nm --numeric-sort out1 | FileCheck %s --check-prefix=ONLY-CG + +#--- order +B +A + +#--- a.s +.section .text.D,"ax"; .globl D; D: + retq + +.section .text.C,"ax"; .globl C; C: + call D + +.section .text.B,"ax"; .globl B; B: + retq + +.section .text.A,"ax"; .globl A; A: + call B + call C + +.cg_profile A, B, 100 +.cg_profile A, C, 40 +.cg_profile C, D, 61 + +# CHECK: T B +# CHECK-NEXT: T A +# CHECK-NEXT: T C +# CHECK-NEXT: T D + +# ONLY-CG: T A +# ONLY-CG-NEXT: T B +# ONLY-CG-NEXT: T C +# ONLY-CG-NEXT: T D