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 Obj
.PeHeader
= *COFFObj
.getPE32PlusHeader();
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
;
47 for (size_t I
= 0; I
< Obj
.PeHeader
.NumberOfRvaAndSize
; I
++) {
48 const data_directory
*Dir
;
49 if (auto EC
= COFFObj
.getDataDirectory(I
, Dir
))
50 return errorCodeToError(EC
);
51 Obj
.DataDirectories
.emplace_back(*Dir
);
53 return Error::success();
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 const coff_section
*Sec
;
61 if (auto EC
= COFFObj
.getSection(I
, Sec
))
62 return errorCodeToError(EC
);
63 Sections
.push_back(Section());
64 Section
&S
= Sections
.back();
66 ArrayRef
<uint8_t> Contents
;
67 if (Error E
= COFFObj
.getSectionContents(Sec
, Contents
))
69 S
.setContentsRef(Contents
);
70 ArrayRef
<coff_relocation
> Relocs
= COFFObj
.getRelocations(Sec
);
71 for (const coff_relocation
&R
: Relocs
)
72 S
.Relocs
.push_back(R
);
73 if (Expected
<StringRef
> NameOrErr
= COFFObj
.getSectionName(Sec
))
76 return NameOrErr
.takeError();
77 if (Sec
->hasExtendedRelocations())
78 return createStringError(object_error::parse_failed
,
79 "extended relocations not supported yet");
81 Obj
.addSections(Sections
);
82 return Error::success();
85 Error
COFFReader::readSymbols(Object
&Obj
, bool IsBigObj
) const {
86 std::vector
<Symbol
> Symbols
;
87 Symbols
.reserve(COFFObj
.getRawNumberOfSymbols());
88 ArrayRef
<Section
> Sections
= Obj
.getSections();
89 for (uint32_t I
= 0, E
= COFFObj
.getRawNumberOfSymbols(); I
< E
;) {
90 Expected
<COFFSymbolRef
> SymOrErr
= COFFObj
.getSymbol(I
);
92 return SymOrErr
.takeError();
93 COFFSymbolRef SymRef
= *SymOrErr
;
95 Symbols
.push_back(Symbol());
96 Symbol
&Sym
= Symbols
.back();
97 // Copy symbols from the original form into an intermediate coff_symbol32.
100 *reinterpret_cast<const coff_symbol32
*>(SymRef
.getRawPtr()));
103 *reinterpret_cast<const coff_symbol16
*>(SymRef
.getRawPtr()));
104 if (auto EC
= COFFObj
.getSymbolName(SymRef
, Sym
.Name
))
105 return errorCodeToError(EC
);
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
116 if (SymRef
.isFileRecord())
117 Sym
.AuxFile
= StringRef(reinterpret_cast<const char *>(AuxData
.data()),
121 for (size_t I
= 0; I
< SymRef
.getNumberOfAuxSymbols(); I
++)
122 Sym
.AuxData
.push_back(AuxData
.slice(I
* SymSize
, sizeof(AuxSymbol
)));
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) <
130 Sym
.TargetSectionId
= Sections
[SymRef
.getSectionNumber() - 1].UniqueId
;
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
) {
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
;
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
148 Sym
.WeakTargetSymbolId
= WE
->TagIndex
;
150 I
+= 1 + SymRef
.getNumberOfAuxSymbols();
152 Obj
.addSymbols(Symbols
);
153 return Error::success();
156 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);
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
;
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
];
184 return createStringError(object_error::parse_failed
,
185 "invalid SymbolTableIndex");
186 R
.Target
= Sym
->UniqueId
;
187 R
.TargetName
= Sym
->Name
;
190 return Error::success();
193 Expected
<std::unique_ptr
<Object
>> COFFReader::create() const {
194 auto Obj
= std::make_unique
<Object
>();
196 bool IsBigObj
= false;
197 if (const coff_file_header
*CFH
= COFFObj
.getCOFFHeader()) {
198 Obj
->CoffFileHeader
= *CFH
;
200 const coff_bigobj_file_header
*CBFH
= COFFObj
.getCOFFBigObjHeader();
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
;
211 if (Error E
= readExecutableHeaders(*Obj
))
213 if (Error E
= readSections(*Obj
))
215 if (Error E
= readSymbols(*Obj
, IsBigObj
))
217 if (Error E
= setSymbolTargets(*Obj
))
220 return std::move(Obj
);
223 } // end namespace coff
224 } // end namespace objcopy
225 } // end namespace llvm