blob: 388c62cbdc67e1a09bdcfe6756a4df21e654ab08 [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
28Writer::~Writer() {}
29
30void COFFWriter::layoutSections() {
31 for (auto &S : Obj.Sections) {
32 if (S.Header.SizeOfRawData > 0)
33 S.Header.PointerToRawData = FileSize;
34 FileSize += S.Header.SizeOfRawData; // For executables, this is already
35 // aligned to FileAlignment.
36 if (S.Header.NumberOfRelocations > 0)
37 S.Header.PointerToRelocations = FileSize;
38 FileSize += S.Relocs.size() * sizeof(coff_relocation);
39 FileSize = alignTo(FileSize, FileAlignment);
40
41 if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
42 SizeOfInitializedData += S.Header.SizeOfRawData;
43 }
44}
45
46size_t COFFWriter::finalizeStringTable() {
47 for (auto &S : Obj.Sections)
48 if (S.Name.size() > COFF::NameSize)
49 StrTabBuilder.add(S.Name);
50
51 for (const auto &S : Obj.Symbols)
52 if (S.Name.size() > COFF::NameSize)
53 StrTabBuilder.add(S.Name);
54
55 StrTabBuilder.finalize();
56
57 for (auto &S : Obj.Sections) {
58 if (S.Name.size() > COFF::NameSize) {
59 snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d",
60 (int)StrTabBuilder.getOffset(S.Name));
61 } else {
62 strncpy(S.Header.Name, S.Name.data(), COFF::NameSize);
63 }
64 }
65 for (auto &S : Obj.Symbols) {
66 if (S.Name.size() > COFF::NameSize) {
67 S.Sym.Name.Offset.Zeroes = 0;
68 S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name);
69 } else {
70 strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize);
71 }
72 }
73 return StrTabBuilder.getSize();
74}
75
76template <class SymbolTy>
77std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
78 size_t SymTabSize = Obj.Symbols.size() * sizeof(SymbolTy);
79 for (const auto &S : Obj.Symbols)
80 SymTabSize += S.AuxData.size();
81 return std::make_pair(SymTabSize, sizeof(SymbolTy));
82}
83
84void COFFWriter::finalize(bool IsBigObj) {
85 size_t SizeOfHeaders = 0;
86 FileAlignment = 1;
87 size_t PeHeaderSize = 0;
88 if (Obj.IsPE) {
89 Obj.DosHeader.AddressOfNewExeHeader =
90 sizeof(Obj.DosHeader) + Obj.DosStub.size();
91 SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic);
92
93 FileAlignment = Obj.PeHeader.FileAlignment;
94 Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size();
95
96 PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header);
97 SizeOfHeaders +=
98 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
99 }
100 Obj.CoffFileHeader.NumberOfSections = Obj.Sections.size();
101 SizeOfHeaders +=
102 IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
103 SizeOfHeaders += sizeof(coff_section) * Obj.Sections.size();
104 SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
105
106 Obj.CoffFileHeader.SizeOfOptionalHeader =
107 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
108
109 FileSize = SizeOfHeaders;
110 SizeOfInitializedData = 0;
111
112 layoutSections();
113
114 if (Obj.IsPE) {
115 Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
116 Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
117
118 if (!Obj.Sections.empty()) {
119 const Section &S = Obj.Sections.back();
120 Obj.PeHeader.SizeOfImage =
121 alignTo(S.Header.VirtualAddress + S.Header.VirtualSize,
122 Obj.PeHeader.SectionAlignment);
123 }
124
125 // If the PE header had a checksum, clear it, since it isn't valid
126 // any longer. (We don't calculate a new one.)
127 Obj.PeHeader.CheckSum = 0;
128 }
129
130 size_t StrTabSize = finalizeStringTable();
131 size_t SymTabSize, SymbolSize;
132 std::tie(SymTabSize, SymbolSize) = IsBigObj
133 ? finalizeSymbolTable<coff_symbol32>()
134 : finalizeSymbolTable<coff_symbol16>();
135
136 size_t PointerToSymbolTable = FileSize;
137 // StrTabSize <= 4 is the size of an empty string table, only consisting
138 // of the length field.
139 if (SymTabSize == 0 && StrTabSize <= 4) {
140 // Don't point to the symbol table if empty.
141 PointerToSymbolTable = 0;
142 // For executables, skip the length field of an empty string table.
143 if (Obj.IsPE)
144 StrTabSize = 0;
145 }
146
147 size_t NumRawSymbols = SymTabSize / SymbolSize;
148 Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable;
149 Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols;
150 FileSize += SymTabSize + StrTabSize;
151 FileSize = alignTo(FileSize, FileAlignment);
152}
153
154void COFFWriter::writeHeaders(bool IsBigObj) {
155 uint8_t *Ptr = Buf.getBufferStart();
156 if (Obj.IsPE) {
157 memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader));
158 Ptr += sizeof(Obj.DosHeader);
159 memcpy(Ptr, Obj.DosStub.data(), Obj.DosStub.size());
160 Ptr += Obj.DosStub.size();
161 memcpy(Ptr, PEMagic, sizeof(PEMagic));
162 Ptr += sizeof(PEMagic);
163 }
164 if (!IsBigObj) {
165 memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader));
166 Ptr += sizeof(Obj.CoffFileHeader);
167 } else {
168 // Generate a coff_bigobj_file_header, filling it in with the values
169 // from Obj.CoffFileHeader. All extra fields that don't exist in
170 // coff_file_header can be set to hardcoded values.
171 coff_bigobj_file_header BigObjHeader;
172 BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN;
173 BigObjHeader.Sig2 = 0xffff;
174 BigObjHeader.Version = BigObjHeader::MinBigObjectVersion;
175 BigObjHeader.Machine = Obj.CoffFileHeader.Machine;
176 BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp;
177 memcpy(BigObjHeader.UUID, BigObjMagic, sizeof(BigObjMagic));
178 BigObjHeader.unused1 = 0;
179 BigObjHeader.unused2 = 0;
180 BigObjHeader.unused3 = 0;
181 BigObjHeader.unused4 = 0;
182 // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
183 // get the original one instead.
184 BigObjHeader.NumberOfSections = Obj.Sections.size();
185 BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable;
186 BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols;
187
188 memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader));
189 Ptr += sizeof(BigObjHeader);
190 }
191 if (Obj.IsPE) {
192 if (Obj.Is64) {
193 memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader));
194 Ptr += sizeof(Obj.PeHeader);
195 } else {
196 pe32_header PeHeader;
197 copyPeHeader(PeHeader, Obj.PeHeader);
198 // The pe32plus_header (stored in Object) lacks the BaseOfData field.
199 PeHeader.BaseOfData = Obj.BaseOfData;
200
201 memcpy(Ptr, &PeHeader, sizeof(PeHeader));
202 Ptr += sizeof(PeHeader);
203 }
204 for (const auto &DD : Obj.DataDirectories) {
205 memcpy(Ptr, &DD, sizeof(DD));
206 Ptr += sizeof(DD);
207 }
208 }
209 for (const auto &S : Obj.Sections) {
210 memcpy(Ptr, &S.Header, sizeof(S.Header));
211 Ptr += sizeof(S.Header);
212 }
213}
214
215void COFFWriter::writeSections() {
216 for (const auto &S : Obj.Sections) {
217 uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
Martin Storsjo14cfa9a2018-12-20 21:35:59 +0000218 std::copy(S.Contents.begin(), S.Contents.end(), Ptr);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000219
220 // For executable sections, pad the remainder of the raw data size with
221 // 0xcc, which is int3 on x86.
222 if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
223 S.Header.SizeOfRawData > S.Contents.size())
224 memset(Ptr + S.Contents.size(), 0xcc,
225 S.Header.SizeOfRawData - S.Contents.size());
226
227 Ptr += S.Header.SizeOfRawData;
Martin Storsjo14cfa9a2018-12-20 21:35:59 +0000228 std::copy(S.Relocs.begin(), S.Relocs.end(),
229 reinterpret_cast<coff_relocation *>(Ptr));
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000230 }
231}
232
233template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
234 uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable;
235 for (const auto &S : Obj.Symbols) {
236 // Convert symbols back to the right size, from coff_symbol32.
237 copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
238 S.Sym);
239 Ptr += sizeof(SymbolTy);
Martin Storsjo14cfa9a2018-12-20 21:35:59 +0000240 std::copy(S.AuxData.begin(), S.AuxData.end(), Ptr);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000241 Ptr += S.AuxData.size();
242 }
243 if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) {
244 // Always write a string table in object files, even an empty one.
245 StrTabBuilder.write(Ptr);
246 Ptr += StrTabBuilder.getSize();
247 }
248}
249
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000250Error COFFWriter::write(bool IsBigObj) {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000251 finalize(IsBigObj);
252
253 Buf.allocate(FileSize);
254
255 writeHeaders(IsBigObj);
256 writeSections();
257 if (IsBigObj)
258 writeSymbolStringTables<coff_symbol32>();
259 else
260 writeSymbolStringTables<coff_symbol16>();
261
262 if (Obj.IsPE)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000263 if (Error E = patchDebugDirectory())
264 return E;
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000265
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000266 return Buf.commit();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000267}
268
269// Locate which sections contain the debug directories, iterate over all
270// the debug_directory structs in there, and set the PointerToRawData field
271// in all of them, according to their new physical location in the file.
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000272Error COFFWriter::patchDebugDirectory() {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000273 if (Obj.DataDirectories.size() < DEBUG_DIRECTORY)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000274 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000275 const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
276 if (Dir->Size <= 0)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000277 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000278 for (const auto &S : Obj.Sections) {
279 if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress &&
280 Dir->RelativeVirtualAddress <
281 S.Header.VirtualAddress + S.Header.SizeOfRawData) {
282 if (Dir->RelativeVirtualAddress + Dir->Size >
283 S.Header.VirtualAddress + S.Header.SizeOfRawData)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000284 return make_error<StringError>(
285 "Debug directory extends past end of section",
286 object_error::parse_failed);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000287
288 size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
289 uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset;
290 uint8_t *End = Ptr + Dir->Size;
291 while (Ptr < End) {
292 debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr);
293 Debug->PointerToRawData =
294 S.Header.PointerToRawData + Offset + sizeof(debug_directory);
295 Ptr += sizeof(debug_directory) + Debug->SizeOfData;
296 Offset += sizeof(debug_directory) + Debug->SizeOfData;
297 }
298 // Debug directory found and patched, all done.
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000299 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000300 }
301 }
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000302 return make_error<StringError>("Debug directory not found",
303 object_error::parse_failed);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000304}
305
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000306Error COFFWriter::write() {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000307 bool IsBigObj = Obj.Sections.size() > MaxNumberOfSections16;
308 if (IsBigObj && Obj.IsPE)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000309 return make_error<StringError>("Too many sections for executable",
310 object_error::parse_failed);
311 return write(IsBigObj);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000312}
313
314} // end namespace coff
315} // end namespace objcopy
316} // end namespace llvm