10b57cec5SDimitry Andric //===- MapFile.cpp --------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 95ffd83dbSDimitry Andric // This file implements the /map option in the same format as link.exe 105ffd83dbSDimitry Andric // (based on observations) 110b57cec5SDimitry Andric // 125ffd83dbSDimitry Andric // Header (program name, timestamp info, preferred load address) 130b57cec5SDimitry Andric // 145ffd83dbSDimitry Andric // Section list (Start = Section index:Base address): 155ffd83dbSDimitry Andric // Start Length Name Class 165ffd83dbSDimitry Andric // 0001:00001000 00000015H .text CODE 175ffd83dbSDimitry Andric // 185ffd83dbSDimitry Andric // Symbols list: 195ffd83dbSDimitry Andric // Address Publics by Value Rva + Base Lib:Object 205ffd83dbSDimitry Andric // 0001:00001000 main 0000000140001000 main.obj 215ffd83dbSDimitry Andric // 0001:00001300 ?__scrt_common_main@@YAHXZ 0000000140001300 libcmt:exe_main.obj 225ffd83dbSDimitry Andric // 235ffd83dbSDimitry Andric // entry point at 0001:00000360 245ffd83dbSDimitry Andric // 255ffd83dbSDimitry Andric // Static symbols 265ffd83dbSDimitry Andric // 275ffd83dbSDimitry Andric // 0000:00000000 __guard_fids__ 0000000140000000 libcmt : exe_main.obj 280b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric #include "MapFile.h" 31349cc55cSDimitry Andric #include "COFFLinkerContext.h" 320b57cec5SDimitry Andric #include "SymbolTable.h" 330b57cec5SDimitry Andric #include "Symbols.h" 340b57cec5SDimitry Andric #include "Writer.h" 350b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h" 365ffd83dbSDimitry Andric #include "lld/Common/Timer.h" 375ffd83dbSDimitry Andric #include "llvm/Support/Parallel.h" 385ffd83dbSDimitry Andric #include "llvm/Support/Path.h" 39*5f757f3fSDimitry Andric #include "llvm/Support/TimeProfiler.h" 400b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric using namespace llvm; 430b57cec5SDimitry Andric using namespace llvm::object; 445ffd83dbSDimitry Andric using namespace lld; 455ffd83dbSDimitry Andric using namespace lld::coff; 460b57cec5SDimitry Andric 475ffd83dbSDimitry Andric // Print out the first two columns of a line. 485ffd83dbSDimitry Andric static void writeHeader(raw_ostream &os, uint32_t sec, uint64_t addr) { 495ffd83dbSDimitry Andric os << format(" %04x:%08llx", sec, addr); 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric 525ffd83dbSDimitry Andric // Write the time stamp with the format used by link.exe 535ffd83dbSDimitry Andric // It seems identical to strftime with "%c" on msvc build, but we need a 545ffd83dbSDimitry Andric // locale-agnostic version. 555ffd83dbSDimitry Andric static void writeFormattedTimestamp(raw_ostream &os, time_t tds) { 565ffd83dbSDimitry Andric constexpr const char *const days[7] = {"Sun", "Mon", "Tue", "Wed", 575ffd83dbSDimitry Andric "Thu", "Fri", "Sat"}; 585ffd83dbSDimitry Andric constexpr const char *const months[12] = {"Jan", "Feb", "Mar", "Apr", 595ffd83dbSDimitry Andric "May", "Jun", "Jul", "Aug", 605ffd83dbSDimitry Andric "Sep", "Oct", "Nov", "Dec"}; 615ffd83dbSDimitry Andric tm *time = localtime(&tds); 625ffd83dbSDimitry Andric os << format("%s %s %2d %02d:%02d:%02d %d", days[time->tm_wday], 635ffd83dbSDimitry Andric months[time->tm_mon], time->tm_mday, time->tm_hour, time->tm_min, 645ffd83dbSDimitry Andric time->tm_sec, time->tm_year + 1900); 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 67bdd1243dSDimitry Andric static void sortUniqueSymbols(std::vector<Defined *> &syms, 68bdd1243dSDimitry Andric uint64_t imageBase) { 695ffd83dbSDimitry Andric // Build helper vector 705ffd83dbSDimitry Andric using SortEntry = std::pair<Defined *, size_t>; 715ffd83dbSDimitry Andric std::vector<SortEntry> v; 725ffd83dbSDimitry Andric v.resize(syms.size()); 735ffd83dbSDimitry Andric for (size_t i = 0, e = syms.size(); i < e; ++i) 745ffd83dbSDimitry Andric v[i] = SortEntry(syms[i], i); 750b57cec5SDimitry Andric 765ffd83dbSDimitry Andric // Remove duplicate symbol pointers 775ffd83dbSDimitry Andric parallelSort(v, std::less<SortEntry>()); 785ffd83dbSDimitry Andric auto end = std::unique(v.begin(), v.end(), 795ffd83dbSDimitry Andric [](const SortEntry &a, const SortEntry &b) { 805ffd83dbSDimitry Andric return a.first == b.first; 810b57cec5SDimitry Andric }); 825ffd83dbSDimitry Andric v.erase(end, v.end()); 835ffd83dbSDimitry Andric 845ffd83dbSDimitry Andric // Sort by RVA then original order 85bdd1243dSDimitry Andric parallelSort(v, [imageBase](const SortEntry &a, const SortEntry &b) { 86bdd1243dSDimitry Andric // Add config.imageBase to avoid comparing "negative" RVAs. 875ffd83dbSDimitry Andric // This can happen with symbols of Absolute kind 88bdd1243dSDimitry Andric uint64_t rvaa = imageBase + a.first->getRVA(); 89bdd1243dSDimitry Andric uint64_t rvab = imageBase + b.first->getRVA(); 905ffd83dbSDimitry Andric return rvaa < rvab || (rvaa == rvab && a.second < b.second); 915ffd83dbSDimitry Andric }); 925ffd83dbSDimitry Andric 935ffd83dbSDimitry Andric syms.resize(v.size()); 945ffd83dbSDimitry Andric for (size_t i = 0, e = v.size(); i < e; ++i) 955ffd83dbSDimitry Andric syms[i] = v[i].first; 960b57cec5SDimitry Andric } 975ffd83dbSDimitry Andric 985ffd83dbSDimitry Andric // Returns the lists of all symbols that we want to print out. 99349cc55cSDimitry Andric static void getSymbols(const COFFLinkerContext &ctx, 100349cc55cSDimitry Andric std::vector<Defined *> &syms, 1015ffd83dbSDimitry Andric std::vector<Defined *> &staticSyms) { 1025ffd83dbSDimitry Andric 103349cc55cSDimitry Andric for (ObjFile *file : ctx.objFileInstances) 1045ffd83dbSDimitry Andric for (Symbol *b : file->getSymbols()) { 1055ffd83dbSDimitry Andric if (!b || !b->isLive()) 1065ffd83dbSDimitry Andric continue; 1075ffd83dbSDimitry Andric if (auto *sym = dyn_cast<DefinedCOFF>(b)) { 1085ffd83dbSDimitry Andric COFFSymbolRef symRef = sym->getCOFFSymbol(); 1095ffd83dbSDimitry Andric if (!symRef.isSectionDefinition() && 1105ffd83dbSDimitry Andric symRef.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL) { 1115ffd83dbSDimitry Andric if (symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC) 1125ffd83dbSDimitry Andric staticSyms.push_back(sym); 1135ffd83dbSDimitry Andric else 1145ffd83dbSDimitry Andric syms.push_back(sym); 1155ffd83dbSDimitry Andric } 1165ffd83dbSDimitry Andric } else if (auto *sym = dyn_cast<Defined>(b)) { 1175ffd83dbSDimitry Andric syms.push_back(sym); 1185ffd83dbSDimitry Andric } 1195ffd83dbSDimitry Andric } 1205ffd83dbSDimitry Andric 121349cc55cSDimitry Andric for (ImportFile *file : ctx.importFileInstances) { 1225ffd83dbSDimitry Andric if (!file->live) 1235ffd83dbSDimitry Andric continue; 1245ffd83dbSDimitry Andric 1255ffd83dbSDimitry Andric if (!file->thunkSym) 1265ffd83dbSDimitry Andric continue; 1275ffd83dbSDimitry Andric 1285ffd83dbSDimitry Andric if (!file->thunkLive) 1295ffd83dbSDimitry Andric continue; 1305ffd83dbSDimitry Andric 1315ffd83dbSDimitry Andric if (auto *thunkSym = dyn_cast<Defined>(file->thunkSym)) 1325ffd83dbSDimitry Andric syms.push_back(thunkSym); 1335ffd83dbSDimitry Andric 1345ffd83dbSDimitry Andric if (auto *impSym = dyn_cast_or_null<Defined>(file->impSym)) 1355ffd83dbSDimitry Andric syms.push_back(impSym); 1365ffd83dbSDimitry Andric } 1375ffd83dbSDimitry Andric 138bdd1243dSDimitry Andric sortUniqueSymbols(syms, ctx.config.imageBase); 139bdd1243dSDimitry Andric sortUniqueSymbols(staticSyms, ctx.config.imageBase); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric // Construct a map from symbols to their stringified representations. 1435ffd83dbSDimitry Andric static DenseMap<Defined *, std::string> 144349cc55cSDimitry Andric getSymbolStrings(const COFFLinkerContext &ctx, ArrayRef<Defined *> syms) { 1450b57cec5SDimitry Andric std::vector<std::string> str(syms.size()); 14681ad6265SDimitry Andric parallelFor((size_t)0, syms.size(), [&](size_t i) { 1470b57cec5SDimitry Andric raw_string_ostream os(str[i]); 1485ffd83dbSDimitry Andric Defined *sym = syms[i]; 1495ffd83dbSDimitry Andric 1505ffd83dbSDimitry Andric uint16_t sectionIdx = 0; 1515ffd83dbSDimitry Andric uint64_t address = 0; 1525ffd83dbSDimitry Andric SmallString<128> fileDescr; 1535ffd83dbSDimitry Andric 1545ffd83dbSDimitry Andric if (auto *absSym = dyn_cast<DefinedAbsolute>(sym)) { 1555ffd83dbSDimitry Andric address = absSym->getVA(); 1565ffd83dbSDimitry Andric fileDescr = "<absolute>"; 1575ffd83dbSDimitry Andric } else if (isa<DefinedSynthetic>(sym)) { 1585ffd83dbSDimitry Andric fileDescr = "<linker-defined>"; 1595ffd83dbSDimitry Andric } else if (isa<DefinedCommon>(sym)) { 1605ffd83dbSDimitry Andric fileDescr = "<common>"; 1615ffd83dbSDimitry Andric } else if (Chunk *chunk = sym->getChunk()) { 1625ffd83dbSDimitry Andric address = sym->getRVA(); 163349cc55cSDimitry Andric if (OutputSection *sec = ctx.getOutputSection(chunk)) 1645ffd83dbSDimitry Andric address -= sec->header.VirtualAddress; 1655ffd83dbSDimitry Andric 1665ffd83dbSDimitry Andric sectionIdx = chunk->getOutputSectionIdx(); 1675ffd83dbSDimitry Andric 1685ffd83dbSDimitry Andric InputFile *file; 1695ffd83dbSDimitry Andric if (auto *impSym = dyn_cast<DefinedImportData>(sym)) 1705ffd83dbSDimitry Andric file = impSym->file; 1715ffd83dbSDimitry Andric else if (auto *thunkSym = dyn_cast<DefinedImportThunk>(sym)) 1725ffd83dbSDimitry Andric file = thunkSym->wrappedSym->file; 1735ffd83dbSDimitry Andric else 1745ffd83dbSDimitry Andric file = sym->getFile(); 1755ffd83dbSDimitry Andric 1765ffd83dbSDimitry Andric if (file) { 1775ffd83dbSDimitry Andric if (!file->parentName.empty()) { 1785ffd83dbSDimitry Andric fileDescr = sys::path::filename(file->parentName); 1795ffd83dbSDimitry Andric sys::path::replace_extension(fileDescr, ""); 1805ffd83dbSDimitry Andric fileDescr += ":"; 1815ffd83dbSDimitry Andric } 1825ffd83dbSDimitry Andric fileDescr += sys::path::filename(file->getName()); 1835ffd83dbSDimitry Andric } 1845ffd83dbSDimitry Andric } 1855ffd83dbSDimitry Andric writeHeader(os, sectionIdx, address); 1865ffd83dbSDimitry Andric os << " "; 1875ffd83dbSDimitry Andric os << left_justify(sym->getName(), 26); 1885ffd83dbSDimitry Andric os << " "; 189bdd1243dSDimitry Andric os << format_hex_no_prefix((ctx.config.imageBase + sym->getRVA()), 16); 1905ffd83dbSDimitry Andric if (!fileDescr.empty()) { 1915ffd83dbSDimitry Andric os << " "; // FIXME : Handle "f" and "i" flags sometimes generated 1925ffd83dbSDimitry Andric // by link.exe in those spaces 1935ffd83dbSDimitry Andric os << fileDescr; 1945ffd83dbSDimitry Andric } 1950b57cec5SDimitry Andric }); 1960b57cec5SDimitry Andric 1975ffd83dbSDimitry Andric DenseMap<Defined *, std::string> ret; 1980b57cec5SDimitry Andric for (size_t i = 0, e = syms.size(); i < e; ++i) 1990b57cec5SDimitry Andric ret[syms[i]] = std::move(str[i]); 2000b57cec5SDimitry Andric return ret; 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 203349cc55cSDimitry Andric void lld::coff::writeMapFile(COFFLinkerContext &ctx) { 204bdd1243dSDimitry Andric if (ctx.config.mapFile.empty()) 2050b57cec5SDimitry Andric return; 2060b57cec5SDimitry Andric 207*5f757f3fSDimitry Andric llvm::TimeTraceScope timeScope("Map file"); 2080b57cec5SDimitry Andric std::error_code ec; 209bdd1243dSDimitry Andric raw_fd_ostream os(ctx.config.mapFile, ec, sys::fs::OF_None); 2100b57cec5SDimitry Andric if (ec) 211bdd1243dSDimitry Andric fatal("cannot open " + ctx.config.mapFile + ": " + ec.message()); 2120b57cec5SDimitry Andric 213349cc55cSDimitry Andric ScopedTimer t1(ctx.totalMapTimer); 2145ffd83dbSDimitry Andric 2150b57cec5SDimitry Andric // Collect symbol info that we want to print out. 216349cc55cSDimitry Andric ScopedTimer t2(ctx.symbolGatherTimer); 2175ffd83dbSDimitry Andric std::vector<Defined *> syms; 2185ffd83dbSDimitry Andric std::vector<Defined *> staticSyms; 219349cc55cSDimitry Andric getSymbols(ctx, syms, staticSyms); 2205ffd83dbSDimitry Andric t2.stop(); 2210b57cec5SDimitry Andric 222349cc55cSDimitry Andric ScopedTimer t3(ctx.symbolStringsTimer); 223349cc55cSDimitry Andric DenseMap<Defined *, std::string> symStr = getSymbolStrings(ctx, syms); 224349cc55cSDimitry Andric DenseMap<Defined *, std::string> staticSymStr = 225349cc55cSDimitry Andric getSymbolStrings(ctx, staticSyms); 2265ffd83dbSDimitry Andric t3.stop(); 2270b57cec5SDimitry Andric 228349cc55cSDimitry Andric ScopedTimer t4(ctx.writeTimer); 229bdd1243dSDimitry Andric SmallString<128> AppName = sys::path::filename(ctx.config.outputFile); 2305ffd83dbSDimitry Andric sys::path::replace_extension(AppName, ""); 2315ffd83dbSDimitry Andric 2325ffd83dbSDimitry Andric // Print out the file header 2335ffd83dbSDimitry Andric os << " " << AppName << "\n"; 2345ffd83dbSDimitry Andric os << "\n"; 2355ffd83dbSDimitry Andric 236bdd1243dSDimitry Andric os << " Timestamp is " << format_hex_no_prefix(ctx.config.timestamp, 8) 237bdd1243dSDimitry Andric << " ("; 238bdd1243dSDimitry Andric if (ctx.config.repro) { 2395ffd83dbSDimitry Andric os << "Repro mode"; 2405ffd83dbSDimitry Andric } else { 241bdd1243dSDimitry Andric writeFormattedTimestamp(os, ctx.config.timestamp); 2425ffd83dbSDimitry Andric } 2435ffd83dbSDimitry Andric os << ")\n"; 2445ffd83dbSDimitry Andric 2455ffd83dbSDimitry Andric os << "\n"; 2465ffd83dbSDimitry Andric os << " Preferred load address is " 247bdd1243dSDimitry Andric << format_hex_no_prefix(ctx.config.imageBase, 16) << "\n"; 2485ffd83dbSDimitry Andric os << "\n"; 2495ffd83dbSDimitry Andric 2505ffd83dbSDimitry Andric // Print out section table. 2515ffd83dbSDimitry Andric os << " Start Length Name Class\n"; 2525ffd83dbSDimitry Andric 253349cc55cSDimitry Andric for (OutputSection *sec : ctx.outputSections) { 2545ffd83dbSDimitry Andric // Merge display of chunks with same sectionName 2555ffd83dbSDimitry Andric std::vector<std::pair<SectionChunk *, SectionChunk *>> ChunkRanges; 2560b57cec5SDimitry Andric for (Chunk *c : sec->chunks) { 2570b57cec5SDimitry Andric auto *sc = dyn_cast<SectionChunk>(c); 2580b57cec5SDimitry Andric if (!sc) 2590b57cec5SDimitry Andric continue; 2600b57cec5SDimitry Andric 2615ffd83dbSDimitry Andric if (ChunkRanges.empty() || 2625ffd83dbSDimitry Andric c->getSectionName() != ChunkRanges.back().first->getSectionName()) { 2635ffd83dbSDimitry Andric ChunkRanges.emplace_back(sc, sc); 2645ffd83dbSDimitry Andric } else { 2655ffd83dbSDimitry Andric ChunkRanges.back().second = sc; 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric } 26885868e8aSDimitry Andric 2695ffd83dbSDimitry Andric const bool isCodeSection = 2705ffd83dbSDimitry Andric (sec->header.Characteristics & COFF::IMAGE_SCN_CNT_CODE) && 2715ffd83dbSDimitry Andric (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_READ) && 2725ffd83dbSDimitry Andric (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE); 2735ffd83dbSDimitry Andric StringRef SectionClass = (isCodeSection ? "CODE" : "DATA"); 2745ffd83dbSDimitry Andric 2755ffd83dbSDimitry Andric for (auto &cr : ChunkRanges) { 2765ffd83dbSDimitry Andric size_t size = 2775ffd83dbSDimitry Andric cr.second->getRVA() + cr.second->getSize() - cr.first->getRVA(); 2785ffd83dbSDimitry Andric 2795ffd83dbSDimitry Andric auto address = cr.first->getRVA() - sec->header.VirtualAddress; 2805ffd83dbSDimitry Andric writeHeader(os, sec->sectionIndex, address); 2815ffd83dbSDimitry Andric os << " " << format_hex_no_prefix(size, 8) << "H"; 2825ffd83dbSDimitry Andric os << " " << left_justify(cr.first->getSectionName(), 23); 2835ffd83dbSDimitry Andric os << " " << SectionClass; 2845ffd83dbSDimitry Andric os << '\n'; 2855ffd83dbSDimitry Andric } 2865ffd83dbSDimitry Andric } 2875ffd83dbSDimitry Andric 2885ffd83dbSDimitry Andric // Print out the symbols table (without static symbols) 2895ffd83dbSDimitry Andric os << "\n"; 2905ffd83dbSDimitry Andric os << " Address Publics by Value Rva+Base" 2915ffd83dbSDimitry Andric " Lib:Object\n"; 2925ffd83dbSDimitry Andric os << "\n"; 2935ffd83dbSDimitry Andric for (Defined *sym : syms) 2945ffd83dbSDimitry Andric os << symStr[sym] << '\n'; 2955ffd83dbSDimitry Andric 2965ffd83dbSDimitry Andric // Print out the entry point. 2975ffd83dbSDimitry Andric os << "\n"; 2985ffd83dbSDimitry Andric 2995ffd83dbSDimitry Andric uint16_t entrySecIndex = 0; 3005ffd83dbSDimitry Andric uint64_t entryAddress = 0; 3015ffd83dbSDimitry Andric 302bdd1243dSDimitry Andric if (!ctx.config.noEntry) { 303bdd1243dSDimitry Andric Defined *entry = dyn_cast_or_null<Defined>(ctx.config.entry); 3045ffd83dbSDimitry Andric if (entry) { 3055ffd83dbSDimitry Andric Chunk *chunk = entry->getChunk(); 3065ffd83dbSDimitry Andric entrySecIndex = chunk->getOutputSectionIdx(); 3075ffd83dbSDimitry Andric entryAddress = 308349cc55cSDimitry Andric entry->getRVA() - ctx.getOutputSection(chunk)->header.VirtualAddress; 3095ffd83dbSDimitry Andric } 3105ffd83dbSDimitry Andric } 3115ffd83dbSDimitry Andric os << " entry point at "; 3125ffd83dbSDimitry Andric os << format("%04x:%08llx", entrySecIndex, entryAddress); 3135ffd83dbSDimitry Andric os << "\n"; 3145ffd83dbSDimitry Andric 3155ffd83dbSDimitry Andric // Print out the static symbols 3165ffd83dbSDimitry Andric os << "\n"; 3175ffd83dbSDimitry Andric os << " Static symbols\n"; 3185ffd83dbSDimitry Andric os << "\n"; 3195ffd83dbSDimitry Andric for (Defined *sym : staticSyms) 3205ffd83dbSDimitry Andric os << staticSymStr[sym] << '\n'; 3215ffd83dbSDimitry Andric 322bdd1243dSDimitry Andric // Print out the exported functions 323bdd1243dSDimitry Andric if (ctx.config.mapInfo) { 324bdd1243dSDimitry Andric os << "\n"; 325bdd1243dSDimitry Andric os << " Exports\n"; 326bdd1243dSDimitry Andric os << "\n"; 327bdd1243dSDimitry Andric os << " ordinal name\n\n"; 328bdd1243dSDimitry Andric for (Export &e : ctx.config.exports) { 329bdd1243dSDimitry Andric os << format(" %7d", e.ordinal) << " " << e.name << "\n"; 330bdd1243dSDimitry Andric if (!e.extName.empty() && e.extName != e.name) 331bdd1243dSDimitry Andric os << " exported name: " << e.extName << "\n"; 332bdd1243dSDimitry Andric } 333bdd1243dSDimitry Andric } 334bdd1243dSDimitry Andric 3355ffd83dbSDimitry Andric t4.stop(); 3365ffd83dbSDimitry Andric t1.stop(); 3375ffd83dbSDimitry Andric } 338