LLVM 20.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"
14#include "llvm/Object/COFF.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.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
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
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
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
uint32_t Index
Symbol * Sym
Definition: ELF_riscv.cpp:479
#define I(x, y, z)
Definition: MD5.cpp:58
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
Expected< std::unique_ptr< Object > > create() const
Definition: COFFReader.cpp:194
const dos_header * getDOSHeader() const
Definition: COFF.h:1129
Expected< StringRef > getSectionName(DataRefImpl Sec) const override
const pe32_header * getPE32Header() const
Definition: COFF.h:1139
Expected< COFFSymbolRef > getSymbol(uint32_t index) const
Definition: COFF.h:1145
Expected< StringRef > getSymbolName(DataRefImpl Symb) const override
uint32_t getNumberOfSymbols() const
Definition: COFF.h:1008
const coff_file_header * getCOFFHeader() const
Definition: COFF.h:1135
const coff_bigobj_file_header * getCOFFBigObjHeader() const
Definition: COFF.h:1136
uint32_t getNumberOfSections() const
Definition: COFF.h:983
Expected< const coff_section * > getSection(int32_t index) const
Expected< ArrayRef< uint8_t > > getSectionContents(DataRefImpl Sec) const override
const data_directory * getDataDirectory(uint32_t index) const
ArrayRef< uint8_t > getSymbolAuxData(COFFSymbolRef Symbol) const
ArrayRef< coff_relocation > getRelocations(const coff_section *Sec) const
const pe32plus_header * getPE32PlusHeader() const
Definition: COFF.h:1140
@ IMAGE_SCN_LNK_NRELOC_OVFL
Definition: COFF.h:329
@ IMAGE_COMDAT_SELECT_ASSOCIATIVE
Definition: COFF.h:458
void copySymbol(Symbol1Ty &Dest, const Symbol2Ty &Src)
Definition: COFFObject.h:161
void copyPeHeader(PeHeader1Ty &Dest, const PeHeader2Ty &Src)
Definition: COFFObject.h:175
coff_symbol< support::ulittle32_t > coff_symbol32
Definition: COFF.h:270
coff_symbol< support::ulittle16_t > coff_symbol16
Definition: COFF.h:269
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1291
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:111
support::ulittle16_t Machine
Definition: COFF.h:95
support::ulittle32_t TimeDateStamp
Definition: COFF.h:96