| //===- 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); |
| for (const coff_relocation &R : Relocs) |
| S.Relocs.push_back(R); |
| 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 |