1 //===- MapFile.cpp --------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements the -Map option. It shows lists in order and
10 // hierarchically the output sections, input sections, input files and
13 // Address Size Align Out In Symbol
14 // 00201000 00000015 4 .text
15 // 00201000 0000000e 4 test.o:(.text)
16 // 0020100e 00000000 0 local
17 // 00201005 00000000 0 f(int)
19 //===----------------------------------------------------------------------===//
22 #include "InputFiles.h"
23 #include "LinkerScript.h"
24 #include "OutputSections.h"
26 #include "SyntheticSections.h"
27 #include "llvm/ADT/MapVector.h"
28 #include "llvm/ADT/SetVector.h"
29 #include "llvm/ADT/SmallPtrSet.h"
30 #include "llvm/Support/FileSystem.h"
31 #include "llvm/Support/Parallel.h"
32 #include "llvm/Support/TimeProfiler.h"
33 #include "llvm/Support/raw_ostream.h"
36 using namespace llvm::object
;
38 using namespace lld::elf
;
40 using SymbolMapTy
= DenseMap
<const SectionBase
*,
41 SmallVector
<std::pair
<Defined
*, uint64_t>, 0>>;
43 static constexpr char indent8
[] = " "; // 8 spaces
44 static constexpr char indent16
[] = " "; // 16 spaces
46 // Print out the first three columns of a line.
47 static void writeHeader(raw_ostream
&os
, uint64_t vma
, uint64_t lma
,
48 uint64_t size
, uint64_t align
) {
50 os
<< format("%16llx %16llx %8llx %5lld ", vma
, lma
, size
, align
);
52 os
<< format("%8llx %8llx %8llx %5lld ", vma
, lma
, size
, align
);
55 // Returns a list of all symbols that we want to print out.
56 static std::vector
<Defined
*> getSymbols() {
57 std::vector
<Defined
*> v
;
58 for (ELFFileBase
*file
: ctx
.objectFiles
)
59 for (Symbol
*b
: file
->getSymbols())
60 if (auto *dr
= dyn_cast
<Defined
>(b
))
61 if (!dr
->isSection() && dr
->section
&& dr
->section
->isLive() &&
62 (dr
->file
== file
|| dr
->hasFlag(NEEDS_COPY
) || dr
->section
->bss
))
67 // Returns a map from sections to their symbols.
68 static SymbolMapTy
getSectionSyms(ArrayRef
<Defined
*> syms
) {
70 for (Defined
*dr
: syms
)
71 ret
[dr
->section
].emplace_back(dr
, dr
->getVA());
73 // Sort symbols by address. We want to print out symbols in the
74 // order in the output file rather than the order they appeared
75 // in the input files.
76 SmallPtrSet
<Defined
*, 4> set
;
77 for (auto &it
: ret
) {
78 // Deduplicate symbols which need a canonical PLT entry/copy relocation.
80 llvm::erase_if(it
.second
, [&](std::pair
<Defined
*, uint64_t> a
) {
81 return !set
.insert(a
.first
).second
;
84 llvm::stable_sort(it
.second
, llvm::less_second());
89 // Construct a map from symbols to their stringified representations.
90 // Demangling symbols (which is what toString() does) is slow, so
91 // we do that in batch using parallel-for.
92 static DenseMap
<Symbol
*, std::string
>
93 getSymbolStrings(ArrayRef
<Defined
*> syms
) {
94 auto strs
= std::make_unique
<std::string
[]>(syms
.size());
95 parallelFor(0, syms
.size(), [&](size_t i
) {
96 raw_string_ostream
os(strs
[i
]);
97 OutputSection
*osec
= syms
[i
]->getOutputSection();
98 uint64_t vma
= syms
[i
]->getVA();
99 uint64_t lma
= osec
? osec
->getLMA() + vma
- osec
->getVA(0) : 0;
100 writeHeader(os
, vma
, lma
, syms
[i
]->getSize(), 1);
101 os
<< indent16
<< toString(*syms
[i
]);
104 DenseMap
<Symbol
*, std::string
> ret
;
105 for (size_t i
= 0, e
= syms
.size(); i
< e
; ++i
)
106 ret
[syms
[i
]] = std::move(strs
[i
]);
110 // Print .eh_frame contents. Since the section consists of EhSectionPieces,
111 // we need a specialized printer for that section.
113 // .eh_frame tend to contain a lot of section pieces that are contiguous
114 // both in input file and output file. Such pieces are squashed before
115 // being displayed to make output compact.
116 static void printEhFrame(raw_ostream
&os
, const EhFrameSection
*sec
) {
117 std::vector
<EhSectionPiece
> pieces
;
119 auto add
= [&](const EhSectionPiece
&p
) {
120 // If P is adjacent to Last, squash the two.
121 if (!pieces
.empty()) {
122 EhSectionPiece
&last
= pieces
.back();
123 if (last
.sec
== p
.sec
&& last
.inputOff
+ last
.size
== p
.inputOff
&&
124 last
.outputOff
+ last
.size
== p
.outputOff
) {
132 // Gather section pieces.
133 for (const CieRecord
*rec
: sec
->getCieRecords()) {
135 for (const EhSectionPiece
*fde
: rec
->fdes
)
139 // Print out section pieces.
140 const OutputSection
*osec
= sec
->getOutputSection();
141 for (EhSectionPiece
&p
: pieces
) {
142 writeHeader(os
, osec
->addr
+ p
.outputOff
, osec
->getLMA() + p
.outputOff
,
144 os
<< indent8
<< toString(p
.sec
->file
) << ":(" << p
.sec
->name
<< "+0x"
145 << Twine::utohexstr(p
.inputOff
) + ")\n";
149 static void writeMapFile(raw_fd_ostream
&os
) {
150 // Collect symbol info that we want to print out.
151 std::vector
<Defined
*> syms
= getSymbols();
152 SymbolMapTy sectionSyms
= getSectionSyms(syms
);
153 DenseMap
<Symbol
*, std::string
> symStr
= getSymbolStrings(syms
);
155 // Print out the header line.
156 int w
= config
->is64
? 16 : 8;
157 os
<< right_justify("VMA", w
) << ' ' << right_justify("LMA", w
)
158 << " Size Align Out In Symbol\n";
160 OutputSection
*osec
= nullptr;
161 for (SectionCommand
*cmd
: script
->sectionCommands
) {
162 if (auto *assign
= dyn_cast
<SymbolAssignment
>(cmd
)) {
163 if (assign
->provide
&& !assign
->sym
)
165 uint64_t lma
= osec
? osec
->getLMA() + assign
->addr
- osec
->getVA(0) : 0;
166 writeHeader(os
, assign
->addr
, lma
, assign
->size
, 1);
167 os
<< assign
->commandString
<< '\n';
171 osec
= &cast
<OutputDesc
>(cmd
)->osec
;
172 writeHeader(os
, osec
->addr
, osec
->getLMA(), osec
->size
, osec
->addralign
);
173 os
<< osec
->name
<< '\n';
175 // Dump symbols for each input section.
176 for (SectionCommand
*subCmd
: osec
->commands
) {
177 if (auto *isd
= dyn_cast
<InputSectionDescription
>(subCmd
)) {
178 for (InputSection
*isec
: isd
->sections
) {
179 if (auto *ehSec
= dyn_cast
<EhFrameSection
>(isec
)) {
180 printEhFrame(os
, ehSec
);
184 writeHeader(os
, isec
->getVA(), osec
->getLMA() + isec
->outSecOff
,
185 isec
->getSize(), isec
->addralign
);
186 os
<< indent8
<< toString(isec
) << '\n';
187 for (Symbol
*sym
: llvm::make_first_range(sectionSyms
[isec
]))
188 os
<< symStr
[sym
] << '\n';
193 if (auto *data
= dyn_cast
<ByteCommand
>(subCmd
)) {
194 writeHeader(os
, osec
->addr
+ data
->offset
,
195 osec
->getLMA() + data
->offset
, data
->size
, 1);
196 os
<< indent8
<< data
->commandString
<< '\n';
200 if (auto *assign
= dyn_cast
<SymbolAssignment
>(subCmd
)) {
201 if (assign
->provide
&& !assign
->sym
)
203 writeHeader(os
, assign
->addr
,
204 osec
->getLMA() + assign
->addr
- osec
->getVA(0),
206 os
<< indent8
<< assign
->commandString
<< '\n';
213 // Output a cross reference table to stdout. This is for --cref.
215 // For each global symbol, we print out a file that defines the symbol
216 // followed by files that uses that symbol. Here is an example.
218 // strlen /lib/x86_64-linux-gnu/libc.so.6
219 // tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o
220 // lib/libLLVMSupport.a(PrettyStackTrace.cpp.o)
222 // In this case, strlen is defined by libc.so.6 and used by other two
224 static void writeCref(raw_fd_ostream
&os
) {
225 // Collect symbols and files.
226 MapVector
<Symbol
*, SetVector
<InputFile
*>> map
;
227 for (ELFFileBase
*file
: ctx
.objectFiles
) {
228 for (Symbol
*sym
: file
->getSymbols()) {
229 if (isa
<SharedSymbol
>(sym
))
230 map
[sym
].insert(file
);
231 if (auto *d
= dyn_cast
<Defined
>(sym
))
232 if (!d
->isLocal() && (!d
->section
|| d
->section
->isLive()))
237 auto print
= [&](StringRef a
, StringRef b
) {
238 os
<< left_justify(a
, 49) << ' ' << b
<< '\n';
241 // Print a blank line and a header. The format matches GNU ld.
242 os
<< "\nCross Reference Table\n\n";
243 print("Symbol", "File");
245 // Print out a table.
246 for (auto kv
: map
) {
247 Symbol
*sym
= kv
.first
;
248 SetVector
<InputFile
*> &files
= kv
.second
;
250 print(toString(*sym
), toString(sym
->file
));
251 for (InputFile
*file
: files
)
252 if (file
!= sym
->file
)
253 print("", toString(file
));
257 void elf::writeMapAndCref() {
258 if (config
->mapFile
.empty() && !config
->cref
)
261 llvm::TimeTraceScope
timeScope("Write map file");
263 // Open a map file for writing.
265 StringRef mapFile
= config
->mapFile
.empty() ? "-" : config
->mapFile
;
266 raw_fd_ostream
os(mapFile
, ec
, sys::fs::OF_None
);
268 error("cannot open " + mapFile
+ ": " + ec
.message());
272 if (!config
->mapFile
.empty())