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