[lld] 811cbfc - [lld][ELF] Implement –print-memory-usage
Petr Hosek via llvm-commits
llvm-commits at lists.llvm.org
Thu May 25 00:14:28 PDT 2023
Author: Petr Hosek
Date: 2023-05-25T07:14:18Z
New Revision: 811cbfc26233587f01f1b7b8cdeb8200747c366a
URL: https://github.com/llvm/llvm-project/commit/811cbfc26233587f01f1b7b8cdeb8200747c366a
DIFF: https://github.com/llvm/llvm-project/commit/811cbfc26233587f01f1b7b8cdeb8200747c366a.diff
LOG: [lld][ELF] Implement –print-memory-usage
This option was introduced in GNU ld in
https://sourceware.org/legacy-ml/binutils/2015-06/msg00086.html and is
often used in embedded development. This change implements this option
in LLD matching the GNU ld output verbatim.
Differential Revision: https://reviews.llvm.org/D150644
Added:
lld/test/ELF/linkerscript/print-memory-usage.s
Modified:
lld/ELF/Config.h
lld/ELF/Driver.cpp
lld/ELF/LinkerScript.cpp
lld/ELF/LinkerScript.h
lld/ELF/Options.td
lld/ELF/Writer.cpp
Removed:
################################################################################
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 9c9a49d9f20ed..956530098c0f1 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -252,6 +252,7 @@ struct Config {
bool pie;
bool printGcSections;
bool printIcfSections;
+ bool printMemoryUsage;
bool relax;
bool relaxGP;
bool relocatable;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index f235ffcbb9559..6325995da2b3b 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1235,6 +1235,7 @@ static void readConfigs(opt::InputArgList &args) {
args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
config->printGcSections =
args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
+ config->printMemoryUsage = args.hasArg(OPT_print_memory_usage);
config->printArchiveStats = args.getLastArgValue(OPT_print_archive_stats);
config->printSymbolOrder =
args.getLastArgValue(OPT_print_symbol_order);
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 9207751cb7d2f..2f183ebc194cd 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -157,8 +157,8 @@ OutputDesc *LinkerScript::getOrCreateOutputSection(StringRef name) {
static void expandMemoryRegion(MemoryRegion *memRegion, uint64_t size,
StringRef secName) {
memRegion->curPos += size;
- uint64_t newSize = memRegion->curPos - (memRegion->origin)().getValue();
- uint64_t length = (memRegion->length)().getValue();
+ uint64_t newSize = memRegion->curPos - memRegion->getOrigin();
+ uint64_t length = memRegion->getLength();
if (newSize > length)
error("section '" + secName + "' will not fit in region '" +
memRegion->name + "': overflowed by " + Twine(newSize - length) +
@@ -1429,3 +1429,30 @@ SmallVector<size_t, 0> LinkerScript::getPhdrIndices(OutputSection *cmd) {
}
return ret;
}
+
+void LinkerScript::printMemoryUsage(raw_ostream& os) {
+ auto printSize = [&](uint64_t size) {
+ if ((size & 0x3fffffff) == 0)
+ os << format_decimal(size >> 30, 10) << " GB";
+ else if ((size & 0xfffff) == 0)
+ os << format_decimal(size >> 20, 10) << " MB";
+ else if ((size & 0x3ff) == 0)
+ os << format_decimal(size >> 10, 10) << " KB";
+ else
+ os << " " << format_decimal(size, 10) << " B";
+ };
+ os << "Memory region Used Size Region Size %age Used\n";
+ for (auto &pair : memoryRegions) {
+ MemoryRegion *m = pair.second;
+ uint64_t usedLength = m->curPos - m->getOrigin();
+ os << right_justify(m->name, 16) << ": ";
+ printSize(usedLength);
+ uint64_t length = m->getLength();
+ if (length != 0) {
+ printSize(length);
+ double percent = usedLength * 100.0 / length;
+ os << " " << format("%6.2f%%", percent);
+ }
+ os << '\n';
+ }
+}
diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h
index 4e566853de519..5b21cd5e619b1 100644
--- a/lld/ELF/LinkerScript.h
+++ b/lld/ELF/LinkerScript.h
@@ -151,6 +151,9 @@ struct MemoryRegion {
uint32_t negInvFlags;
uint64_t curPos = 0;
+ uint64_t getOrigin() const { return origin().getValue(); }
+ uint64_t getLength() const { return length().getValue(); }
+
bool compatibleWith(uint32_t secFlags) const {
if ((secFlags & negFlags) || (~secFlags & negInvFlags))
return false;
@@ -333,6 +336,9 @@ class LinkerScript final {
// Used to handle INSERT AFTER statements.
void processInsertCommands();
+ // Describe memory region usage.
+ void printMemoryUsage(raw_ostream &os);
+
// SECTIONS command list.
SmallVector<SectionCommand *, 0> sectionCommands;
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 8f2a440fd67a2..0c6884afe52d4 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -351,6 +351,9 @@ def push_state: F<"push-state">,
def print_map: F<"print-map">,
HelpText<"Print a link map to the standard output">;
+def print_memory_usage: F<"print-memory-usage">,
+ HelpText<"Report target memory usage">;
+
defm relax: BB<"relax",
"Enable target-specific relaxations if supported (default)",
"Disable target-specific relaxations">;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 9266764ee0f6c..9c2205222165b 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -559,6 +559,10 @@ template <class ELFT> void Writer<ELFT>::run() {
// fails, for example, due to an erroneous file size.
writeMapAndCref();
+ // Handle --print-memory-usage option.
+ if (config->printMemoryUsage)
+ script->printMemoryUsage(lld::outs());
+
if (config->checkSections)
checkSections();
diff --git a/lld/test/ELF/linkerscript/print-memory-usage.s b/lld/test/ELF/linkerscript/print-memory-usage.s
new file mode 100644
index 0000000000000..0db90a940550a
--- /dev/null
+++ b/lld/test/ELF/linkerscript/print-memory-usage.s
@@ -0,0 +1,73 @@
+# REQUIRES: x86
+
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a1.s -o %t/a1.o
+# RUN: ld.lld -T %t/1.t %t/a1.o -o %t/a1 --print-memory-usage \
+# RUN: | FileCheck %s --check-prefix=CHECK1 --match-full-lines --strict-whitespace
+# RUN: ld.lld -T %t/2.t %t/a1.o -o %t/a2 --print-memory-usage \
+# RUN: | FileCheck %s --check-prefix=CHECK2 --match-full-lines --strict-whitespace
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a2.s -o %t/a2.o
+# RUN: ld.lld -T %t/3.t %t/a2.o -o %t/a3 --print-memory-usage \
+# RUN: | FileCheck %s --check-prefix=CHECK3 --match-full-lines --strict-whitespace
+
+# CHECK1:Memory region Used Size Region Size %age Used
+# CHECK1: ROM: 4 B 1 KB 0.39%
+# CHECK1: RAM: 4 B 256 KB 0.00%
+
+# CHECK2:Memory region Used Size Region Size %age Used
+# CHECK2-NOT:{{.}}
+
+# CHECK3:Memory region Used Size Region Size %age Used
+# CHECK3: ROM: 256 KB 1 MB 25.00%
+# CHECK3: RAM: 32 B 2 GB 0.00%
+
+#--- a1.s
+.text
+.globl _start
+_start:
+ .long 1
+
+.data
+.globl b
+b:
+ .long 2
+
+#--- a2.s
+.text
+.globl _start
+_start:
+ .space 256*1024
+
+.data
+.globl b
+b:
+ .space 32
+
+#--- 1.t
+MEMORY {
+ ROM (RX) : ORIGIN = 0x0, LENGTH = 1K
+ RAM (W) : ORIGIN = 0x100000, LENGTH = 256K
+}
+SECTIONS {
+ . = 0;
+ .text : { *(.text) }
+ .data : { *(.data) }
+}
+
+#--- 2.t
+SECTIONS {
+ . = 0;
+ .text : { *(.text) }
+ .data : { *(.data) }
+}
+
+#--- 3.t
+MEMORY {
+ ROM (RX) : ORIGIN = 0x0, LENGTH = 1M
+ RAM (W) : ORIGIN = 0x1000000, LENGTH = 2048M
+}
+SECTIONS {
+ . = 0;
+ .text : { *(.text) }
+ .data : { *(.data) }
+}
More information about the llvm-commits
mailing list