xref: /freebsd/contrib/llvm-project/llvm/lib/ObjCopy/COFF/COFFReader.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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 
readExecutableHeaders(Object & Obj) const26 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 
readSections(Object & Obj) const56 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 
readSymbols(Object & Obj,bool IsBigObj) const83 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 
setSymbolTargets(Object & Obj) const156 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 
create() const193 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