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 = 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
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    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
84Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
85  std::vector<Symbol> Symbols;
86  Symbols.reserve(COFFObj.getRawNumberOfSymbols());
87  ArrayRef<Section> Sections = Obj.getSections();
88  for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); 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
157Error 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
194Expected<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