1ece8a530Spatrick //===- MapFile.cpp --------------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick //
9bb684c34Spatrick // This file implements the /map option in the same format as link.exe
10bb684c34Spatrick // (based on observations)
11ece8a530Spatrick //
12bb684c34Spatrick // Header (program name, timestamp info, preferred load address)
13ece8a530Spatrick //
14bb684c34Spatrick // Section list (Start = Section index:Base address):
15bb684c34Spatrick // Start Length Name Class
16bb684c34Spatrick // 0001:00001000 00000015H .text CODE
17bb684c34Spatrick //
18bb684c34Spatrick // Symbols list:
19bb684c34Spatrick // Address Publics by Value Rva + Base Lib:Object
20bb684c34Spatrick // 0001:00001000 main 0000000140001000 main.obj
21bb684c34Spatrick // 0001:00001300 ?__scrt_common_main@@YAHXZ 0000000140001300 libcmt:exe_main.obj
22bb684c34Spatrick //
23bb684c34Spatrick // entry point at 0001:00000360
24bb684c34Spatrick //
25bb684c34Spatrick // Static symbols
26bb684c34Spatrick //
27bb684c34Spatrick // 0000:00000000 __guard_fids__ 0000000140000000 libcmt : exe_main.obj
28ece8a530Spatrick //===----------------------------------------------------------------------===//
29ece8a530Spatrick
30ece8a530Spatrick #include "MapFile.h"
31*dfe94b16Srobert #include "COFFLinkerContext.h"
32ece8a530Spatrick #include "SymbolTable.h"
33ece8a530Spatrick #include "Symbols.h"
34ece8a530Spatrick #include "Writer.h"
35ece8a530Spatrick #include "lld/Common/ErrorHandler.h"
36bb684c34Spatrick #include "lld/Common/Timer.h"
37bb684c34Spatrick #include "llvm/Support/Parallel.h"
38bb684c34Spatrick #include "llvm/Support/Path.h"
39ece8a530Spatrick #include "llvm/Support/raw_ostream.h"
40ece8a530Spatrick
41ece8a530Spatrick using namespace llvm;
42ece8a530Spatrick using namespace llvm::object;
43bb684c34Spatrick using namespace lld;
44bb684c34Spatrick using namespace lld::coff;
45ece8a530Spatrick
46bb684c34Spatrick // Print out the first two columns of a line.
writeHeader(raw_ostream & os,uint32_t sec,uint64_t addr)47bb684c34Spatrick static void writeHeader(raw_ostream &os, uint32_t sec, uint64_t addr) {
48bb684c34Spatrick os << format(" %04x:%08llx", sec, addr);
49ece8a530Spatrick }
50ece8a530Spatrick
51bb684c34Spatrick // Write the time stamp with the format used by link.exe
52bb684c34Spatrick // It seems identical to strftime with "%c" on msvc build, but we need a
53bb684c34Spatrick // locale-agnostic version.
writeFormattedTimestamp(raw_ostream & os,time_t tds)54bb684c34Spatrick static void writeFormattedTimestamp(raw_ostream &os, time_t tds) {
55bb684c34Spatrick constexpr const char *const days[7] = {"Sun", "Mon", "Tue", "Wed",
56bb684c34Spatrick "Thu", "Fri", "Sat"};
57bb684c34Spatrick constexpr const char *const months[12] = {"Jan", "Feb", "Mar", "Apr",
58bb684c34Spatrick "May", "Jun", "Jul", "Aug",
59bb684c34Spatrick "Sep", "Oct", "Nov", "Dec"};
60bb684c34Spatrick tm *time = localtime(&tds);
61bb684c34Spatrick os << format("%s %s %2d %02d:%02d:%02d %d", days[time->tm_wday],
62bb684c34Spatrick months[time->tm_mon], time->tm_mday, time->tm_hour, time->tm_min,
63bb684c34Spatrick time->tm_sec, time->tm_year + 1900);
64ece8a530Spatrick }
65ece8a530Spatrick
sortUniqueSymbols(std::vector<Defined * > & syms,uint64_t imageBase)66*dfe94b16Srobert static void sortUniqueSymbols(std::vector<Defined *> &syms,
67*dfe94b16Srobert uint64_t imageBase) {
68bb684c34Spatrick // Build helper vector
69bb684c34Spatrick using SortEntry = std::pair<Defined *, size_t>;
70bb684c34Spatrick std::vector<SortEntry> v;
71bb684c34Spatrick v.resize(syms.size());
72bb684c34Spatrick for (size_t i = 0, e = syms.size(); i < e; ++i)
73bb684c34Spatrick v[i] = SortEntry(syms[i], i);
74ece8a530Spatrick
75bb684c34Spatrick // Remove duplicate symbol pointers
76bb684c34Spatrick parallelSort(v, std::less<SortEntry>());
77bb684c34Spatrick auto end = std::unique(v.begin(), v.end(),
78bb684c34Spatrick [](const SortEntry &a, const SortEntry &b) {
79bb684c34Spatrick return a.first == b.first;
80ece8a530Spatrick });
81bb684c34Spatrick v.erase(end, v.end());
82bb684c34Spatrick
83bb684c34Spatrick // Sort by RVA then original order
84*dfe94b16Srobert parallelSort(v, [imageBase](const SortEntry &a, const SortEntry &b) {
85*dfe94b16Srobert // Add config.imageBase to avoid comparing "negative" RVAs.
86bb684c34Spatrick // This can happen with symbols of Absolute kind
87*dfe94b16Srobert uint64_t rvaa = imageBase + a.first->getRVA();
88*dfe94b16Srobert uint64_t rvab = imageBase + b.first->getRVA();
89bb684c34Spatrick return rvaa < rvab || (rvaa == rvab && a.second < b.second);
90bb684c34Spatrick });
91bb684c34Spatrick
92bb684c34Spatrick syms.resize(v.size());
93bb684c34Spatrick for (size_t i = 0, e = v.size(); i < e; ++i)
94bb684c34Spatrick syms[i] = v[i].first;
95ece8a530Spatrick }
96bb684c34Spatrick
97bb684c34Spatrick // Returns the lists of all symbols that we want to print out.
getSymbols(const COFFLinkerContext & ctx,std::vector<Defined * > & syms,std::vector<Defined * > & staticSyms)98*dfe94b16Srobert static void getSymbols(const COFFLinkerContext &ctx,
99*dfe94b16Srobert std::vector<Defined *> &syms,
100bb684c34Spatrick std::vector<Defined *> &staticSyms) {
101bb684c34Spatrick
102*dfe94b16Srobert for (ObjFile *file : ctx.objFileInstances)
103bb684c34Spatrick for (Symbol *b : file->getSymbols()) {
104bb684c34Spatrick if (!b || !b->isLive())
105bb684c34Spatrick continue;
106bb684c34Spatrick if (auto *sym = dyn_cast<DefinedCOFF>(b)) {
107bb684c34Spatrick COFFSymbolRef symRef = sym->getCOFFSymbol();
108bb684c34Spatrick if (!symRef.isSectionDefinition() &&
109bb684c34Spatrick symRef.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL) {
110bb684c34Spatrick if (symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC)
111bb684c34Spatrick staticSyms.push_back(sym);
112bb684c34Spatrick else
113bb684c34Spatrick syms.push_back(sym);
114bb684c34Spatrick }
115bb684c34Spatrick } else if (auto *sym = dyn_cast<Defined>(b)) {
116bb684c34Spatrick syms.push_back(sym);
117bb684c34Spatrick }
118bb684c34Spatrick }
119bb684c34Spatrick
120*dfe94b16Srobert for (ImportFile *file : ctx.importFileInstances) {
121bb684c34Spatrick if (!file->live)
122bb684c34Spatrick continue;
123bb684c34Spatrick
124bb684c34Spatrick if (!file->thunkSym)
125bb684c34Spatrick continue;
126bb684c34Spatrick
127bb684c34Spatrick if (!file->thunkLive)
128bb684c34Spatrick continue;
129bb684c34Spatrick
130bb684c34Spatrick if (auto *thunkSym = dyn_cast<Defined>(file->thunkSym))
131bb684c34Spatrick syms.push_back(thunkSym);
132bb684c34Spatrick
133bb684c34Spatrick if (auto *impSym = dyn_cast_or_null<Defined>(file->impSym))
134bb684c34Spatrick syms.push_back(impSym);
135bb684c34Spatrick }
136bb684c34Spatrick
137*dfe94b16Srobert sortUniqueSymbols(syms, ctx.config.imageBase);
138*dfe94b16Srobert sortUniqueSymbols(staticSyms, ctx.config.imageBase);
139ece8a530Spatrick }
140ece8a530Spatrick
141ece8a530Spatrick // Construct a map from symbols to their stringified representations.
142bb684c34Spatrick static DenseMap<Defined *, std::string>
getSymbolStrings(const COFFLinkerContext & ctx,ArrayRef<Defined * > syms)143*dfe94b16Srobert getSymbolStrings(const COFFLinkerContext &ctx, ArrayRef<Defined *> syms) {
144ece8a530Spatrick std::vector<std::string> str(syms.size());
145*dfe94b16Srobert parallelFor((size_t)0, syms.size(), [&](size_t i) {
146ece8a530Spatrick raw_string_ostream os(str[i]);
147bb684c34Spatrick Defined *sym = syms[i];
148bb684c34Spatrick
149bb684c34Spatrick uint16_t sectionIdx = 0;
150bb684c34Spatrick uint64_t address = 0;
151bb684c34Spatrick SmallString<128> fileDescr;
152bb684c34Spatrick
153bb684c34Spatrick if (auto *absSym = dyn_cast<DefinedAbsolute>(sym)) {
154bb684c34Spatrick address = absSym->getVA();
155bb684c34Spatrick fileDescr = "<absolute>";
156bb684c34Spatrick } else if (isa<DefinedSynthetic>(sym)) {
157bb684c34Spatrick fileDescr = "<linker-defined>";
158bb684c34Spatrick } else if (isa<DefinedCommon>(sym)) {
159bb684c34Spatrick fileDescr = "<common>";
160bb684c34Spatrick } else if (Chunk *chunk = sym->getChunk()) {
161bb684c34Spatrick address = sym->getRVA();
162*dfe94b16Srobert if (OutputSection *sec = ctx.getOutputSection(chunk))
163bb684c34Spatrick address -= sec->header.VirtualAddress;
164bb684c34Spatrick
165bb684c34Spatrick sectionIdx = chunk->getOutputSectionIdx();
166bb684c34Spatrick
167bb684c34Spatrick InputFile *file;
168bb684c34Spatrick if (auto *impSym = dyn_cast<DefinedImportData>(sym))
169bb684c34Spatrick file = impSym->file;
170bb684c34Spatrick else if (auto *thunkSym = dyn_cast<DefinedImportThunk>(sym))
171bb684c34Spatrick file = thunkSym->wrappedSym->file;
172bb684c34Spatrick else
173bb684c34Spatrick file = sym->getFile();
174bb684c34Spatrick
175bb684c34Spatrick if (file) {
176bb684c34Spatrick if (!file->parentName.empty()) {
177bb684c34Spatrick fileDescr = sys::path::filename(file->parentName);
178bb684c34Spatrick sys::path::replace_extension(fileDescr, "");
179bb684c34Spatrick fileDescr += ":";
180bb684c34Spatrick }
181bb684c34Spatrick fileDescr += sys::path::filename(file->getName());
182bb684c34Spatrick }
183bb684c34Spatrick }
184bb684c34Spatrick writeHeader(os, sectionIdx, address);
185bb684c34Spatrick os << " ";
186bb684c34Spatrick os << left_justify(sym->getName(), 26);
187bb684c34Spatrick os << " ";
188*dfe94b16Srobert os << format_hex_no_prefix((ctx.config.imageBase + sym->getRVA()), 16);
189bb684c34Spatrick if (!fileDescr.empty()) {
190bb684c34Spatrick os << " "; // FIXME : Handle "f" and "i" flags sometimes generated
191bb684c34Spatrick // by link.exe in those spaces
192bb684c34Spatrick os << fileDescr;
193bb684c34Spatrick }
194ece8a530Spatrick });
195ece8a530Spatrick
196bb684c34Spatrick DenseMap<Defined *, std::string> ret;
197ece8a530Spatrick for (size_t i = 0, e = syms.size(); i < e; ++i)
198ece8a530Spatrick ret[syms[i]] = std::move(str[i]);
199ece8a530Spatrick return ret;
200ece8a530Spatrick }
201ece8a530Spatrick
writeMapFile(COFFLinkerContext & ctx)202*dfe94b16Srobert void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
203*dfe94b16Srobert if (ctx.config.mapFile.empty())
204ece8a530Spatrick return;
205ece8a530Spatrick
206ece8a530Spatrick std::error_code ec;
207*dfe94b16Srobert raw_fd_ostream os(ctx.config.mapFile, ec, sys::fs::OF_None);
208ece8a530Spatrick if (ec)
209*dfe94b16Srobert fatal("cannot open " + ctx.config.mapFile + ": " + ec.message());
210ece8a530Spatrick
211*dfe94b16Srobert ScopedTimer t1(ctx.totalMapTimer);
212bb684c34Spatrick
213ece8a530Spatrick // Collect symbol info that we want to print out.
214*dfe94b16Srobert ScopedTimer t2(ctx.symbolGatherTimer);
215bb684c34Spatrick std::vector<Defined *> syms;
216bb684c34Spatrick std::vector<Defined *> staticSyms;
217*dfe94b16Srobert getSymbols(ctx, syms, staticSyms);
218bb684c34Spatrick t2.stop();
219ece8a530Spatrick
220*dfe94b16Srobert ScopedTimer t3(ctx.symbolStringsTimer);
221*dfe94b16Srobert DenseMap<Defined *, std::string> symStr = getSymbolStrings(ctx, syms);
222*dfe94b16Srobert DenseMap<Defined *, std::string> staticSymStr =
223*dfe94b16Srobert getSymbolStrings(ctx, staticSyms);
224bb684c34Spatrick t3.stop();
225ece8a530Spatrick
226*dfe94b16Srobert ScopedTimer t4(ctx.writeTimer);
227*dfe94b16Srobert SmallString<128> AppName = sys::path::filename(ctx.config.outputFile);
228bb684c34Spatrick sys::path::replace_extension(AppName, "");
229bb684c34Spatrick
230bb684c34Spatrick // Print out the file header
231bb684c34Spatrick os << " " << AppName << "\n";
232bb684c34Spatrick os << "\n";
233bb684c34Spatrick
234*dfe94b16Srobert os << " Timestamp is " << format_hex_no_prefix(ctx.config.timestamp, 8)
235*dfe94b16Srobert << " (";
236*dfe94b16Srobert if (ctx.config.repro) {
237bb684c34Spatrick os << "Repro mode";
238bb684c34Spatrick } else {
239*dfe94b16Srobert writeFormattedTimestamp(os, ctx.config.timestamp);
240bb684c34Spatrick }
241bb684c34Spatrick os << ")\n";
242bb684c34Spatrick
243bb684c34Spatrick os << "\n";
244bb684c34Spatrick os << " Preferred load address is "
245*dfe94b16Srobert << format_hex_no_prefix(ctx.config.imageBase, 16) << "\n";
246bb684c34Spatrick os << "\n";
247bb684c34Spatrick
248bb684c34Spatrick // Print out section table.
249bb684c34Spatrick os << " Start Length Name Class\n";
250bb684c34Spatrick
251*dfe94b16Srobert for (OutputSection *sec : ctx.outputSections) {
252bb684c34Spatrick // Merge display of chunks with same sectionName
253bb684c34Spatrick std::vector<std::pair<SectionChunk *, SectionChunk *>> ChunkRanges;
254ece8a530Spatrick for (Chunk *c : sec->chunks) {
255ece8a530Spatrick auto *sc = dyn_cast<SectionChunk>(c);
256ece8a530Spatrick if (!sc)
257ece8a530Spatrick continue;
258ece8a530Spatrick
259bb684c34Spatrick if (ChunkRanges.empty() ||
260bb684c34Spatrick c->getSectionName() != ChunkRanges.back().first->getSectionName()) {
261bb684c34Spatrick ChunkRanges.emplace_back(sc, sc);
262bb684c34Spatrick } else {
263bb684c34Spatrick ChunkRanges.back().second = sc;
264ece8a530Spatrick }
265ece8a530Spatrick }
266ece8a530Spatrick
267bb684c34Spatrick const bool isCodeSection =
268bb684c34Spatrick (sec->header.Characteristics & COFF::IMAGE_SCN_CNT_CODE) &&
269bb684c34Spatrick (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_READ) &&
270bb684c34Spatrick (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE);
271bb684c34Spatrick StringRef SectionClass = (isCodeSection ? "CODE" : "DATA");
272bb684c34Spatrick
273bb684c34Spatrick for (auto &cr : ChunkRanges) {
274bb684c34Spatrick size_t size =
275bb684c34Spatrick cr.second->getRVA() + cr.second->getSize() - cr.first->getRVA();
276bb684c34Spatrick
277bb684c34Spatrick auto address = cr.first->getRVA() - sec->header.VirtualAddress;
278bb684c34Spatrick writeHeader(os, sec->sectionIndex, address);
279bb684c34Spatrick os << " " << format_hex_no_prefix(size, 8) << "H";
280bb684c34Spatrick os << " " << left_justify(cr.first->getSectionName(), 23);
281bb684c34Spatrick os << " " << SectionClass;
282bb684c34Spatrick os << '\n';
283bb684c34Spatrick }
284bb684c34Spatrick }
285bb684c34Spatrick
286bb684c34Spatrick // Print out the symbols table (without static symbols)
287bb684c34Spatrick os << "\n";
288bb684c34Spatrick os << " Address Publics by Value Rva+Base"
289bb684c34Spatrick " Lib:Object\n";
290bb684c34Spatrick os << "\n";
291bb684c34Spatrick for (Defined *sym : syms)
292bb684c34Spatrick os << symStr[sym] << '\n';
293bb684c34Spatrick
294bb684c34Spatrick // Print out the entry point.
295bb684c34Spatrick os << "\n";
296bb684c34Spatrick
297bb684c34Spatrick uint16_t entrySecIndex = 0;
298bb684c34Spatrick uint64_t entryAddress = 0;
299bb684c34Spatrick
300*dfe94b16Srobert if (!ctx.config.noEntry) {
301*dfe94b16Srobert Defined *entry = dyn_cast_or_null<Defined>(ctx.config.entry);
302bb684c34Spatrick if (entry) {
303bb684c34Spatrick Chunk *chunk = entry->getChunk();
304bb684c34Spatrick entrySecIndex = chunk->getOutputSectionIdx();
305bb684c34Spatrick entryAddress =
306*dfe94b16Srobert entry->getRVA() - ctx.getOutputSection(chunk)->header.VirtualAddress;
307bb684c34Spatrick }
308bb684c34Spatrick }
309bb684c34Spatrick os << " entry point at ";
310bb684c34Spatrick os << format("%04x:%08llx", entrySecIndex, entryAddress);
311bb684c34Spatrick os << "\n";
312bb684c34Spatrick
313bb684c34Spatrick // Print out the static symbols
314bb684c34Spatrick os << "\n";
315bb684c34Spatrick os << " Static symbols\n";
316bb684c34Spatrick os << "\n";
317bb684c34Spatrick for (Defined *sym : staticSyms)
318bb684c34Spatrick os << staticSymStr[sym] << '\n';
319bb684c34Spatrick
320*dfe94b16Srobert // Print out the exported functions
321*dfe94b16Srobert if (ctx.config.mapInfo) {
322*dfe94b16Srobert os << "\n";
323*dfe94b16Srobert os << " Exports\n";
324*dfe94b16Srobert os << "\n";
325*dfe94b16Srobert os << " ordinal name\n\n";
326*dfe94b16Srobert for (Export &e : ctx.config.exports) {
327*dfe94b16Srobert os << format(" %7d", e.ordinal) << " " << e.name << "\n";
328*dfe94b16Srobert if (!e.extName.empty() && e.extName != e.name)
329*dfe94b16Srobert os << " exported name: " << e.extName << "\n";
330*dfe94b16Srobert }
331*dfe94b16Srobert }
332*dfe94b16Srobert
333bb684c34Spatrick t4.stop();
334bb684c34Spatrick t1.stop();
335bb684c34Spatrick }
336