blob: c347810dd240278ac8ae8647bb586f195ef84cc4 [file] [log] [blame]
Martin Storsjoe84a0b52018-12-19 07:24:38 +00001//===- Writer.cpp ---------------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Martin Storsjoe84a0b52018-12-19 07:24:38 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "Writer.h"
10#include "Object.h"
11#include "llvm-objcopy.h"
12#include "llvm/ADT/ArrayRef.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/BinaryFormat/COFF.h"
15#include "llvm/Object/COFF.h"
16#include "llvm/Support/ErrorHandling.h"
17#include <cstddef>
18#include <cstdint>
19
20namespace llvm {
21namespace objcopy {
22namespace coff {
23
24using namespace object;
25using namespace COFF;
26
Martin Storsjo10b72962019-01-10 21:28:24 +000027Error COFFWriter::finalizeRelocTargets() {
28 for (Section &Sec : Obj.Sections) {
29 for (Relocation &R : Sec.Relocs) {
30 const Symbol *Sym = Obj.findSymbol(R.Target);
31 if (Sym == nullptr)
32 return make_error<StringError>("Relocation target " + R.TargetName +
33 " (" + Twine(R.Target) +
34 ") not found",
35 object_error::invalid_symbol_index);
36 R.Reloc.SymbolTableIndex = Sym->RawIndex;
37 }
38 }
39 return Error::success();
40}
41
Martin Storsjoe84a0b52018-12-19 07:24:38 +000042void COFFWriter::layoutSections() {
43 for (auto &S : Obj.Sections) {
44 if (S.Header.SizeOfRawData > 0)
45 S.Header.PointerToRawData = FileSize;
46 FileSize += S.Header.SizeOfRawData; // For executables, this is already
47 // aligned to FileAlignment.
Martin Storsjof51f5ea2019-01-15 09:34:55 +000048 S.Header.NumberOfRelocations = S.Relocs.size();
49 S.Header.PointerToRelocations =
50 S.Header.NumberOfRelocations > 0 ? FileSize : 0;
Martin Storsjoe84a0b52018-12-19 07:24:38 +000051 FileSize += S.Relocs.size() * sizeof(coff_relocation);
52 FileSize = alignTo(FileSize, FileAlignment);
53
54 if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
55 SizeOfInitializedData += S.Header.SizeOfRawData;
56 }
57}
58
59size_t COFFWriter::finalizeStringTable() {
60 for (auto &S : Obj.Sections)
61 if (S.Name.size() > COFF::NameSize)
62 StrTabBuilder.add(S.Name);
63
Martin Storsjo10b72962019-01-10 21:28:24 +000064 for (const auto &S : Obj.getSymbols())
Martin Storsjoe84a0b52018-12-19 07:24:38 +000065 if (S.Name.size() > COFF::NameSize)
66 StrTabBuilder.add(S.Name);
67
68 StrTabBuilder.finalize();
69
70 for (auto &S : Obj.Sections) {
71 if (S.Name.size() > COFF::NameSize) {
72 snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d",
73 (int)StrTabBuilder.getOffset(S.Name));
74 } else {
75 strncpy(S.Header.Name, S.Name.data(), COFF::NameSize);
76 }
77 }
Martin Storsjo10b72962019-01-10 21:28:24 +000078 for (auto &S : Obj.getMutableSymbols()) {
Martin Storsjoe84a0b52018-12-19 07:24:38 +000079 if (S.Name.size() > COFF::NameSize) {
80 S.Sym.Name.Offset.Zeroes = 0;
81 S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name);
82 } else {
83 strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize);
84 }
85 }
86 return StrTabBuilder.getSize();
87}
88
89template <class SymbolTy>
90std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
Martin Storsjo10b72962019-01-10 21:28:24 +000091 size_t SymTabSize = Obj.getSymbols().size() * sizeof(SymbolTy);
92 for (const auto &S : Obj.getSymbols())
Martin Storsjoe84a0b52018-12-19 07:24:38 +000093 SymTabSize += S.AuxData.size();
94 return std::make_pair(SymTabSize, sizeof(SymbolTy));
95}
96
Martin Storsjo10b72962019-01-10 21:28:24 +000097Error COFFWriter::finalize(bool IsBigObj) {
98 if (Error E = finalizeRelocTargets())
99 return E;
100
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000101 size_t SizeOfHeaders = 0;
102 FileAlignment = 1;
103 size_t PeHeaderSize = 0;
104 if (Obj.IsPE) {
105 Obj.DosHeader.AddressOfNewExeHeader =
106 sizeof(Obj.DosHeader) + Obj.DosStub.size();
107 SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic);
108
109 FileAlignment = Obj.PeHeader.FileAlignment;
110 Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size();
111
112 PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header);
113 SizeOfHeaders +=
114 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
115 }
116 Obj.CoffFileHeader.NumberOfSections = Obj.Sections.size();
117 SizeOfHeaders +=
118 IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
119 SizeOfHeaders += sizeof(coff_section) * Obj.Sections.size();
120 SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
121
122 Obj.CoffFileHeader.SizeOfOptionalHeader =
123 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
124
125 FileSize = SizeOfHeaders;
126 SizeOfInitializedData = 0;
127
128 layoutSections();
129
130 if (Obj.IsPE) {
131 Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
132 Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
133
134 if (!Obj.Sections.empty()) {
135 const Section &S = Obj.Sections.back();
136 Obj.PeHeader.SizeOfImage =
137 alignTo(S.Header.VirtualAddress + S.Header.VirtualSize,
138 Obj.PeHeader.SectionAlignment);
139 }
140
141 // If the PE header had a checksum, clear it, since it isn't valid
142 // any longer. (We don't calculate a new one.)
143 Obj.PeHeader.CheckSum = 0;
144 }
145
146 size_t StrTabSize = finalizeStringTable();
147 size_t SymTabSize, SymbolSize;
148 std::tie(SymTabSize, SymbolSize) = IsBigObj
149 ? finalizeSymbolTable<coff_symbol32>()
150 : finalizeSymbolTable<coff_symbol16>();
151
152 size_t PointerToSymbolTable = FileSize;
153 // StrTabSize <= 4 is the size of an empty string table, only consisting
154 // of the length field.
Martin Storsjod1cc64f2019-01-11 13:47:37 +0000155 if (SymTabSize == 0 && StrTabSize <= 4 && Obj.IsPE) {
156 // For executables, don't point to the symbol table and skip writing
157 // the length field, if both the symbol and string tables are empty.
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000158 PointerToSymbolTable = 0;
Martin Storsjod1cc64f2019-01-11 13:47:37 +0000159 StrTabSize = 0;
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000160 }
161
162 size_t NumRawSymbols = SymTabSize / SymbolSize;
163 Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable;
164 Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols;
165 FileSize += SymTabSize + StrTabSize;
166 FileSize = alignTo(FileSize, FileAlignment);
Martin Storsjo10b72962019-01-10 21:28:24 +0000167
168 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000169}
170
171void COFFWriter::writeHeaders(bool IsBigObj) {
172 uint8_t *Ptr = Buf.getBufferStart();
173 if (Obj.IsPE) {
174 memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader));
175 Ptr += sizeof(Obj.DosHeader);
176 memcpy(Ptr, Obj.DosStub.data(), Obj.DosStub.size());
177 Ptr += Obj.DosStub.size();
178 memcpy(Ptr, PEMagic, sizeof(PEMagic));
179 Ptr += sizeof(PEMagic);
180 }
181 if (!IsBigObj) {
182 memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader));
183 Ptr += sizeof(Obj.CoffFileHeader);
184 } else {
185 // Generate a coff_bigobj_file_header, filling it in with the values
186 // from Obj.CoffFileHeader. All extra fields that don't exist in
187 // coff_file_header can be set to hardcoded values.
188 coff_bigobj_file_header BigObjHeader;
189 BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN;
190 BigObjHeader.Sig2 = 0xffff;
191 BigObjHeader.Version = BigObjHeader::MinBigObjectVersion;
192 BigObjHeader.Machine = Obj.CoffFileHeader.Machine;
193 BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp;
194 memcpy(BigObjHeader.UUID, BigObjMagic, sizeof(BigObjMagic));
195 BigObjHeader.unused1 = 0;
196 BigObjHeader.unused2 = 0;
197 BigObjHeader.unused3 = 0;
198 BigObjHeader.unused4 = 0;
199 // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
200 // get the original one instead.
201 BigObjHeader.NumberOfSections = Obj.Sections.size();
202 BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable;
203 BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols;
204
205 memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader));
206 Ptr += sizeof(BigObjHeader);
207 }
208 if (Obj.IsPE) {
209 if (Obj.Is64) {
210 memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader));
211 Ptr += sizeof(Obj.PeHeader);
212 } else {
213 pe32_header PeHeader;
214 copyPeHeader(PeHeader, Obj.PeHeader);
215 // The pe32plus_header (stored in Object) lacks the BaseOfData field.
216 PeHeader.BaseOfData = Obj.BaseOfData;
217
218 memcpy(Ptr, &PeHeader, sizeof(PeHeader));
219 Ptr += sizeof(PeHeader);
220 }
221 for (const auto &DD : Obj.DataDirectories) {
222 memcpy(Ptr, &DD, sizeof(DD));
223 Ptr += sizeof(DD);
224 }
225 }
226 for (const auto &S : Obj.Sections) {
227 memcpy(Ptr, &S.Header, sizeof(S.Header));
228 Ptr += sizeof(S.Header);
229 }
230}
231
232void COFFWriter::writeSections() {
233 for (const auto &S : Obj.Sections) {
234 uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
Martin Storsjo14cfa9a2018-12-20 21:35:59 +0000235 std::copy(S.Contents.begin(), S.Contents.end(), Ptr);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000236
237 // For executable sections, pad the remainder of the raw data size with
238 // 0xcc, which is int3 on x86.
239 if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
240 S.Header.SizeOfRawData > S.Contents.size())
241 memset(Ptr + S.Contents.size(), 0xcc,
242 S.Header.SizeOfRawData - S.Contents.size());
243
244 Ptr += S.Header.SizeOfRawData;
Martin Storsjo10b72962019-01-10 21:28:24 +0000245 for (const auto &R : S.Relocs) {
246 memcpy(Ptr, &R.Reloc, sizeof(R.Reloc));
247 Ptr += sizeof(R.Reloc);
248 }
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000249 }
250}
251
252template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
253 uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable;
Martin Storsjo10b72962019-01-10 21:28:24 +0000254 for (const auto &S : Obj.getSymbols()) {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000255 // Convert symbols back to the right size, from coff_symbol32.
256 copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
257 S.Sym);
258 Ptr += sizeof(SymbolTy);
Martin Storsjo14cfa9a2018-12-20 21:35:59 +0000259 std::copy(S.AuxData.begin(), S.AuxData.end(), Ptr);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000260 Ptr += S.AuxData.size();
261 }
262 if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) {
263 // Always write a string table in object files, even an empty one.
264 StrTabBuilder.write(Ptr);
265 Ptr += StrTabBuilder.getSize();
266 }
267}
268
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000269Error COFFWriter::write(bool IsBigObj) {
Martin Storsjo10b72962019-01-10 21:28:24 +0000270 if (Error E = finalize(IsBigObj))
271 return E;
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000272
273 Buf.allocate(FileSize);
274
275 writeHeaders(IsBigObj);
276 writeSections();
277 if (IsBigObj)
278 writeSymbolStringTables<coff_symbol32>();
279 else
280 writeSymbolStringTables<coff_symbol16>();
281
282 if (Obj.IsPE)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000283 if (Error E = patchDebugDirectory())
284 return E;
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000285
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000286 return Buf.commit();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000287}
288
289// Locate which sections contain the debug directories, iterate over all
290// the debug_directory structs in there, and set the PointerToRawData field
291// in all of them, according to their new physical location in the file.
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000292Error COFFWriter::patchDebugDirectory() {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000293 if (Obj.DataDirectories.size() < DEBUG_DIRECTORY)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000294 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000295 const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
296 if (Dir->Size <= 0)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000297 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000298 for (const auto &S : Obj.Sections) {
299 if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress &&
300 Dir->RelativeVirtualAddress <
301 S.Header.VirtualAddress + S.Header.SizeOfRawData) {
302 if (Dir->RelativeVirtualAddress + Dir->Size >
303 S.Header.VirtualAddress + S.Header.SizeOfRawData)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000304 return make_error<StringError>(
305 "Debug directory extends past end of section",
306 object_error::parse_failed);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000307
308 size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
309 uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset;
310 uint8_t *End = Ptr + Dir->Size;
311 while (Ptr < End) {
312 debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr);
313 Debug->PointerToRawData =
314 S.Header.PointerToRawData + Offset + sizeof(debug_directory);
315 Ptr += sizeof(debug_directory) + Debug->SizeOfData;
316 Offset += sizeof(debug_directory) + Debug->SizeOfData;
317 }
318 // Debug directory found and patched, all done.
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000319 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000320 }
321 }
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000322 return make_error<StringError>("Debug directory not found",
323 object_error::parse_failed);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000324}
325
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000326Error COFFWriter::write() {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000327 bool IsBigObj = Obj.Sections.size() > MaxNumberOfSections16;
328 if (IsBigObj && Obj.IsPE)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000329 return make_error<StringError>("Too many sections for executable",
330 object_error::parse_failed);
331 return write(IsBigObj);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000332}
333
334} // end namespace coff
335} // end namespace objcopy
336} // end namespace llvm