Reader.cpp revision 360784
1//===- Reader.cpp ---------------------------------------------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "Reader.h" 10#include "Object.h" 11#include "llvm/ADT/ArrayRef.h" 12#include "llvm/ADT/StringRef.h" 13#include "llvm/BinaryFormat/COFF.h" 14#include "llvm/Object/COFF.h" 15#include "llvm/Support/ErrorHandling.h" 16#include <cstddef> 17#include <cstdint> 18 19namespace llvm { 20namespace objcopy { 21namespace coff { 22 23using namespace object; 24using namespace COFF; 25 26Error COFFReader::readExecutableHeaders(Object &Obj) const { 27 const dos_header *DH = COFFObj.getDOSHeader(); 28 Obj.Is64 = COFFObj.is64(); 29 if (!DH) 30 return Error::success(); 31 32 Obj.IsPE = true; 33 Obj.DosHeader = *DH; 34 if (DH->AddressOfNewExeHeader > sizeof(*DH)) 35 Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]), 36 DH->AddressOfNewExeHeader - sizeof(*DH)); 37 38 if (COFFObj.is64()) { 39 Obj.PeHeader = *COFFObj.getPE32PlusHeader(); 40 } else { 41 const pe32_header *PE32 = COFFObj.getPE32Header(); 42 copyPeHeader(Obj.PeHeader, *PE32); 43 // The pe32plus_header (stored in Object) lacks the BaseOfData field. 44 Obj.BaseOfData = PE32->BaseOfData; 45 } 46 47 for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) { 48 const data_directory *Dir; 49 if (auto EC = COFFObj.getDataDirectory(I, Dir)) 50 return errorCodeToError(EC); 51 Obj.DataDirectories.emplace_back(*Dir); 52 } 53 return Error::success(); 54} 55 56Error COFFReader::readSections(Object &Obj) const { 57 std::vector<Section> Sections; 58 // Section indexing starts from 1. 59 for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) { 60 const coff_section *Sec; 61 if (auto EC = COFFObj.getSection(I, Sec)) 62 return errorCodeToError(EC); 63 Sections.push_back(Section()); 64 Section &S = Sections.back(); 65 S.Header = *Sec; 66 S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL; 67 ArrayRef<uint8_t> Contents; 68 if (Error E = COFFObj.getSectionContents(Sec, Contents)) 69 return E; 70 S.setContentsRef(Contents); 71 ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec); 72 for (const coff_relocation &R : Relocs) 73 S.Relocs.push_back(R); 74 if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec)) 75 S.Name = *NameOrErr; 76 else 77 return NameOrErr.takeError(); 78 } 79 Obj.addSections(Sections); 80 return Error::success(); 81} 82 83Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const { 84 std::vector<Symbol> Symbols; 85 Symbols.reserve(COFFObj.getRawNumberOfSymbols()); 86 ArrayRef<Section> Sections = Obj.getSections(); 87 for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) { 88 Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I); 89 if (!SymOrErr) 90 return SymOrErr.takeError(); 91 COFFSymbolRef SymRef = *SymOrErr; 92 93 Symbols.push_back(Symbol()); 94 Symbol &Sym = Symbols.back(); 95 // Copy symbols from the original form into an intermediate coff_symbol32. 96 if (IsBigObj) 97 copySymbol(Sym.Sym, 98 *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr())); 99 else 100 copySymbol(Sym.Sym, 101 *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr())); 102 if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name)) 103 return errorCodeToError(EC); 104 105 ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef); 106 size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16); 107 assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols()); 108 // The auxillary symbols are structs of sizeof(coff_symbol16) each. 109 // In the big object format (where symbols are coff_symbol32), each 110 // auxillary symbol is padded with 2 bytes at the end. Copy each 111 // auxillary symbol to the Sym.AuxData vector. For file symbols, 112 // the whole range of aux symbols are interpreted as one null padded 113 // string instead. 114 if (SymRef.isFileRecord()) 115 Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()), 116 AuxData.size()) 117 .rtrim('\0'); 118 else 119 for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++) 120 Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol))); 121 122 // Find the unique id of the section 123 if (SymRef.getSectionNumber() <= 124 0) // Special symbol (undefined/absolute/debug) 125 Sym.TargetSectionId = SymRef.getSectionNumber(); 126 else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) < 127 Sections.size()) 128 Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId; 129 else 130 return createStringError(object_error::parse_failed, 131 "section number out of range"); 132 // For section definitions, check if it is comdat associative, and if 133 // it is, find the target section unique id. 134 const coff_aux_section_definition *SD = SymRef.getSectionDefinition(); 135 const coff_aux_weak_external *WE = SymRef.getWeakExternal(); 136 if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) { 137 int32_t Index = SD->getNumber(IsBigObj); 138 if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size()) 139 return createStringError(object_error::parse_failed, 140 "unexpected associative section index"); 141 Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId; 142 } else if (WE) { 143 // This is a raw symbol index for now, but store it in the Symbol 144 // until we've added them to the Object, which assigns the final 145 // unique ids. 146 Sym.WeakTargetSymbolId = WE->TagIndex; 147 } 148 I += 1 + SymRef.getNumberOfAuxSymbols(); 149 } 150 Obj.addSymbols(Symbols); 151 return Error::success(); 152} 153 154Error COFFReader::setSymbolTargets(Object &Obj) const { 155 std::vector<const Symbol *> RawSymbolTable; 156 for (const Symbol &Sym : Obj.getSymbols()) { 157 RawSymbolTable.push_back(&Sym); 158 for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++) 159 RawSymbolTable.push_back(nullptr); 160 } 161 for (Symbol &Sym : Obj.getMutableSymbols()) { 162 // Convert WeakTargetSymbolId from the original raw symbol index to 163 // a proper unique id. 164 if (Sym.WeakTargetSymbolId) { 165 if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size()) 166 return createStringError(object_error::parse_failed, 167 "weak external reference out of range"); 168 const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId]; 169 if (Target == nullptr) 170 return createStringError(object_error::parse_failed, 171 "invalid SymbolTableIndex"); 172 Sym.WeakTargetSymbolId = Target->UniqueId; 173 } 174 } 175 for (Section &Sec : Obj.getMutableSections()) { 176 for (Relocation &R : Sec.Relocs) { 177 if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size()) 178 return createStringError(object_error::parse_failed, 179 "SymbolTableIndex out of range"); 180 const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex]; 181 if (Sym == nullptr) 182 return createStringError(object_error::parse_failed, 183 "invalid SymbolTableIndex"); 184 R.Target = Sym->UniqueId; 185 R.TargetName = Sym->Name; 186 } 187 } 188 return Error::success(); 189} 190 191Expected<std::unique_ptr<Object>> COFFReader::create() const { 192 auto Obj = std::make_unique<Object>(); 193 194 bool IsBigObj = false; 195 if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) { 196 Obj->CoffFileHeader = *CFH; 197 } else { 198 const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader(); 199 if (!CBFH) 200 return createStringError(object_error::parse_failed, 201 "no COFF file header returned"); 202 // Only copying the few fields from the bigobj header that we need 203 // and won't recreate in the end. 204 Obj->CoffFileHeader.Machine = CBFH->Machine; 205 Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp; 206 IsBigObj = true; 207 } 208 209 if (Error E = readExecutableHeaders(*Obj)) 210 return std::move(E); 211 if (Error E = readSections(*Obj)) 212 return std::move(E); 213 if (Error E = readSymbols(*Obj, IsBigObj)) 214 return std::move(E); 215 if (Error E = setSymbolTargets(*Obj)) 216 return std::move(E); 217 218 return std::move(Obj); 219} 220 221} // end namespace coff 222} // end namespace objcopy 223} // end namespace llvm 224