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