brintos

brintos / llvm-project-archived public Read only

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