1 //===- COFFReader.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 "COFFReader.h" 10 #include "COFFObject.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 19 namespace llvm { 20 namespace objcopy { 21 namespace coff { 22 23 using namespace object; 24 using namespace COFF; 25 26 Error 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 = COFFObj.getDataDirectory(I); 49 if (!Dir) 50 return errorCodeToError(object_error::parse_failed); 51 Obj.DataDirectories.emplace_back(*Dir); 52 } 53 return Error::success(); 54 } 55 56 Error 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 Expected<const coff_section *> SecOrErr = COFFObj.getSection(I); 61 if (!SecOrErr) 62 return SecOrErr.takeError(); 63 const coff_section *Sec = *SecOrErr; 64 Sections.push_back(Section()); 65 Section &S = Sections.back(); 66 S.Header = *Sec; 67 S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL; 68 ArrayRef<uint8_t> Contents; 69 if (Error E = COFFObj.getSectionContents(Sec, Contents)) 70 return E; 71 S.setContentsRef(Contents); 72 ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec); 73 llvm::append_range(S.Relocs, Relocs); 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 83 Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const { 84 std::vector<Symbol> Symbols; 85 Symbols.reserve(COFFObj.getNumberOfSymbols()); 86 ArrayRef<Section> Sections = Obj.getSections(); 87 for (uint32_t I = 0, E = COFFObj.getNumberOfSymbols(); 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 auto NameOrErr = COFFObj.getSymbolName(SymRef); 103 if (!NameOrErr) 104 return NameOrErr.takeError(); 105 Sym.Name = *NameOrErr; 106 107 ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef); 108 size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16); 109 assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols()); 110 // The auxillary symbols are structs of sizeof(coff_symbol16) each. 111 // In the big object format (where symbols are coff_symbol32), each 112 // auxillary symbol is padded with 2 bytes at the end. Copy each 113 // auxillary symbol to the Sym.AuxData vector. For file symbols, 114 // the whole range of aux symbols are interpreted as one null padded 115 // string instead. 116 if (SymRef.isFileRecord()) 117 Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()), 118 AuxData.size()) 119 .rtrim('\0'); 120 else 121 for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++) 122 Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol))); 123 124 // Find the unique id of the section 125 if (SymRef.getSectionNumber() <= 126 0) // Special symbol (undefined/absolute/debug) 127 Sym.TargetSectionId = SymRef.getSectionNumber(); 128 else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) < 129 Sections.size()) 130 Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId; 131 else 132 return createStringError(object_error::parse_failed, 133 "section number out of range"); 134 // For section definitions, check if it is comdat associative, and if 135 // it is, find the target section unique id. 136 const coff_aux_section_definition *SD = SymRef.getSectionDefinition(); 137 const coff_aux_weak_external *WE = SymRef.getWeakExternal(); 138 if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE && !Obj.IsPE) { 139 int32_t Index = SD->getNumber(IsBigObj); 140 if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size()) 141 return createStringError(object_error::parse_failed, 142 "unexpected associative section index"); 143 Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId; 144 } else if (WE) { 145 // This is a raw symbol index for now, but store it in the Symbol 146 // until we've added them to the Object, which assigns the final 147 // unique ids. 148 Sym.WeakTargetSymbolId = WE->TagIndex; 149 } 150 I += 1 + SymRef.getNumberOfAuxSymbols(); 151 } 152 Obj.addSymbols(Symbols); 153 return Error::success(); 154 } 155 156 Error COFFReader::setSymbolTargets(Object &Obj) const { 157 std::vector<const Symbol *> RawSymbolTable; 158 for (const Symbol &Sym : Obj.getSymbols()) { 159 RawSymbolTable.push_back(&Sym); 160 for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++) 161 RawSymbolTable.push_back(nullptr); 162 } 163 for (Symbol &Sym : Obj.getMutableSymbols()) { 164 // Convert WeakTargetSymbolId from the original raw symbol index to 165 // a proper unique id. 166 if (Sym.WeakTargetSymbolId) { 167 if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size()) 168 return createStringError(object_error::parse_failed, 169 "weak external reference out of range"); 170 const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId]; 171 if (Target == nullptr) 172 return createStringError(object_error::parse_failed, 173 "invalid SymbolTableIndex"); 174 Sym.WeakTargetSymbolId = Target->UniqueId; 175 } 176 } 177 for (Section &Sec : Obj.getMutableSections()) { 178 for (Relocation &R : Sec.Relocs) { 179 if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size()) 180 return createStringError(object_error::parse_failed, 181 "SymbolTableIndex out of range"); 182 const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex]; 183 if (Sym == nullptr) 184 return createStringError(object_error::parse_failed, 185 "invalid SymbolTableIndex"); 186 R.Target = Sym->UniqueId; 187 R.TargetName = Sym->Name; 188 } 189 } 190 return Error::success(); 191 } 192 193 Expected<std::unique_ptr<Object>> COFFReader::create() const { 194 auto Obj = std::make_unique<Object>(); 195 196 bool IsBigObj = false; 197 if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) { 198 Obj->CoffFileHeader = *CFH; 199 } else { 200 const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader(); 201 if (!CBFH) 202 return createStringError(object_error::parse_failed, 203 "no COFF file header returned"); 204 // Only copying the few fields from the bigobj header that we need 205 // and won't recreate in the end. 206 Obj->CoffFileHeader.Machine = CBFH->Machine; 207 Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp; 208 IsBigObj = true; 209 } 210 211 if (Error E = readExecutableHeaders(*Obj)) 212 return std::move(E); 213 if (Error E = readSections(*Obj)) 214 return std::move(E); 215 if (Error E = readSymbols(*Obj, IsBigObj)) 216 return std::move(E); 217 if (Error E = setSymbolTargets(*Obj)) 218 return std::move(E); 219 220 return std::move(Obj); 221 } 222 223 } // end namespace coff 224 } // end namespace objcopy 225 } // end namespace llvm 226