diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:05:49 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:05:49 +0000 | 
| commit | e2fd426bdafe9f5c10066d3926ece6e342184a67 (patch) | |
| tree | bfbbb5fd38554e6b8988b7a217e9fd0623728d7d /COFF/SymbolTable.cpp | |
| parent | 84c4061b34e048f47e5eb4fbabc1558495e8157c (diff) | |
Notes
Diffstat (limited to 'COFF/SymbolTable.cpp')
| -rw-r--r-- | COFF/SymbolTable.cpp | 185 | 
1 files changed, 136 insertions, 49 deletions
| diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp index b286d865caafc..1a9e0455dc1dc 100644 --- a/COFF/SymbolTable.cpp +++ b/COFF/SymbolTable.cpp @@ -60,16 +60,16 @@ void SymbolTable::addFile(InputFile *File) {  }  static void errorOrWarn(const Twine &S) { -  if (Config->Force) +  if (Config->ForceUnresolved)      warn(S);    else      error(S);  } -// Returns the name of the symbol in SC whose value is <= Addr that is closest -// to Addr. This is generally the name of the global variable or function whose -// definition contains Addr. -static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) { +// Returns the symbol in SC whose value is <= Addr that is closest to Addr. +// This is generally the global variable or function whose definition contains +// Addr. +static Symbol *getSymbol(SectionChunk *SC, uint32_t Addr) {    DefinedRegular *Candidate = nullptr;    for (Symbol *S : SC->File->getSymbols()) { @@ -81,14 +81,12 @@ static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) {      Candidate = D;    } -  if (!Candidate) -    return ""; -  return Candidate->getName(); +  return Candidate;  } -static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) { +std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {    struct Location { -    StringRef SymName; +    Symbol *Sym;      std::pair<StringRef, uint32_t> FileLine;    };    std::vector<Location> Locations; @@ -102,14 +100,14 @@ static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {          continue;        std::pair<StringRef, uint32_t> FileLine =            getFileLine(SC, R.VirtualAddress); -      StringRef SymName = getSymbolName(SC, R.VirtualAddress); -      if (!FileLine.first.empty() || !SymName.empty()) -        Locations.push_back({SymName, FileLine}); +      Symbol *Sym = getSymbol(SC, R.VirtualAddress); +      if (!FileLine.first.empty() || Sym) +        Locations.push_back({Sym, FileLine});      }    }    if (Locations.empty()) -    return "\n>>> referenced by " + toString(File) + "\n"; +    return "\n>>> referenced by " + toString(File);    std::string Out;    llvm::raw_string_ostream OS(Out); @@ -119,13 +117,87 @@ static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {        OS << Loc.FileLine.first << ":" << Loc.FileLine.second           << "\n>>>               ";      OS << toString(File); -    if (!Loc.SymName.empty()) -      OS << ":(" << Loc.SymName << ')'; +    if (Loc.Sym) +      OS << ":(" << toString(*Loc.Sym) << ')';    } -  OS << '\n';    return OS.str();  } +void SymbolTable::loadMinGWAutomaticImports() { +  for (auto &I : SymMap) { +    Symbol *Sym = I.second; +    auto *Undef = dyn_cast<Undefined>(Sym); +    if (!Undef) +      continue; +    if (!Sym->IsUsedInRegularObj) +      continue; + +    StringRef Name = Undef->getName(); + +    if (Name.startswith("__imp_")) +      continue; +    // If we have an undefined symbol, but we have a Lazy representing a +    // symbol we could load from file, make sure to load that. +    Lazy *L = dyn_cast_or_null<Lazy>(find(("__imp_" + Name).str())); +    if (!L || L->PendingArchiveLoad) +      continue; + +    log("Loading lazy " + L->getName() + " from " + L->File->getName() + +        " for automatic import"); +    L->PendingArchiveLoad = true; +    L->File->addMember(&L->Sym); +  } +} + +bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) { +  if (Name.startswith("__imp_")) +    return false; +  Defined *Imp = dyn_cast_or_null<Defined>(find(("__imp_" + Name).str())); +  if (!Imp) +    return false; + +  // Replace the reference directly to a variable with a reference +  // to the import address table instead. This obviously isn't right, +  // but we mark the symbol as IsRuntimePseudoReloc, and a later pass +  // will add runtime pseudo relocations for every relocation against +  // this Symbol. The runtime pseudo relocation framework expects the +  // reference itself to point at the IAT entry. +  size_t ImpSize = 0; +  if (isa<DefinedImportData>(Imp)) { +    log("Automatically importing " + Name + " from " + +        cast<DefinedImportData>(Imp)->getDLLName()); +    ImpSize = sizeof(DefinedImportData); +  } else if (isa<DefinedRegular>(Imp)) { +    log("Automatically importing " + Name + " from " + +        toString(cast<DefinedRegular>(Imp)->File)); +    ImpSize = sizeof(DefinedRegular); +  } else { +    warn("unable to automatically import " + Name + " from " + Imp->getName() + +         " from " + toString(cast<DefinedRegular>(Imp)->File) + +         "; unexpected symbol type"); +    return false; +  } +  Sym->replaceKeepingName(Imp, ImpSize); +  Sym->IsRuntimePseudoReloc = true; + +  // There may exist symbols named .refptr.<name> which only consist +  // of a single pointer to <name>. If it turns out <name> is +  // automatically imported, we don't need to keep the .refptr.<name> +  // pointer at all, but redirect all accesses to it to the IAT entry +  // for __imp_<name> instead, and drop the whole .refptr.<name> chunk. +  DefinedRegular *Refptr = +      dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str())); +  if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) { +    SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk()); +    if (SC && SC->Relocs.size() == 1 && *SC->symbols().begin() == Sym) { +      log("Replacing .refptr." + Name + " with " + Imp->getName()); +      Refptr->getChunk()->Live = false; +      Refptr->replaceKeepingName(Imp, ImpSize); +    } +  } +  return true; +} +  void SymbolTable::reportRemainingUndefines() {    SmallPtrSet<Symbol *, 8> Undefs;    DenseMap<Symbol *, Symbol *> LocalImports; @@ -169,9 +241,17 @@ void SymbolTable::reportRemainingUndefines() {        }      } +    // We don't want to report missing Microsoft precompiled headers symbols. +    // A proper message will be emitted instead in PDBLinker::aquirePrecompObj +    if (Name.contains("_PchSym_")) +      continue; + +    if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name)) +      continue; +      // Remaining undefined symbols are not fatal if /force is specified.      // They are replaced with dummy defined symbols. -    if (Config->Force) +    if (Config->ForceUnresolved)        replaceSymbol<DefinedAbsolute>(Sym, Name, 0);      Undefs.insert(Sym);    } @@ -181,10 +261,10 @@ void SymbolTable::reportRemainingUndefines() {    for (Symbol *B : Config->GCRoot) {      if (Undefs.count(B)) -      errorOrWarn("<root>: undefined symbol: " + B->getName()); +      errorOrWarn("<root>: undefined symbol: " + toString(*B));      if (Config->WarnLocallyDefinedImported)        if (Symbol *Imp = LocalImports.lookup(B)) -        warn("<root>: locally defined symbol imported: " + Imp->getName() + +        warn("<root>: locally defined symbol imported: " + toString(*Imp) +               " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");    } @@ -195,34 +275,41 @@ void SymbolTable::reportRemainingUndefines() {        if (!Sym)          continue;        if (Undefs.count(Sym)) -        errorOrWarn("undefined symbol: " + Sym->getName() + +        errorOrWarn("undefined symbol: " + toString(*Sym) +                      getSymbolLocations(File, SymIndex));        if (Config->WarnLocallyDefinedImported)          if (Symbol *Imp = LocalImports.lookup(Sym)) -          warn(toString(File) + ": locally defined symbol imported: " + -               Imp->getName() + " (defined in " + toString(Imp->getFile()) + -               ") [LNK4217]"); +          warn(toString(File) + +               ": locally defined symbol imported: " + toString(*Imp) + +               " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");      }    }  }  std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { +  bool Inserted = false;    Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; -  if (Sym) -    return {Sym, false}; -  Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); -  Sym->IsUsedInRegularObj = false; -  Sym->PendingArchiveLoad = false; -  return {Sym, true}; +  if (!Sym) { +    Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); +    Sym->IsUsedInRegularObj = false; +    Sym->PendingArchiveLoad = false; +    Inserted = true; +  } +  return {Sym, Inserted}; +} + +std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) { +  std::pair<Symbol *, bool> Result = insert(Name); +  if (!File || !isa<BitcodeFile>(File)) +    Result.first->IsUsedInRegularObj = true; +  return Result;  }  Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F,                                    bool IsWeakAlias) {    Symbol *S;    bool WasInserted; -  std::tie(S, WasInserted) = insert(Name); -  if (!F || !isa<BitcodeFile>(F)) -    S->IsUsedInRegularObj = true; +  std::tie(S, WasInserted) = insert(Name, F);    if (WasInserted || (isa<Lazy>(S) && IsWeakAlias)) {      replaceSymbol<Undefined>(S, Name);      return S; @@ -253,14 +340,20 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {  }  void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { -  error("duplicate symbol: " + toString(*Existing) + " in " + -        toString(Existing->getFile()) + " and in " + toString(NewFile)); +  std::string Msg = "duplicate symbol: " + toString(*Existing) + " in " + +                    toString(Existing->getFile()) + " and in " + +                    toString(NewFile); + +  if (Config->ForceMultiple) +    warn(Msg); +  else +    error(Msg);  }  Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {    Symbol *S;    bool WasInserted; -  std::tie(S, WasInserted) = insert(N); +  std::tie(S, WasInserted) = insert(N, nullptr);    S->IsUsedInRegularObj = true;    if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))      replaceSymbol<DefinedAbsolute>(S, N, Sym); @@ -272,7 +365,7 @@ Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {  Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {    Symbol *S;    bool WasInserted; -  std::tie(S, WasInserted) = insert(N); +  std::tie(S, WasInserted) = insert(N, nullptr);    S->IsUsedInRegularObj = true;    if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))      replaceSymbol<DefinedAbsolute>(S, N, VA); @@ -284,7 +377,7 @@ Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {  Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) {    Symbol *S;    bool WasInserted; -  std::tie(S, WasInserted) = insert(N); +  std::tie(S, WasInserted) = insert(N, nullptr);    S->IsUsedInRegularObj = true;    if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))      replaceSymbol<DefinedSynthetic>(S, N, C); @@ -298,9 +391,7 @@ Symbol *SymbolTable::addRegular(InputFile *F, StringRef N,                                  SectionChunk *C) {    Symbol *S;    bool WasInserted; -  std::tie(S, WasInserted) = insert(N); -  if (!isa<BitcodeFile>(F)) -    S->IsUsedInRegularObj = true; +  std::tie(S, WasInserted) = insert(N, F);    if (WasInserted || !isa<DefinedRegular>(S))      replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ false,                                    /*IsExternal*/ true, Sym, C); @@ -314,9 +405,7 @@ SymbolTable::addComdat(InputFile *F, StringRef N,                         const coff_symbol_generic *Sym) {    Symbol *S;    bool WasInserted; -  std::tie(S, WasInserted) = insert(N); -  if (!isa<BitcodeFile>(F)) -    S->IsUsedInRegularObj = true; +  std::tie(S, WasInserted) = insert(N, F);    if (WasInserted || !isa<DefinedRegular>(S)) {      replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ true,                                    /*IsExternal*/ true, Sym, nullptr); @@ -331,9 +420,7 @@ Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,                                 const coff_symbol_generic *Sym, CommonChunk *C) {    Symbol *S;    bool WasInserted; -  std::tie(S, WasInserted) = insert(N); -  if (!isa<BitcodeFile>(F)) -    S->IsUsedInRegularObj = true; +  std::tie(S, WasInserted) = insert(N, F);    if (WasInserted || !isa<DefinedCOFF>(S))      replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C);    else if (auto *DC = dyn_cast<DefinedCommon>(S)) @@ -345,7 +432,7 @@ Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,  Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) {    Symbol *S;    bool WasInserted; -  std::tie(S, WasInserted) = insert(N); +  std::tie(S, WasInserted) = insert(N, nullptr);    S->IsUsedInRegularObj = true;    if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {      replaceSymbol<DefinedImportData>(S, N, F); @@ -360,7 +447,7 @@ Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID,                                      uint16_t Machine) {    Symbol *S;    bool WasInserted; -  std::tie(S, WasInserted) = insert(Name); +  std::tie(S, WasInserted) = insert(Name, nullptr);    S->IsUsedInRegularObj = true;    if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {      replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine); | 
