1 //===- Writer.cpp ---------------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 #include "llvm-objcopy.h"
13 #include "llvm/ADT/ArrayRef.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/BinaryFormat/COFF.h"
16 #include "llvm/Object/COFF.h"
17 #include "llvm/Support/ErrorHandling.h"
25 using namespace object
;
28 Error
COFFWriter::finalizeRelocTargets() {
29 for (Section
&Sec
: Obj
.Sections
) {
30 for (Relocation
&R
: Sec
.Relocs
) {
31 const Symbol
*Sym
= Obj
.findSymbol(R
.Target
);
33 return make_error
<StringError
>("Relocation target " + R
.TargetName
+
34 " (" + Twine(R
.Target
) +
36 object_error::invalid_symbol_index
);
37 R
.Reloc
.SymbolTableIndex
= Sym
->RawIndex
;
40 return Error::success();
43 void COFFWriter::layoutSections() {
44 for (auto &S
: Obj
.Sections
) {
45 if (S
.Header
.SizeOfRawData
> 0)
46 S
.Header
.PointerToRawData
= FileSize
;
47 FileSize
+= S
.Header
.SizeOfRawData
; // For executables, this is already
48 // aligned to FileAlignment.
49 S
.Header
.NumberOfRelocations
= S
.Relocs
.size();
50 S
.Header
.PointerToRelocations
=
51 S
.Header
.NumberOfRelocations
> 0 ? FileSize
: 0;
52 FileSize
+= S
.Relocs
.size() * sizeof(coff_relocation
);
53 FileSize
= alignTo(FileSize
, FileAlignment
);
55 if (S
.Header
.Characteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
56 SizeOfInitializedData
+= S
.Header
.SizeOfRawData
;
60 size_t COFFWriter::finalizeStringTable() {
61 for (auto &S
: Obj
.Sections
)
62 if (S
.Name
.size() > COFF::NameSize
)
63 StrTabBuilder
.add(S
.Name
);
65 for (const auto &S
: Obj
.getSymbols())
66 if (S
.Name
.size() > COFF::NameSize
)
67 StrTabBuilder
.add(S
.Name
);
69 StrTabBuilder
.finalize();
71 for (auto &S
: Obj
.Sections
) {
72 if (S
.Name
.size() > COFF::NameSize
) {
73 snprintf(S
.Header
.Name
, sizeof(S
.Header
.Name
), "/%d",
74 (int)StrTabBuilder
.getOffset(S
.Name
));
76 strncpy(S
.Header
.Name
, S
.Name
.data(), COFF::NameSize
);
79 for (auto &S
: Obj
.getMutableSymbols()) {
80 if (S
.Name
.size() > COFF::NameSize
) {
81 S
.Sym
.Name
.Offset
.Zeroes
= 0;
82 S
.Sym
.Name
.Offset
.Offset
= StrTabBuilder
.getOffset(S
.Name
);
84 strncpy(S
.Sym
.Name
.ShortName
, S
.Name
.data(), COFF::NameSize
);
87 return StrTabBuilder
.getSize();
90 template <class SymbolTy
>
91 std::pair
<size_t, size_t> COFFWriter::finalizeSymbolTable() {
92 size_t SymTabSize
= Obj
.getSymbols().size() * sizeof(SymbolTy
);
93 for (const auto &S
: Obj
.getSymbols())
94 SymTabSize
+= S
.AuxData
.size();
95 return std::make_pair(SymTabSize
, sizeof(SymbolTy
));
98 Error
COFFWriter::finalize(bool IsBigObj
) {
99 if (Error E
= finalizeRelocTargets())
102 size_t SizeOfHeaders
= 0;
104 size_t PeHeaderSize
= 0;
106 Obj
.DosHeader
.AddressOfNewExeHeader
=
107 sizeof(Obj
.DosHeader
) + Obj
.DosStub
.size();
108 SizeOfHeaders
+= Obj
.DosHeader
.AddressOfNewExeHeader
+ sizeof(PEMagic
);
110 FileAlignment
= Obj
.PeHeader
.FileAlignment
;
111 Obj
.PeHeader
.NumberOfRvaAndSize
= Obj
.DataDirectories
.size();
113 PeHeaderSize
= Obj
.Is64
? sizeof(pe32plus_header
) : sizeof(pe32_header
);
115 PeHeaderSize
+ sizeof(data_directory
) * Obj
.DataDirectories
.size();
117 Obj
.CoffFileHeader
.NumberOfSections
= Obj
.Sections
.size();
119 IsBigObj
? sizeof(coff_bigobj_file_header
) : sizeof(coff_file_header
);
120 SizeOfHeaders
+= sizeof(coff_section
) * Obj
.Sections
.size();
121 SizeOfHeaders
= alignTo(SizeOfHeaders
, FileAlignment
);
123 Obj
.CoffFileHeader
.SizeOfOptionalHeader
=
124 PeHeaderSize
+ sizeof(data_directory
) * Obj
.DataDirectories
.size();
126 FileSize
= SizeOfHeaders
;
127 SizeOfInitializedData
= 0;
132 Obj
.PeHeader
.SizeOfHeaders
= SizeOfHeaders
;
133 Obj
.PeHeader
.SizeOfInitializedData
= SizeOfInitializedData
;
135 if (!Obj
.Sections
.empty()) {
136 const Section
&S
= Obj
.Sections
.back();
137 Obj
.PeHeader
.SizeOfImage
=
138 alignTo(S
.Header
.VirtualAddress
+ S
.Header
.VirtualSize
,
139 Obj
.PeHeader
.SectionAlignment
);
142 // If the PE header had a checksum, clear it, since it isn't valid
143 // any longer. (We don't calculate a new one.)
144 Obj
.PeHeader
.CheckSum
= 0;
147 size_t StrTabSize
= finalizeStringTable();
148 size_t SymTabSize
, SymbolSize
;
149 std::tie(SymTabSize
, SymbolSize
) = IsBigObj
150 ? finalizeSymbolTable
<coff_symbol32
>()
151 : finalizeSymbolTable
<coff_symbol16
>();
153 size_t PointerToSymbolTable
= FileSize
;
154 // StrTabSize <= 4 is the size of an empty string table, only consisting
155 // of the length field.
156 if (SymTabSize
== 0 && StrTabSize
<= 4 && Obj
.IsPE
) {
157 // For executables, don't point to the symbol table and skip writing
158 // the length field, if both the symbol and string tables are empty.
159 PointerToSymbolTable
= 0;
163 size_t NumRawSymbols
= SymTabSize
/ SymbolSize
;
164 Obj
.CoffFileHeader
.PointerToSymbolTable
= PointerToSymbolTable
;
165 Obj
.CoffFileHeader
.NumberOfSymbols
= NumRawSymbols
;
166 FileSize
+= SymTabSize
+ StrTabSize
;
167 FileSize
= alignTo(FileSize
, FileAlignment
);
169 return Error::success();
172 void COFFWriter::writeHeaders(bool IsBigObj
) {
173 uint8_t *Ptr
= Buf
.getBufferStart();
175 memcpy(Ptr
, &Obj
.DosHeader
, sizeof(Obj
.DosHeader
));
176 Ptr
+= sizeof(Obj
.DosHeader
);
177 memcpy(Ptr
, Obj
.DosStub
.data(), Obj
.DosStub
.size());
178 Ptr
+= Obj
.DosStub
.size();
179 memcpy(Ptr
, PEMagic
, sizeof(PEMagic
));
180 Ptr
+= sizeof(PEMagic
);
183 memcpy(Ptr
, &Obj
.CoffFileHeader
, sizeof(Obj
.CoffFileHeader
));
184 Ptr
+= sizeof(Obj
.CoffFileHeader
);
186 // Generate a coff_bigobj_file_header, filling it in with the values
187 // from Obj.CoffFileHeader. All extra fields that don't exist in
188 // coff_file_header can be set to hardcoded values.
189 coff_bigobj_file_header BigObjHeader
;
190 BigObjHeader
.Sig1
= IMAGE_FILE_MACHINE_UNKNOWN
;
191 BigObjHeader
.Sig2
= 0xffff;
192 BigObjHeader
.Version
= BigObjHeader::MinBigObjectVersion
;
193 BigObjHeader
.Machine
= Obj
.CoffFileHeader
.Machine
;
194 BigObjHeader
.TimeDateStamp
= Obj
.CoffFileHeader
.TimeDateStamp
;
195 memcpy(BigObjHeader
.UUID
, BigObjMagic
, sizeof(BigObjMagic
));
196 BigObjHeader
.unused1
= 0;
197 BigObjHeader
.unused2
= 0;
198 BigObjHeader
.unused3
= 0;
199 BigObjHeader
.unused4
= 0;
200 // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
201 // get the original one instead.
202 BigObjHeader
.NumberOfSections
= Obj
.Sections
.size();
203 BigObjHeader
.PointerToSymbolTable
= Obj
.CoffFileHeader
.PointerToSymbolTable
;
204 BigObjHeader
.NumberOfSymbols
= Obj
.CoffFileHeader
.NumberOfSymbols
;
206 memcpy(Ptr
, &BigObjHeader
, sizeof(BigObjHeader
));
207 Ptr
+= sizeof(BigObjHeader
);
211 memcpy(Ptr
, &Obj
.PeHeader
, sizeof(Obj
.PeHeader
));
212 Ptr
+= sizeof(Obj
.PeHeader
);
214 pe32_header PeHeader
;
215 copyPeHeader(PeHeader
, Obj
.PeHeader
);
216 // The pe32plus_header (stored in Object) lacks the BaseOfData field.
217 PeHeader
.BaseOfData
= Obj
.BaseOfData
;
219 memcpy(Ptr
, &PeHeader
, sizeof(PeHeader
));
220 Ptr
+= sizeof(PeHeader
);
222 for (const auto &DD
: Obj
.DataDirectories
) {
223 memcpy(Ptr
, &DD
, sizeof(DD
));
227 for (const auto &S
: Obj
.Sections
) {
228 memcpy(Ptr
, &S
.Header
, sizeof(S
.Header
));
229 Ptr
+= sizeof(S
.Header
);
233 void COFFWriter::writeSections() {
234 for (const auto &S
: Obj
.Sections
) {
235 uint8_t *Ptr
= Buf
.getBufferStart() + S
.Header
.PointerToRawData
;
236 std::copy(S
.Contents
.begin(), S
.Contents
.end(), Ptr
);
238 // For executable sections, pad the remainder of the raw data size with
239 // 0xcc, which is int3 on x86.
240 if ((S
.Header
.Characteristics
& IMAGE_SCN_CNT_CODE
) &&
241 S
.Header
.SizeOfRawData
> S
.Contents
.size())
242 memset(Ptr
+ S
.Contents
.size(), 0xcc,
243 S
.Header
.SizeOfRawData
- S
.Contents
.size());
245 Ptr
+= S
.Header
.SizeOfRawData
;
246 for (const auto &R
: S
.Relocs
) {
247 memcpy(Ptr
, &R
.Reloc
, sizeof(R
.Reloc
));
248 Ptr
+= sizeof(R
.Reloc
);
253 template <class SymbolTy
> void COFFWriter::writeSymbolStringTables() {
254 uint8_t *Ptr
= Buf
.getBufferStart() + Obj
.CoffFileHeader
.PointerToSymbolTable
;
255 for (const auto &S
: Obj
.getSymbols()) {
256 // Convert symbols back to the right size, from coff_symbol32.
257 copySymbol
<SymbolTy
, coff_symbol32
>(*reinterpret_cast<SymbolTy
*>(Ptr
),
259 Ptr
+= sizeof(SymbolTy
);
260 std::copy(S
.AuxData
.begin(), S
.AuxData
.end(), Ptr
);
261 Ptr
+= S
.AuxData
.size();
263 if (StrTabBuilder
.getSize() > 4 || !Obj
.IsPE
) {
264 // Always write a string table in object files, even an empty one.
265 StrTabBuilder
.write(Ptr
);
266 Ptr
+= StrTabBuilder
.getSize();
270 Error
COFFWriter::write(bool IsBigObj
) {
271 if (Error E
= finalize(IsBigObj
))
274 Buf
.allocate(FileSize
);
276 writeHeaders(IsBigObj
);
279 writeSymbolStringTables
<coff_symbol32
>();
281 writeSymbolStringTables
<coff_symbol16
>();
284 if (Error E
= patchDebugDirectory())
290 // Locate which sections contain the debug directories, iterate over all
291 // the debug_directory structs in there, and set the PointerToRawData field
292 // in all of them, according to their new physical location in the file.
293 Error
COFFWriter::patchDebugDirectory() {
294 if (Obj
.DataDirectories
.size() < DEBUG_DIRECTORY
)
295 return Error::success();
296 const data_directory
*Dir
= &Obj
.DataDirectories
[DEBUG_DIRECTORY
];
298 return Error::success();
299 for (const auto &S
: Obj
.Sections
) {
300 if (Dir
->RelativeVirtualAddress
>= S
.Header
.VirtualAddress
&&
301 Dir
->RelativeVirtualAddress
<
302 S
.Header
.VirtualAddress
+ S
.Header
.SizeOfRawData
) {
303 if (Dir
->RelativeVirtualAddress
+ Dir
->Size
>
304 S
.Header
.VirtualAddress
+ S
.Header
.SizeOfRawData
)
305 return make_error
<StringError
>(
306 "Debug directory extends past end of section",
307 object_error::parse_failed
);
309 size_t Offset
= Dir
->RelativeVirtualAddress
- S
.Header
.VirtualAddress
;
310 uint8_t *Ptr
= Buf
.getBufferStart() + S
.Header
.PointerToRawData
+ Offset
;
311 uint8_t *End
= Ptr
+ Dir
->Size
;
313 debug_directory
*Debug
= reinterpret_cast<debug_directory
*>(Ptr
);
314 Debug
->PointerToRawData
=
315 S
.Header
.PointerToRawData
+ Offset
+ sizeof(debug_directory
);
316 Ptr
+= sizeof(debug_directory
) + Debug
->SizeOfData
;
317 Offset
+= sizeof(debug_directory
) + Debug
->SizeOfData
;
319 // Debug directory found and patched, all done.
320 return Error::success();
323 return make_error
<StringError
>("Debug directory not found",
324 object_error::parse_failed
);
327 Error
COFFWriter::write() {
328 bool IsBigObj
= Obj
.Sections
.size() > MaxNumberOfSections16
;
329 if (IsBigObj
&& Obj
.IsPE
)
330 return make_error
<StringError
>("Too many sections for executable",
331 object_error::parse_failed
);
332 return write(IsBigObj
);
335 } // end namespace coff
336 } // end namespace objcopy
337 } // end namespace llvm