//===- 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 #include 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(reinterpret_cast(&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
Sections; // Section indexing starts from 1. for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) { Expected 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 Contents; if (Error E = COFFObj.getSectionContents(Sec, Contents)) return E; S.setContentsRef(Contents); ArrayRef Relocs = COFFObj.getRelocations(Sec); for (const coff_relocation &R : Relocs) S.Relocs.push_back(R); if (Expected 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 Symbols; Symbols.reserve(COFFObj.getNumberOfSymbols()); ArrayRef
Sections = Obj.getSections(); for (uint32_t I = 0, E = COFFObj.getNumberOfSymbols(); I < E;) { Expected 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(SymRef.getRawPtr())); else copySymbol(Sym.Sym, *reinterpret_cast(SymRef.getRawPtr())); auto NameOrErr = COFFObj.getSymbolName(SymRef); if (!NameOrErr) return NameOrErr.takeError(); Sym.Name = *NameOrErr; ArrayRef 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(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(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(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 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> COFFReader::create() const { auto Obj = std::make_unique(); 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