LLVM  16.0.0git
COFFReader.cpp
Go to the documentation of this file.
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"
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.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 
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 
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
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::COFF::IMAGE_SCN_LNK_NRELOC_OVFL
@ IMAGE_SCN_LNK_NRELOC_OVFL
Definition: COFF.h:314
llvm::lltok::Error
@ Error
Definition: LLToken.h:21
StringRef.h
ErrorHandling.h
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
COFF.h
llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE
@ IMAGE_COMDAT_SELECT_ASSOCIATIVE
Definition: COFF.h:410
llvm::AMDGPU::Exp::Target
Target
Definition: SIDefines.h:858
llvm::objcopy::coff::COFFReader::create
Expected< std::unique_ptr< Object > > create() const
Definition: COFFReader.cpp:194
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
COFFObject.h
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:241
llvm::ARMBuildAttrs::Section
@ Section
Legacy Tags.
Definition: ARMBuildAttributes.h:82
llvm::object::coff_file_header
Definition: COFF.h:75
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:92
llvm::object::coff_symbol16
coff_symbol< support::ulittle16_t > coff_symbol16
Definition: COFF.h:265
llvm::object::coff_bigobj_file_header::TimeDateStamp
support::ulittle32_t TimeDateStamp
Definition: COFF.h:92
object
bar al al movzbl eax ret Missed when stored in a memory object
Definition: README.txt:1411
Index
uint32_t Index
Definition: ELFObjHandler.cpp:82
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
I
#define I(x, y, z)
Definition: MD5.cpp:58
ArrayRef.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::object::coff_bigobj_file_header
Definition: COFF.h:87
uint32_t
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
llvm::object::coff_symbol32
coff_symbol< support::ulittle32_t > coff_symbol32
Definition: COFF.h:266
llvm::objcopy::coff::copyPeHeader
void copyPeHeader(PeHeader1Ty &Dest, const PeHeader2Ty &Src)
Definition: COFFObject.h:176
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1239
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::objcopy::coff::copySymbol
void copySymbol(Symbol1Ty &Dest, const Symbol2Ty &Src)
Definition: COFFObject.h:162
llvm::ARMBuildAttrs::Symbol
@ Symbol
Definition: ARMBuildAttributes.h:83
COFFReader.h
COFF.h
llvm::object::coff_bigobj_file_header::Machine
support::ulittle16_t Machine
Definition: COFF.h:91