1 //===- COFFReader.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 //===----------------------------------------------------------------------===//
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"
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
= COFFObj
.getDataDirectory(I
);
50 return errorCodeToError(object_error::parse_failed
);
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 Expected
<const coff_section
*> SecOrErr
= COFFObj
.getSection(I
);
62 return SecOrErr
.takeError();
63 const coff_section
*Sec
= *SecOrErr
;
64 Sections
.push_back(Section());
65 Section
&S
= Sections
.back();
67 S
.Header
.Characteristics
&= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL
;
68 ArrayRef
<uint8_t> Contents
;
69 if (Error E
= COFFObj
.getSectionContents(Sec
, Contents
))
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
))
78 return NameOrErr
.takeError();
80 Obj
.addSections(Sections
);
81 return Error::success();
84 Error
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
);
91 return SymOrErr
.takeError();
92 COFFSymbolRef SymRef
= *SymOrErr
;
94 Symbols
.push_back(Symbol());
95 Symbol
&Sym
= Symbols
.back();
96 // Copy symbols from the original form into an intermediate coff_symbol32.
99 *reinterpret_cast<const coff_symbol32
*>(SymRef
.getRawPtr()));
102 *reinterpret_cast<const coff_symbol16
*>(SymRef
.getRawPtr()));
103 auto NameOrErr
= COFFObj
.getSymbolName(SymRef
);
105 return NameOrErr
.takeError();
106 Sym
.Name
= *NameOrErr
;
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
117 if (SymRef
.isFileRecord())
118 Sym
.AuxFile
= StringRef(reinterpret_cast<const char *>(AuxData
.data()),
122 for (size_t I
= 0; I
< SymRef
.getNumberOfAuxSymbols(); I
++)
123 Sym
.AuxData
.push_back(AuxData
.slice(I
* SymSize
, sizeof(AuxSymbol
)));
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) <
131 Sym
.TargetSectionId
= Sections
[SymRef
.getSectionNumber() - 1].UniqueId
;
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
;
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
149 Sym
.WeakTargetSymbolId
= WE
->TagIndex
;
151 I
+= 1 + SymRef
.getNumberOfAuxSymbols();
153 Obj
.addSymbols(Symbols
);
154 return Error::success();
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);
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
;
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
];
185 return createStringError(object_error::parse_failed
,
186 "invalid SymbolTableIndex");
187 R
.Target
= Sym
->UniqueId
;
188 R
.TargetName
= Sym
->Name
;
191 return Error::success();
194 Expected
<std::unique_ptr
<Object
>> COFFReader::create() const {
195 auto Obj
= std::make_unique
<Object
>();
197 bool IsBigObj
= false;
198 if (const coff_file_header
*CFH
= COFFObj
.getCOFFHeader()) {
199 Obj
->CoffFileHeader
= *CFH
;
201 const coff_bigobj_file_header
*CBFH
= COFFObj
.getCOFFBigObjHeader();
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
;
212 if (Error E
= readExecutableHeaders(*Obj
))
214 if (Error E
= readSections(*Obj
))
216 if (Error E
= readSymbols(*Obj
, IsBigObj
))
218 if (Error E
= setSymbolTargets(*Obj
))
221 return std::move(Obj
);
224 } // end namespace coff
225 } // end namespace objcopy
226 } // end namespace llvm