1343171Sdim//===- Reader.cpp ---------------------------------------------------------===// 2343171Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343171Sdim// 7343171Sdim//===----------------------------------------------------------------------===// 8343171Sdim 9343171Sdim#include "Reader.h" 10343171Sdim#include "Object.h" 11343171Sdim#include "llvm/ADT/ArrayRef.h" 12343171Sdim#include "llvm/ADT/StringRef.h" 13353358Sdim#include "llvm/BinaryFormat/COFF.h" 14343171Sdim#include "llvm/Object/COFF.h" 15343171Sdim#include "llvm/Support/ErrorHandling.h" 16343171Sdim#include <cstddef> 17343171Sdim#include <cstdint> 18343171Sdim 19343171Sdimnamespace llvm { 20343171Sdimnamespace objcopy { 21343171Sdimnamespace coff { 22343171Sdim 23343171Sdimusing namespace object; 24353358Sdimusing namespace COFF; 25343171Sdim 26343171SdimError COFFReader::readExecutableHeaders(Object &Obj) const { 27343171Sdim const dos_header *DH = COFFObj.getDOSHeader(); 28343171Sdim Obj.Is64 = COFFObj.is64(); 29343171Sdim if (!DH) 30343171Sdim return Error::success(); 31343171Sdim 32343171Sdim Obj.IsPE = true; 33343171Sdim Obj.DosHeader = *DH; 34343171Sdim if (DH->AddressOfNewExeHeader > sizeof(*DH)) 35343171Sdim Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]), 36343171Sdim DH->AddressOfNewExeHeader - sizeof(*DH)); 37343171Sdim 38343171Sdim if (COFFObj.is64()) { 39360784Sdim Obj.PeHeader = *COFFObj.getPE32PlusHeader(); 40343171Sdim } else { 41360784Sdim const pe32_header *PE32 = COFFObj.getPE32Header(); 42343171Sdim copyPeHeader(Obj.PeHeader, *PE32); 43343171Sdim // The pe32plus_header (stored in Object) lacks the BaseOfData field. 44343171Sdim Obj.BaseOfData = PE32->BaseOfData; 45343171Sdim } 46343171Sdim 47343171Sdim for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) { 48343171Sdim const data_directory *Dir; 49343171Sdim if (auto EC = COFFObj.getDataDirectory(I, Dir)) 50343171Sdim return errorCodeToError(EC); 51343171Sdim Obj.DataDirectories.emplace_back(*Dir); 52343171Sdim } 53343171Sdim return Error::success(); 54343171Sdim} 55343171Sdim 56343171SdimError COFFReader::readSections(Object &Obj) const { 57353358Sdim std::vector<Section> Sections; 58343171Sdim // Section indexing starts from 1. 59343171Sdim for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) { 60343171Sdim const coff_section *Sec; 61343171Sdim if (auto EC = COFFObj.getSection(I, Sec)) 62343171Sdim return errorCodeToError(EC); 63353358Sdim Sections.push_back(Section()); 64353358Sdim Section &S = Sections.back(); 65343171Sdim S.Header = *Sec; 66360784Sdim S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL; 67353358Sdim ArrayRef<uint8_t> Contents; 68353358Sdim if (Error E = COFFObj.getSectionContents(Sec, Contents)) 69353358Sdim return E; 70353358Sdim S.setContentsRef(Contents); 71343171Sdim ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec); 72343171Sdim for (const coff_relocation &R : Relocs) 73343171Sdim S.Relocs.push_back(R); 74353358Sdim if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec)) 75353358Sdim S.Name = *NameOrErr; 76353358Sdim else 77353358Sdim return NameOrErr.takeError(); 78343171Sdim } 79353358Sdim Obj.addSections(Sections); 80343171Sdim return Error::success(); 81343171Sdim} 82343171Sdim 83343171SdimError COFFReader::readSymbols(Object &Obj, bool IsBigObj) const { 84343171Sdim std::vector<Symbol> Symbols; 85343171Sdim Symbols.reserve(COFFObj.getRawNumberOfSymbols()); 86353358Sdim ArrayRef<Section> Sections = Obj.getSections(); 87343171Sdim for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) { 88343171Sdim Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I); 89343171Sdim if (!SymOrErr) 90343171Sdim return SymOrErr.takeError(); 91343171Sdim COFFSymbolRef SymRef = *SymOrErr; 92343171Sdim 93343171Sdim Symbols.push_back(Symbol()); 94343171Sdim Symbol &Sym = Symbols.back(); 95343171Sdim // Copy symbols from the original form into an intermediate coff_symbol32. 96343171Sdim if (IsBigObj) 97343171Sdim copySymbol(Sym.Sym, 98343171Sdim *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr())); 99343171Sdim else 100343171Sdim copySymbol(Sym.Sym, 101343171Sdim *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr())); 102343171Sdim if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name)) 103343171Sdim return errorCodeToError(EC); 104353358Sdim 105353358Sdim ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef); 106353358Sdim size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16); 107353358Sdim assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols()); 108353358Sdim // The auxillary symbols are structs of sizeof(coff_symbol16) each. 109353358Sdim // In the big object format (where symbols are coff_symbol32), each 110353358Sdim // auxillary symbol is padded with 2 bytes at the end. Copy each 111353358Sdim // auxillary symbol to the Sym.AuxData vector. For file symbols, 112353358Sdim // the whole range of aux symbols are interpreted as one null padded 113353358Sdim // string instead. 114353358Sdim if (SymRef.isFileRecord()) 115353358Sdim Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()), 116353358Sdim AuxData.size()) 117353358Sdim .rtrim('\0'); 118353358Sdim else 119353358Sdim for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++) 120353358Sdim Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol))); 121353358Sdim 122353358Sdim // Find the unique id of the section 123353358Sdim if (SymRef.getSectionNumber() <= 124353358Sdim 0) // Special symbol (undefined/absolute/debug) 125353358Sdim Sym.TargetSectionId = SymRef.getSectionNumber(); 126353358Sdim else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) < 127353358Sdim Sections.size()) 128353358Sdim Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId; 129353358Sdim else 130353358Sdim return createStringError(object_error::parse_failed, 131353358Sdim "section number out of range"); 132353358Sdim // For section definitions, check if it is comdat associative, and if 133353358Sdim // it is, find the target section unique id. 134353358Sdim const coff_aux_section_definition *SD = SymRef.getSectionDefinition(); 135353358Sdim const coff_aux_weak_external *WE = SymRef.getWeakExternal(); 136353358Sdim if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) { 137353358Sdim int32_t Index = SD->getNumber(IsBigObj); 138353358Sdim if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size()) 139353358Sdim return createStringError(object_error::parse_failed, 140353358Sdim "unexpected associative section index"); 141353358Sdim Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId; 142353358Sdim } else if (WE) { 143353358Sdim // This is a raw symbol index for now, but store it in the Symbol 144353358Sdim // until we've added them to the Object, which assigns the final 145353358Sdim // unique ids. 146353358Sdim Sym.WeakTargetSymbolId = WE->TagIndex; 147353358Sdim } 148343171Sdim I += 1 + SymRef.getNumberOfAuxSymbols(); 149343171Sdim } 150343171Sdim Obj.addSymbols(Symbols); 151343171Sdim return Error::success(); 152343171Sdim} 153343171Sdim 154353358SdimError COFFReader::setSymbolTargets(Object &Obj) const { 155343171Sdim std::vector<const Symbol *> RawSymbolTable; 156343171Sdim for (const Symbol &Sym : Obj.getSymbols()) { 157343171Sdim RawSymbolTable.push_back(&Sym); 158343171Sdim for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++) 159343171Sdim RawSymbolTable.push_back(nullptr); 160343171Sdim } 161353358Sdim for (Symbol &Sym : Obj.getMutableSymbols()) { 162353358Sdim // Convert WeakTargetSymbolId from the original raw symbol index to 163353358Sdim // a proper unique id. 164353358Sdim if (Sym.WeakTargetSymbolId) { 165353358Sdim if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size()) 166353358Sdim return createStringError(object_error::parse_failed, 167353358Sdim "weak external reference out of range"); 168353358Sdim const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId]; 169353358Sdim if (Target == nullptr) 170353358Sdim return createStringError(object_error::parse_failed, 171353358Sdim "invalid SymbolTableIndex"); 172353358Sdim Sym.WeakTargetSymbolId = Target->UniqueId; 173353358Sdim } 174353358Sdim } 175353358Sdim for (Section &Sec : Obj.getMutableSections()) { 176343171Sdim for (Relocation &R : Sec.Relocs) { 177343171Sdim if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size()) 178353358Sdim return createStringError(object_error::parse_failed, 179353358Sdim "SymbolTableIndex out of range"); 180343171Sdim const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex]; 181343171Sdim if (Sym == nullptr) 182353358Sdim return createStringError(object_error::parse_failed, 183353358Sdim "invalid SymbolTableIndex"); 184343171Sdim R.Target = Sym->UniqueId; 185343171Sdim R.TargetName = Sym->Name; 186343171Sdim } 187343171Sdim } 188343171Sdim return Error::success(); 189343171Sdim} 190343171Sdim 191343171SdimExpected<std::unique_ptr<Object>> COFFReader::create() const { 192360784Sdim auto Obj = std::make_unique<Object>(); 193343171Sdim 194343171Sdim bool IsBigObj = false; 195360784Sdim if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) { 196343171Sdim Obj->CoffFileHeader = *CFH; 197343171Sdim } else { 198360784Sdim const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader(); 199343171Sdim if (!CBFH) 200353358Sdim return createStringError(object_error::parse_failed, 201353358Sdim "no COFF file header returned"); 202343171Sdim // Only copying the few fields from the bigobj header that we need 203343171Sdim // and won't recreate in the end. 204343171Sdim Obj->CoffFileHeader.Machine = CBFH->Machine; 205343171Sdim Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp; 206343171Sdim IsBigObj = true; 207343171Sdim } 208343171Sdim 209343171Sdim if (Error E = readExecutableHeaders(*Obj)) 210343171Sdim return std::move(E); 211343171Sdim if (Error E = readSections(*Obj)) 212343171Sdim return std::move(E); 213343171Sdim if (Error E = readSymbols(*Obj, IsBigObj)) 214343171Sdim return std::move(E); 215353358Sdim if (Error E = setSymbolTargets(*Obj)) 216343171Sdim return std::move(E); 217343171Sdim 218343171Sdim return std::move(Obj); 219343171Sdim} 220343171Sdim 221343171Sdim} // end namespace coff 222343171Sdim} // end namespace objcopy 223343171Sdim} // end namespace llvm 224