[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