1 //===- Reader.cpp ---------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
23 using namespace object;
26 Error COFFReader::readExecutableHeaders(Object &Obj) const {
27 const dos_header *DH = COFFObj.getDOSHeader();
28 Obj.Is64 = COFFObj.is64();
30 return Error::success();
34 if (DH->AddressOfNewExeHeader > sizeof(*DH))
35 Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),
36 DH->AddressOfNewExeHeader - sizeof(*DH));
39 const pe32plus_header *PE32Plus = nullptr;
40 if (auto EC = COFFObj.getPE32PlusHeader(PE32Plus))
41 return errorCodeToError(EC);
42 Obj.PeHeader = *PE32Plus;
44 const pe32_header *PE32 = nullptr;
45 if (auto EC = COFFObj.getPE32Header(PE32))
46 return errorCodeToError(EC);
47 copyPeHeader(Obj.PeHeader, *PE32);
48 // The pe32plus_header (stored in Object) lacks the BaseOfData field.
49 Obj.BaseOfData = PE32->BaseOfData;
52 for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {
53 const data_directory *Dir;
54 if (auto EC = COFFObj.getDataDirectory(I, Dir))
55 return errorCodeToError(EC);
56 Obj.DataDirectories.emplace_back(*Dir);
58 return Error::success();
61 Error COFFReader::readSections(Object &Obj) const {
62 std::vector<Section> Sections;
63 // Section indexing starts from 1.
64 for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
65 const coff_section *Sec;
66 if (auto EC = COFFObj.getSection(I, Sec))
67 return errorCodeToError(EC);
68 Sections.push_back(Section());
69 Section &S = Sections.back();
71 ArrayRef<uint8_t> Contents;
72 if (Error E = COFFObj.getSectionContents(Sec, Contents))
74 S.setContentsRef(Contents);
75 ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
76 for (const coff_relocation &R : Relocs)
77 S.Relocs.push_back(R);
78 if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))
81 return NameOrErr.takeError();
82 if (Sec->hasExtendedRelocations())
83 return createStringError(object_error::parse_failed,
84 "extended relocations not supported yet");
86 Obj.addSections(Sections);
87 return Error::success();
90 Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
91 std::vector<Symbol> Symbols;
92 Symbols.reserve(COFFObj.getRawNumberOfSymbols());
93 ArrayRef<Section> Sections = Obj.getSections();
94 for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
95 Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
97 return SymOrErr.takeError();
98 COFFSymbolRef SymRef = *SymOrErr;
100 Symbols.push_back(Symbol());
101 Symbol &Sym = Symbols.back();
102 // Copy symbols from the original form into an intermediate coff_symbol32.
105 *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));
108 *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
109 if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name))
110 return errorCodeToError(EC);
112 ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
113 size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
114 assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
115 // The auxillary symbols are structs of sizeof(coff_symbol16) each.
116 // In the big object format (where symbols are coff_symbol32), each
117 // auxillary symbol is padded with 2 bytes at the end. Copy each
118 // auxillary symbol to the Sym.AuxData vector. For file symbols,
119 // the whole range of aux symbols are interpreted as one null padded
121 if (SymRef.isFileRecord())
122 Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
126 for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
127 Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
129 // Find the unique id of the section
130 if (SymRef.getSectionNumber() <=
131 0) // Special symbol (undefined/absolute/debug)
132 Sym.TargetSectionId = SymRef.getSectionNumber();
133 else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
135 Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
137 return createStringError(object_error::parse_failed,
138 "section number out of range");
139 // For section definitions, check if it is comdat associative, and if
140 // it is, find the target section unique id.
141 const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
142 const coff_aux_weak_external *WE = SymRef.getWeakExternal();
143 if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
144 int32_t Index = SD->getNumber(IsBigObj);
145 if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
146 return createStringError(object_error::parse_failed,
147 "unexpected associative section index");
148 Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
150 // This is a raw symbol index for now, but store it in the Symbol
151 // until we've added them to the Object, which assigns the final
153 Sym.WeakTargetSymbolId = WE->TagIndex;
155 I += 1 + SymRef.getNumberOfAuxSymbols();
157 Obj.addSymbols(Symbols);
158 return Error::success();
161 Error COFFReader::setSymbolTargets(Object &Obj) const {
162 std::vector<const Symbol *> RawSymbolTable;
163 for (const Symbol &Sym : Obj.getSymbols()) {
164 RawSymbolTable.push_back(&Sym);
165 for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
166 RawSymbolTable.push_back(nullptr);
168 for (Symbol &Sym : Obj.getMutableSymbols()) {
169 // Convert WeakTargetSymbolId from the original raw symbol index to
170 // a proper unique id.
171 if (Sym.WeakTargetSymbolId) {
172 if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
173 return createStringError(object_error::parse_failed,
174 "weak external reference out of range");
175 const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
176 if (Target == nullptr)
177 return createStringError(object_error::parse_failed,
178 "invalid SymbolTableIndex");
179 Sym.WeakTargetSymbolId = Target->UniqueId;
182 for (Section &Sec : Obj.getMutableSections()) {
183 for (Relocation &R : Sec.Relocs) {
184 if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
185 return createStringError(object_error::parse_failed,
186 "SymbolTableIndex out of range");
187 const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
189 return createStringError(object_error::parse_failed,
190 "invalid SymbolTableIndex");
191 R.Target = Sym->UniqueId;
192 R.TargetName = Sym->Name;
195 return Error::success();
198 Expected<std::unique_ptr<Object>> COFFReader::create() const {
199 auto Obj = llvm::make_unique<Object>();
201 const coff_file_header *CFH = nullptr;
202 const coff_bigobj_file_header *CBFH = nullptr;
203 COFFObj.getCOFFHeader(CFH);
204 COFFObj.getCOFFBigObjHeader(CBFH);
205 bool IsBigObj = false;
207 Obj->CoffFileHeader = *CFH;
210 return createStringError(object_error::parse_failed,
211 "no COFF file header returned");
212 // Only copying the few fields from the bigobj header that we need
213 // and won't recreate in the end.
214 Obj->CoffFileHeader.Machine = CBFH->Machine;
215 Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;
219 if (Error E = readExecutableHeaders(*Obj))
221 if (Error E = readSections(*Obj))
223 if (Error E = readSymbols(*Obj, IsBigObj))
225 if (Error E = setSymbolTargets(*Obj))
228 return std::move(Obj);
231 } // end namespace coff
232 } // end namespace objcopy
233 } // end namespace llvm