blob: 385d43b1bae561507a912a03e2af9982c404ed45 [file] [log] [blame]
Martin Storsjoe84a0b52018-12-19 07:24:38 +00001//===- Writer.cpp ---------------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Writer.h"
11#include "Object.h"
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"
18#include <cstddef>
19#include <cstdint>
20
21namespace llvm {
22namespace objcopy {
23namespace coff {
24
25using namespace object;
26using namespace COFF;
27
Martin Storsjo10b72962019-01-10 21:28:24 +000028Error COFFWriter::finalizeRelocTargets() {
29 for (Section &Sec : Obj.Sections) {
30 for (Relocation &R : Sec.Relocs) {
31 const Symbol *Sym = Obj.findSymbol(R.Target);
32 if (Sym == nullptr)
33 return make_error<StringError>("Relocation target " + R.TargetName +
34 " (" + Twine(R.Target) +
35 ") not found",
36 object_error::invalid_symbol_index);
37 R.Reloc.SymbolTableIndex = Sym->RawIndex;
38 }
39 }
40 return Error::success();
41}
42
Martin Storsjoe84a0b52018-12-19 07:24:38 +000043void 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.
Martin Storsjof51f5ea2019-01-15 09:34:55 +000049 S.Header.NumberOfRelocations = S.Relocs.size();
50 S.Header.PointerToRelocations =
51 S.Header.NumberOfRelocations > 0 ? FileSize : 0;
Martin Storsjoe84a0b52018-12-19 07:24:38 +000052 FileSize += S.Relocs.size() * sizeof(coff_relocation);
53 FileSize = alignTo(FileSize, FileAlignment);
54
55 if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
56 SizeOfInitializedData += S.Header.SizeOfRawData;
57 }
58}
59
60size_t COFFWriter::finalizeStringTable() {
61 for (auto &S : Obj.Sections)
62 if (S.Name.size() > COFF::NameSize)
63 StrTabBuilder.add(S.Name);
64
Martin Storsjo10b72962019-01-10 21:28:24 +000065 for (const auto &S : Obj.getSymbols())
Martin Storsjoe84a0b52018-12-19 07:24:38 +000066 if (S.Name.size() > COFF::NameSize)
67 StrTabBuilder.add(S.Name);
68
69 StrTabBuilder.finalize();
70
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));
75 } else {
76 strncpy(S.Header.Name, S.Name.data(), COFF::NameSize);
77 }
78 }
Martin Storsjo10b72962019-01-10 21:28:24 +000079 for (auto &S : Obj.getMutableSymbols()) {
Martin Storsjoe84a0b52018-12-19 07:24:38 +000080 if (S.Name.size() > COFF::NameSize) {
81 S.Sym.Name.Offset.Zeroes = 0;
82 S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name);
83 } else {
84 strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize);
85 }
86 }
87 return StrTabBuilder.getSize();
88}
89
90template <class SymbolTy>
91std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
Martin Storsjo10b72962019-01-10 21:28:24 +000092 size_t SymTabSize = Obj.getSymbols().size() * sizeof(SymbolTy);
93 for (const auto &S : Obj.getSymbols())
Martin Storsjoe84a0b52018-12-19 07:24:38 +000094 SymTabSize += S.AuxData.size();
95 return std::make_pair(SymTabSize, sizeof(SymbolTy));
96}
97
Martin Storsjo10b72962019-01-10 21:28:24 +000098Error COFFWriter::finalize(bool IsBigObj) {
99 if (Error E = finalizeRelocTargets())
100 return E;
101
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000102 size_t SizeOfHeaders = 0;
103 FileAlignment = 1;
104 size_t PeHeaderSize = 0;
105 if (Obj.IsPE) {
106 Obj.DosHeader.AddressOfNewExeHeader =
107 sizeof(Obj.DosHeader) + Obj.DosStub.size();
108 SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic);
109
110 FileAlignment = Obj.PeHeader.FileAlignment;
111 Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size();
112
113 PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header);
114 SizeOfHeaders +=
115 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
116 }
117 Obj.CoffFileHeader.NumberOfSections = Obj.Sections.size();
118 SizeOfHeaders +=
119 IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
120 SizeOfHeaders += sizeof(coff_section) * Obj.Sections.size();
121 SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
122
123 Obj.CoffFileHeader.SizeOfOptionalHeader =
124 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
125
126 FileSize = SizeOfHeaders;
127 SizeOfInitializedData = 0;
128
129 layoutSections();
130
131 if (Obj.IsPE) {
132 Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
133 Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
134
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);
140 }
141
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;
145 }
146
147 size_t StrTabSize = finalizeStringTable();
148 size_t SymTabSize, SymbolSize;
149 std::tie(SymTabSize, SymbolSize) = IsBigObj
150 ? finalizeSymbolTable<coff_symbol32>()
151 : finalizeSymbolTable<coff_symbol16>();
152
153 size_t PointerToSymbolTable = FileSize;
154 // StrTabSize <= 4 is the size of an empty string table, only consisting
155 // of the length field.
Martin Storsjod1cc64f2019-01-11 13:47:37 +0000156 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.
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000159 PointerToSymbolTable = 0;
Martin Storsjod1cc64f2019-01-11 13:47:37 +0000160 StrTabSize = 0;
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000161 }
162
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);
Martin Storsjo10b72962019-01-10 21:28:24 +0000168
169 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000170}
171
172void COFFWriter::writeHeaders(bool IsBigObj) {
173 uint8_t *Ptr = Buf.getBufferStart();
174 if (Obj.IsPE) {
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);
181 }
182 if (!IsBigObj) {
183 memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader));
184 Ptr += sizeof(Obj.CoffFileHeader);
185 } else {
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;
205
206 memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader));
207 Ptr += sizeof(BigObjHeader);
208 }
209 if (Obj.IsPE) {
210 if (Obj.Is64) {
211 memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader));
212 Ptr += sizeof(Obj.PeHeader);
213 } else {
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;
218
219 memcpy(Ptr, &PeHeader, sizeof(PeHeader));
220 Ptr += sizeof(PeHeader);
221 }
222 for (const auto &DD : Obj.DataDirectories) {
223 memcpy(Ptr, &DD, sizeof(DD));
224 Ptr += sizeof(DD);
225 }
226 }
227 for (const auto &S : Obj.Sections) {
228 memcpy(Ptr, &S.Header, sizeof(S.Header));
229 Ptr += sizeof(S.Header);
230 }
231}
232
233void COFFWriter::writeSections() {
234 for (const auto &S : Obj.Sections) {
235 uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
Martin Storsjo14cfa9a2018-12-20 21:35:59 +0000236 std::copy(S.Contents.begin(), S.Contents.end(), Ptr);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000237
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());
244
245 Ptr += S.Header.SizeOfRawData;
Martin Storsjo10b72962019-01-10 21:28:24 +0000246 for (const auto &R : S.Relocs) {
247 memcpy(Ptr, &R.Reloc, sizeof(R.Reloc));
248 Ptr += sizeof(R.Reloc);
249 }
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000250 }
251}
252
253template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
254 uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable;
Martin Storsjo10b72962019-01-10 21:28:24 +0000255 for (const auto &S : Obj.getSymbols()) {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000256 // Convert symbols back to the right size, from coff_symbol32.
257 copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
258 S.Sym);
259 Ptr += sizeof(SymbolTy);
Martin Storsjo14cfa9a2018-12-20 21:35:59 +0000260 std::copy(S.AuxData.begin(), S.AuxData.end(), Ptr);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000261 Ptr += S.AuxData.size();
262 }
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();
267 }
268}
269
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000270Error COFFWriter::write(bool IsBigObj) {
Martin Storsjo10b72962019-01-10 21:28:24 +0000271 if (Error E = finalize(IsBigObj))
272 return E;
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000273
274 Buf.allocate(FileSize);
275
276 writeHeaders(IsBigObj);
277 writeSections();
278 if (IsBigObj)
279 writeSymbolStringTables<coff_symbol32>();
280 else
281 writeSymbolStringTables<coff_symbol16>();
282
283 if (Obj.IsPE)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000284 if (Error E = patchDebugDirectory())
285 return E;
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000286
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000287 return Buf.commit();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000288}
289
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.
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000293Error COFFWriter::patchDebugDirectory() {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000294 if (Obj.DataDirectories.size() < DEBUG_DIRECTORY)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000295 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000296 const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
297 if (Dir->Size <= 0)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000298 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000299 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)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000305 return make_error<StringError>(
306 "Debug directory extends past end of section",
307 object_error::parse_failed);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000308
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;
312 while (Ptr < End) {
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;
318 }
319 // Debug directory found and patched, all done.
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000320 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000321 }
322 }
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000323 return make_error<StringError>("Debug directory not found",
324 object_error::parse_failed);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000325}
326
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000327Error COFFWriter::write() {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000328 bool IsBigObj = Obj.Sections.size() > MaxNumberOfSections16;
329 if (IsBigObj && Obj.IsPE)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000330 return make_error<StringError>("Too many sections for executable",
331 object_error::parse_failed);
332 return write(IsBigObj);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000333}
334
335} // end namespace coff
336} // end namespace objcopy
337} // end namespace llvm