[llvm-objcopy] [COFF] Implement --strip-all[-gnu] for symbols
[llvm-core.git] / tools / llvm-objcopy / COFF / Writer.cpp
blob385d43b1bae561507a912a03e2af9982c404ed45
1 //===- 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 //===----------------------------------------------------------------------===//
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>
21 namespace llvm {
22 namespace objcopy {
23 namespace coff {
25 using namespace object;
26 using namespace COFF;
28 Error 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;
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));
75 } else {
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);
83 } else {
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())
100 return E;
102 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);
110 FileAlignment = Obj.PeHeader.FileAlignment;
111 Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size();
113 PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header);
114 SizeOfHeaders +=
115 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
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);
123 Obj.CoffFileHeader.SizeOfOptionalHeader =
124 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
126 FileSize = SizeOfHeaders;
127 SizeOfInitializedData = 0;
129 layoutSections();
131 if (Obj.IsPE) {
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;
160 StrTabSize = 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();
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);
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;
206 memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader));
207 Ptr += sizeof(BigObjHeader);
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;
219 memcpy(Ptr, &PeHeader, sizeof(PeHeader));
220 Ptr += sizeof(PeHeader);
222 for (const auto &DD : Obj.DataDirectories) {
223 memcpy(Ptr, &DD, sizeof(DD));
224 Ptr += 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),
258 S.Sym);
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))
272 return E;
274 Buf.allocate(FileSize);
276 writeHeaders(IsBigObj);
277 writeSections();
278 if (IsBigObj)
279 writeSymbolStringTables<coff_symbol32>();
280 else
281 writeSymbolStringTables<coff_symbol16>();
283 if (Obj.IsPE)
284 if (Error E = patchDebugDirectory())
285 return E;
287 return Buf.commit();
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];
297 if (Dir->Size <= 0)
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;
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;
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