Skip to content

Commit 811cbfc

Browse files
committed
[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
1 parent 3d90c81 commit 811cbfc

File tree

7 files changed

+117
-2
lines changed

7 files changed

+117
-2
lines changed

lld/ELF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ struct Config {
252252
bool pie;
253253
bool printGcSections;
254254
bool printIcfSections;
255+
bool printMemoryUsage;
255256
bool relax;
256257
bool relaxGP;
257258
bool relocatable;

lld/ELF/Driver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,7 @@ static void readConfigs(opt::InputArgList &args) {
12351235
args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
12361236
config->printGcSections =
12371237
args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
1238+
config->printMemoryUsage = args.hasArg(OPT_print_memory_usage);
12381239
config->printArchiveStats = args.getLastArgValue(OPT_print_archive_stats);
12391240
config->printSymbolOrder =
12401241
args.getLastArgValue(OPT_print_symbol_order);

lld/ELF/LinkerScript.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ OutputDesc *LinkerScript::getOrCreateOutputSection(StringRef name) {
157157
static void expandMemoryRegion(MemoryRegion *memRegion, uint64_t size,
158158
StringRef secName) {
159159
memRegion->curPos += size;
160-
uint64_t newSize = memRegion->curPos - (memRegion->origin)().getValue();
161-
uint64_t length = (memRegion->length)().getValue();
160+
uint64_t newSize = memRegion->curPos - memRegion->getOrigin();
161+
uint64_t length = memRegion->getLength();
162162
if (newSize > length)
163163
error("section '" + secName + "' will not fit in region '" +
164164
memRegion->name + "': overflowed by " + Twine(newSize - length) +
@@ -1429,3 +1429,30 @@ SmallVector<size_t, 0> LinkerScript::getPhdrIndices(OutputSection *cmd) {
14291429
}
14301430
return ret;
14311431
}
1432+
1433+
void LinkerScript::printMemoryUsage(raw_ostream& os) {
1434+
auto printSize = [&](uint64_t size) {
1435+
if ((size & 0x3fffffff) == 0)
1436+
os << format_decimal(size >> 30, 10) << " GB";
1437+
else if ((size & 0xfffff) == 0)
1438+
os << format_decimal(size >> 20, 10) << " MB";
1439+
else if ((size & 0x3ff) == 0)
1440+
os << format_decimal(size >> 10, 10) << " KB";
1441+
else
1442+
os << " " << format_decimal(size, 10) << " B";
1443+
};
1444+
os << "Memory region Used Size Region Size %age Used\n";
1445+
for (auto &pair : memoryRegions) {
1446+
MemoryRegion *m = pair.second;
1447+
uint64_t usedLength = m->curPos - m->getOrigin();
1448+
os << right_justify(m->name, 16) << ": ";
1449+
printSize(usedLength);
1450+
uint64_t length = m->getLength();
1451+
if (length != 0) {
1452+
printSize(length);
1453+
double percent = usedLength * 100.0 / length;
1454+
os << " " << format("%6.2f%%", percent);
1455+
}
1456+
os << '\n';
1457+
}
1458+
}

lld/ELF/LinkerScript.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ struct MemoryRegion {
151151
uint32_t negInvFlags;
152152
uint64_t curPos = 0;
153153

154+
uint64_t getOrigin() const { return origin().getValue(); }
155+
uint64_t getLength() const { return length().getValue(); }
156+
154157
bool compatibleWith(uint32_t secFlags) const {
155158
if ((secFlags & negFlags) || (~secFlags & negInvFlags))
156159
return false;
@@ -333,6 +336,9 @@ class LinkerScript final {
333336
// Used to handle INSERT AFTER statements.
334337
void processInsertCommands();
335338

339+
// Describe memory region usage.
340+
void printMemoryUsage(raw_ostream &os);
341+
336342
// SECTIONS command list.
337343
SmallVector<SectionCommand *, 0> sectionCommands;
338344

lld/ELF/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,9 @@ def push_state: F<"push-state">,
351351
def print_map: F<"print-map">,
352352
HelpText<"Print a link map to the standard output">;
353353

354+
def print_memory_usage: F<"print-memory-usage">,
355+
HelpText<"Report target memory usage">;
356+
354357
defm relax: BB<"relax",
355358
"Enable target-specific relaxations if supported (default)",
356359
"Disable target-specific relaxations">;

lld/ELF/Writer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,10 @@ template <class ELFT> void Writer<ELFT>::run() {
559559
// fails, for example, due to an erroneous file size.
560560
writeMapAndCref();
561561

562+
// Handle --print-memory-usage option.
563+
if (config->printMemoryUsage)
564+
script->printMemoryUsage(lld::outs());
565+
562566
if (config->checkSections)
563567
checkSections();
564568

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# REQUIRES: x86
2+
3+
# RUN: rm -rf %t && split-file %s %t
4+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a1.s -o %t/a1.o
5+
# RUN: ld.lld -T %t/1.t %t/a1.o -o %t/a1 --print-memory-usage \
6+
# RUN: | FileCheck %s --check-prefix=CHECK1 --match-full-lines --strict-whitespace
7+
# RUN: ld.lld -T %t/2.t %t/a1.o -o %t/a2 --print-memory-usage \
8+
# RUN: | FileCheck %s --check-prefix=CHECK2 --match-full-lines --strict-whitespace
9+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a2.s -o %t/a2.o
10+
# RUN: ld.lld -T %t/3.t %t/a2.o -o %t/a3 --print-memory-usage \
11+
# RUN: | FileCheck %s --check-prefix=CHECK3 --match-full-lines --strict-whitespace
12+
13+
# CHECK1:Memory region Used Size Region Size %age Used
14+
# CHECK1: ROM: 4 B 1 KB 0.39%
15+
# CHECK1: RAM: 4 B 256 KB 0.00%
16+
17+
# CHECK2:Memory region Used Size Region Size %age Used
18+
# CHECK2-NOT:{{.}}
19+
20+
# CHECK3:Memory region Used Size Region Size %age Used
21+
# CHECK3: ROM: 256 KB 1 MB 25.00%
22+
# CHECK3: RAM: 32 B 2 GB 0.00%
23+
24+
#--- a1.s
25+
.text
26+
.globl _start
27+
_start:
28+
.long 1
29+
30+
.data
31+
.globl b
32+
b:
33+
.long 2
34+
35+
#--- a2.s
36+
.text
37+
.globl _start
38+
_start:
39+
.space 256*1024
40+
41+
.data
42+
.globl b
43+
b:
44+
.space 32
45+
46+
#--- 1.t
47+
MEMORY {
48+
ROM (RX) : ORIGIN = 0x0, LENGTH = 1K
49+
RAM (W) : ORIGIN = 0x100000, LENGTH = 256K
50+
}
51+
SECTIONS {
52+
. = 0;
53+
.text : { *(.text) }
54+
.data : { *(.data) }
55+
}
56+
57+
#--- 2.t
58+
SECTIONS {
59+
. = 0;
60+
.text : { *(.text) }
61+
.data : { *(.data) }
62+
}
63+
64+
#--- 3.t
65+
MEMORY {
66+
ROM (RX) : ORIGIN = 0x0, LENGTH = 1M
67+
RAM (W) : ORIGIN = 0x1000000, LENGTH = 2048M
68+
}
69+
SECTIONS {
70+
. = 0;
71+
.text : { *(.text) }
72+
.data : { *(.data) }
73+
}

0 commit comments

Comments
 (0)