| //===- COFFReader.cpp -----------------------------------------------------===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "COFFReader.h" | 
 | #include "COFFObject.h" | 
 | #include "llvm/ADT/ArrayRef.h" | 
 | #include "llvm/ADT/StringRef.h" | 
 | #include "llvm/BinaryFormat/COFF.h" | 
 | #include "llvm/Object/COFF.h" | 
 | #include "llvm/Support/ErrorHandling.h" | 
 | #include <cstddef> | 
 | #include <cstdint> | 
 |  | 
 | namespace llvm { | 
 | namespace objcopy { | 
 | namespace coff { | 
 |  | 
 | using namespace object; | 
 | using namespace COFF; | 
 |  | 
 | Error COFFReader::readExecutableHeaders(Object &Obj) const { | 
 |   const dos_header *DH = COFFObj.getDOSHeader(); | 
 |   Obj.Is64 = COFFObj.is64(); | 
 |   if (!DH) | 
 |     return Error::success(); | 
 |  | 
 |   Obj.IsPE = true; | 
 |   Obj.DosHeader = *DH; | 
 |   if (DH->AddressOfNewExeHeader > sizeof(*DH)) | 
 |     Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]), | 
 |                                     DH->AddressOfNewExeHeader - sizeof(*DH)); | 
 |  | 
 |   if (COFFObj.is64()) { | 
 |     Obj.PeHeader = *COFFObj.getPE32PlusHeader(); | 
 |   } else { | 
 |     const pe32_header *PE32 = COFFObj.getPE32Header(); | 
 |     copyPeHeader(Obj.PeHeader, *PE32); | 
 |     // The pe32plus_header (stored in Object) lacks the BaseOfData field. | 
 |     Obj.BaseOfData = PE32->BaseOfData; | 
 |   } | 
 |  | 
 |   for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) { | 
 |     const data_directory *Dir = COFFObj.getDataDirectory(I); | 
 |     if (!Dir) | 
 |       return errorCodeToError(object_error::parse_failed); | 
 |     Obj.DataDirectories.emplace_back(*Dir); | 
 |   } | 
 |   return Error::success(); | 
 | } | 
 |  | 
 | Error COFFReader::readSections(Object &Obj) const { | 
 |   std::vector<Section> Sections; | 
 |   // Section indexing starts from 1. | 
 |   for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) { | 
 |     Expected<const coff_section *> SecOrErr = COFFObj.getSection(I); | 
 |     if (!SecOrErr) | 
 |       return SecOrErr.takeError(); | 
 |     const coff_section *Sec = *SecOrErr; | 
 |     Sections.push_back(Section()); | 
 |     Section &S = Sections.back(); | 
 |     S.Header = *Sec; | 
 |     S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL; | 
 |     ArrayRef<uint8_t> Contents; | 
 |     if (Error E = COFFObj.getSectionContents(Sec, Contents)) | 
 |       return E; | 
 |     S.setContentsRef(Contents); | 
 |     ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec); | 
 |     llvm::append_range(S.Relocs, Relocs); | 
 |     if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec)) | 
 |       S.Name = *NameOrErr; | 
 |     else | 
 |       return NameOrErr.takeError(); | 
 |   } | 
 |   Obj.addSections(Sections); | 
 |   return Error::success(); | 
 | } | 
 |  | 
 | Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const { | 
 |   std::vector<Symbol> Symbols; | 
 |   Symbols.reserve(COFFObj.getNumberOfSymbols()); | 
 |   ArrayRef<Section> Sections = Obj.getSections(); | 
 |   for (uint32_t I = 0, E = COFFObj.getNumberOfSymbols(); I < E;) { | 
 |     Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I); | 
 |     if (!SymOrErr) | 
 |       return SymOrErr.takeError(); | 
 |     COFFSymbolRef SymRef = *SymOrErr; | 
 |  | 
 |     Symbols.push_back(Symbol()); | 
 |     Symbol &Sym = Symbols.back(); | 
 |     // Copy symbols from the original form into an intermediate coff_symbol32. | 
 |     if (IsBigObj) | 
 |       copySymbol(Sym.Sym, | 
 |                  *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr())); | 
 |     else | 
 |       copySymbol(Sym.Sym, | 
 |                  *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr())); | 
 |     auto NameOrErr = COFFObj.getSymbolName(SymRef); | 
 |     if (!NameOrErr) | 
 |       return NameOrErr.takeError(); | 
 |     Sym.Name = *NameOrErr; | 
 |  | 
 |     ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef); | 
 |     size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16); | 
 |     assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols()); | 
 |     // The auxillary symbols are structs of sizeof(coff_symbol16) each. | 
 |     // In the big object format (where symbols are coff_symbol32), each | 
 |     // auxillary symbol is padded with 2 bytes at the end. Copy each | 
 |     // auxillary symbol to the Sym.AuxData vector. For file symbols, | 
 |     // the whole range of aux symbols are interpreted as one null padded | 
 |     // string instead. | 
 |     if (SymRef.isFileRecord()) | 
 |       Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()), | 
 |                               AuxData.size()) | 
 |                         .rtrim('\0'); | 
 |     else | 
 |       for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++) | 
 |         Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol))); | 
 |  | 
 |     // Find the unique id of the section | 
 |     if (SymRef.getSectionNumber() <= | 
 |         0) // Special symbol (undefined/absolute/debug) | 
 |       Sym.TargetSectionId = SymRef.getSectionNumber(); | 
 |     else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) < | 
 |              Sections.size()) | 
 |       Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId; | 
 |     else | 
 |       return createStringError(object_error::parse_failed, | 
 |                                "section number out of range"); | 
 |     // For section definitions, check if it is comdat associative, and if | 
 |     // it is, find the target section unique id. | 
 |     const coff_aux_section_definition *SD = SymRef.getSectionDefinition(); | 
 |     const coff_aux_weak_external *WE = SymRef.getWeakExternal(); | 
 |     if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) { | 
 |       int32_t Index = SD->getNumber(IsBigObj); | 
 |       if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size()) | 
 |         return createStringError(object_error::parse_failed, | 
 |                                  "unexpected associative section index"); | 
 |       Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId; | 
 |     } else if (WE) { | 
 |       // This is a raw symbol index for now, but store it in the Symbol | 
 |       // until we've added them to the Object, which assigns the final | 
 |       // unique ids. | 
 |       Sym.WeakTargetSymbolId = WE->TagIndex; | 
 |     } | 
 |     I += 1 + SymRef.getNumberOfAuxSymbols(); | 
 |   } | 
 |   Obj.addSymbols(Symbols); | 
 |   return Error::success(); | 
 | } | 
 |  | 
 | Error COFFReader::setSymbolTargets(Object &Obj) const { | 
 |   std::vector<const Symbol *> RawSymbolTable; | 
 |   for (const Symbol &Sym : Obj.getSymbols()) { | 
 |     RawSymbolTable.push_back(&Sym); | 
 |     for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++) | 
 |       RawSymbolTable.push_back(nullptr); | 
 |   } | 
 |   for (Symbol &Sym : Obj.getMutableSymbols()) { | 
 |     // Convert WeakTargetSymbolId from the original raw symbol index to | 
 |     // a proper unique id. | 
 |     if (Sym.WeakTargetSymbolId) { | 
 |       if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size()) | 
 |         return createStringError(object_error::parse_failed, | 
 |                                  "weak external reference out of range"); | 
 |       const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId]; | 
 |       if (Target == nullptr) | 
 |         return createStringError(object_error::parse_failed, | 
 |                                  "invalid SymbolTableIndex"); | 
 |       Sym.WeakTargetSymbolId = Target->UniqueId; | 
 |     } | 
 |   } | 
 |   for (Section &Sec : Obj.getMutableSections()) { | 
 |     for (Relocation &R : Sec.Relocs) { | 
 |       if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size()) | 
 |         return createStringError(object_error::parse_failed, | 
 |                                  "SymbolTableIndex out of range"); | 
 |       const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex]; | 
 |       if (Sym == nullptr) | 
 |         return createStringError(object_error::parse_failed, | 
 |                                  "invalid SymbolTableIndex"); | 
 |       R.Target = Sym->UniqueId; | 
 |       R.TargetName = Sym->Name; | 
 |     } | 
 |   } | 
 |   return Error::success(); | 
 | } | 
 |  | 
 | Expected<std::unique_ptr<Object>> COFFReader::create() const { | 
 |   auto Obj = std::make_unique<Object>(); | 
 |  | 
 |   bool IsBigObj = false; | 
 |   if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) { | 
 |     Obj->CoffFileHeader = *CFH; | 
 |   } else { | 
 |     const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader(); | 
 |     if (!CBFH) | 
 |       return createStringError(object_error::parse_failed, | 
 |                                "no COFF file header returned"); | 
 |     // Only copying the few fields from the bigobj header that we need | 
 |     // and won't recreate in the end. | 
 |     Obj->CoffFileHeader.Machine = CBFH->Machine; | 
 |     Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp; | 
 |     IsBigObj = true; | 
 |   } | 
 |  | 
 |   if (Error E = readExecutableHeaders(*Obj)) | 
 |     return std::move(E); | 
 |   if (Error E = readSections(*Obj)) | 
 |     return std::move(E); | 
 |   if (Error E = readSymbols(*Obj, IsBigObj)) | 
 |     return std::move(E); | 
 |   if (Error E = setSymbolTargets(*Obj)) | 
 |     return std::move(E); | 
 |  | 
 |   return std::move(Obj); | 
 | } | 
 |  | 
 | } // end namespace coff | 
 | } // end namespace objcopy | 
 | } // end namespace llvm |