llvm.org GIT mirror llvm / 237544b
obj2yaml, yaml2obj: Add support for COFF executables In support of serializing executables, obj2yaml now records the virtual address and size of sections. It also serializes whatever we strictly need from the PE header, it expects that it can reconstitute everything else via inference. yaml2obj can reconstitute a fully linked executable. In order to get executables correctly serialized/deserialized, other bugs were fixed as a circumstance. We now properly respect file and section alignments. We also avoid writing out string tables unless they are strictly necessary. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221975 91177308-0d34-0410-b5e6-96231b3b80d8 David Majnemer 4 years ago
7 changed file(s) with 396 addition(s) and 55 deletion(s). Raw diff Collapse all Expand all
109109 support::ulittle32_t SizeOfHeaders;
110110 support::ulittle32_t CheckSum;
111111 support::ulittle16_t Subsystem;
112 // FIXME: This should be DllCharacteristics.
112113 support::ulittle16_t DLLCharacteristics;
113114 support::ulittle32_t SizeOfStackReserve;
114115 support::ulittle32_t SizeOfStackCommit;
115116 support::ulittle32_t SizeOfHeapReserve;
116117 support::ulittle32_t SizeOfHeapCommit;
117118 support::ulittle32_t LoaderFlags;
119 // FIXME: This should be NumberOfRvaAndSizes.
118120 support::ulittle32_t NumberOfRvaAndSize;
119121 };
120122
2929 SectionCharacteristics b) {
3030 uint32_t Ret = static_cast(a) | static_cast(b);
3131 return static_cast(Ret);
32 }
33
34 inline DLLCharacteristics operator|(DLLCharacteristics a,
35 DLLCharacteristics b) {
36 uint16_t Ret = static_cast(a) | static_cast(b);
37 return static_cast(Ret);
3238 }
3339 }
3440
6874 Symbol();
6975 };
7076
77 struct PEHeader {
78 COFF::PE32Header Header;
79 Optional DataDirectories[COFF::NUM_DATA_DIRECTORIES];
80 };
81
7182 struct Object {
83 Optional OptionalHeader;
7284 COFF::header Header;
7385 std::vector
Sections;
7486 std::vector Symbols;
130142 };
131143
132144 template <>
145 struct ScalarEnumerationTraits {
146 static void enumeration(IO &IO, COFF::WindowsSubsystem &Value);
147 };
148
149 template <>
133150 struct ScalarBitSetTraits {
134151 static void bitset(IO &IO, COFF::Characteristics &Value);
135152 };
140157 };
141158
142159 template <>
160 struct ScalarBitSetTraits {
161 static void bitset(IO &IO, COFF::DLLCharacteristics &Value);
162 };
163
164 template <>
143165 struct MappingTraits {
144166 static void mapping(IO &IO, COFFYAML::Relocation &Rel);
145167 };
146168
147169 template <>
170 struct MappingTraits {
171 static void mapping(IO &IO, COFFYAML::PEHeader &PH);
172 };
173
174 template <>
175 struct MappingTraits {
176 static void mapping(IO &IO, COFF::DataDirectory &DD);
177 };
178
179 template <>
148180 struct MappingTraits {
149181 static void mapping(IO &IO, COFF::header &H);
150182 };
514514 uint32_t SizeOfHeaders;
515515 uint32_t CheckSum;
516516 uint16_t Subsystem;
517 // FIXME: This should be DllCharacteristics to match the COFF spec.
517518 uint16_t DLLCharacteristics;
518519 uint32_t SizeOfStackReserve;
519520 uint32_t SizeOfStackCommit;
520521 uint32_t SizeOfHeapReserve;
521522 uint32_t SizeOfHeapCommit;
522523 uint32_t LoaderFlags;
524 // FIXME: This should be NumberOfRvaAndSizes to match the COFF spec.
523525 uint32_t NumberOfRvaAndSize;
524526 };
525527
543545 BOUND_IMPORT,
544546 IAT,
545547 DELAY_IMPORT_DESCRIPTOR,
546 CLR_RUNTIME_HEADER
547 };
548
549 enum WindowsSubsystem {
548 CLR_RUNTIME_HEADER,
549
550 NUM_DATA_DIRECTORIES
551 };
552
553 enum WindowsSubsystem : uint16_t {
550554 IMAGE_SUBSYSTEM_UNKNOWN = 0, ///< An unknown subsystem.
551555 IMAGE_SUBSYSTEM_NATIVE = 1, ///< Device drivers and native Windows processes
552556 IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, ///< The Windows GUI subsystem.
565569 IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16 ///< A BCD application.
566570 };
567571
568 enum DLLCharacteristics {
572 enum DLLCharacteristics : uint16_t {
569573 /// ASLR with 64 bit address space.
570574 IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020,
571575 /// DLL can be relocated at load time.
459459 // Find string table. The first four byte of the string table contains the
460460 // total size of the string table, including the size field itself. If the
461461 // string table is empty, the value of the first four byte would be 4.
462 const uint8_t *StringTableAddr =
463 base() + getPointerToSymbolTable() +
464 getNumberOfSymbols() * getSymbolTableEntrySize();
462 uint32_t StringTableOffset = getPointerToSymbolTable() +
463 getNumberOfSymbols() * getSymbolTableEntrySize();
464 const uint8_t *StringTableAddr = base() + StringTableOffset;
465465 const ulittle32_t *StringTableSizePtr;
466466 if (std::error_code EC = getObject(StringTableSizePtr, Data, StringTableAddr))
467467 return EC;
825825 COFFObjectFile::getDataDirectory(uint32_t Index,
826826 const data_directory *&Res) const {
827827 // Error if if there's no data directory or the index is out of range.
828 if (!DataDirectory)
828 if (!DataDirectory) {
829 Res = nullptr;
829830 return object_error::parse_failed;
831 }
830832 assert(PE32Header || PE32PlusHeader);
831833 uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize
832834 : PE32PlusHeader->NumberOfRvaAndSize;
833 if (Index > NumEnt)
835 if (Index >= NumEnt) {
836 Res = nullptr;
834837 return object_error::parse_failed;
838 }
835839 Res = &DataDirectory[Index];
836840 return object_error::success;
837841 }
167167 ECase(IMAGE_REL_AMD64_PAIR);
168168 ECase(IMAGE_REL_AMD64_SSPAN32);
169169 }
170
171 void ScalarEnumerationTraits::enumeration(
172 IO &IO, COFF::WindowsSubsystem &Value) {
173 ECase(IMAGE_SUBSYSTEM_UNKNOWN);
174 ECase(IMAGE_SUBSYSTEM_NATIVE);
175 ECase(IMAGE_SUBSYSTEM_WINDOWS_GUI);
176 ECase(IMAGE_SUBSYSTEM_WINDOWS_CUI);
177 ECase(IMAGE_SUBSYSTEM_OS2_CUI);
178 ECase(IMAGE_SUBSYSTEM_POSIX_CUI);
179 ECase(IMAGE_SUBSYSTEM_NATIVE_WINDOWS);
180 ECase(IMAGE_SUBSYSTEM_WINDOWS_CE_GUI);
181 ECase(IMAGE_SUBSYSTEM_EFI_APPLICATION);
182 ECase(IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER);
183 ECase(IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER);
184 ECase(IMAGE_SUBSYSTEM_EFI_ROM);
185 ECase(IMAGE_SUBSYSTEM_XBOX);
186 ECase(IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION);
187 }
170188 #undef ECase
171189
172190 #define BCase(X) IO.bitSetCase(Value, #X, COFF::X);
213231 BCase(IMAGE_SCN_MEM_READ);
214232 BCase(IMAGE_SCN_MEM_WRITE);
215233 }
234
235 void ScalarBitSetTraits::bitset(
236 IO &IO, COFF::DLLCharacteristics &Value) {
237 BCase(IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA);
238 BCase(IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE);
239 BCase(IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY);
240 BCase(IMAGE_DLL_CHARACTERISTICS_NX_COMPAT);
241 BCase(IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION);
242 BCase(IMAGE_DLL_CHARACTERISTICS_NO_SEH);
243 BCase(IMAGE_DLL_CHARACTERISTICS_NO_BIND);
244 BCase(IMAGE_DLL_CHARACTERISTICS_APPCONTAINER);
245 BCase(IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER);
246 BCase(IMAGE_DLL_CHARACTERISTICS_GUARD_CF);
247 BCase(IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE);
248 }
216249 #undef BCase
217250
218251 namespace {
282315 NType(IO &, uint16_t T) : Type(RelocType(T)) {}
283316 uint16_t denormalize(IO &) { return Type; }
284317 RelocType Type;
318 };
319
320 struct NWindowsSubsystem {
321 NWindowsSubsystem(IO &) : Subsystem(COFF::WindowsSubsystem(0)) {}
322 NWindowsSubsystem(IO &, uint16_t C) : Subsystem(COFF::WindowsSubsystem(C)) {}
323 uint16_t denormalize(IO &) { return Subsystem; }
324
325 COFF::WindowsSubsystem Subsystem;
326 };
327
328 struct NDLLCharacteristics {
329 NDLLCharacteristics(IO &) : Characteristics(COFF::DLLCharacteristics(0)) {}
330 NDLLCharacteristics(IO &, uint16_t C)
331 : Characteristics(COFF::DLLCharacteristics(C)) {}
332 uint16_t denormalize(IO &) { return Characteristics; }
333
334 COFF::DLLCharacteristics Characteristics;
285335 };
286336
287337 }
305355 }
306356 }
307357
358 void MappingTraits::mapping(IO &IO,
359 COFF::DataDirectory &DD) {
360 IO.mapRequired("RelativeVirtualAddress", DD.RelativeVirtualAddress);
361 IO.mapRequired("Size", DD.Size);
362 }
363
364 void MappingTraits::mapping(IO &IO,
365 COFFYAML::PEHeader &PH) {
366 MappingNormalization NWS(IO,
367 PH.Header.Subsystem);
368 MappingNormalization NDC(
369 IO, PH.Header.DLLCharacteristics);
370
371 IO.mapRequired("AddressOfEntryPoint", PH.Header.AddressOfEntryPoint);
372 IO.mapRequired("ImageBase", PH.Header.ImageBase);
373 IO.mapRequired("SectionAlignment", PH.Header.SectionAlignment);
374 IO.mapRequired("FileAlignment", PH.Header.FileAlignment);
375 IO.mapRequired("MajorOperatingSystemVersion",
376 PH.Header.MajorOperatingSystemVersion);
377 IO.mapRequired("MinorOperatingSystemVersion",
378 PH.Header.MinorOperatingSystemVersion);
379 IO.mapRequired("MajorImageVersion", PH.Header.MajorImageVersion);
380 IO.mapRequired("MinorImageVersion", PH.Header.MinorImageVersion);
381 IO.mapRequired("MajorSubsystemVersion", PH.Header.MajorSubsystemVersion);
382 IO.mapRequired("MinorSubsystemVersion", PH.Header.MinorSubsystemVersion);
383 IO.mapRequired("Subsystem", NWS->Subsystem);
384 IO.mapRequired("DLLCharacteristics", NDC->Characteristics);
385 IO.mapRequired("SizeOfStackReserve", PH.Header.SizeOfStackReserve);
386 IO.mapRequired("SizeOfStackCommit", PH.Header.SizeOfStackCommit);
387 IO.mapRequired("SizeOfHeapReserve", PH.Header.SizeOfHeapReserve);
388 IO.mapRequired("SizeOfHeapCommit", PH.Header.SizeOfHeapCommit);
389
390 IO.mapOptional("ExportTable", PH.DataDirectories[COFF::EXPORT_TABLE]);
391 IO.mapOptional("ImportTable", PH.DataDirectories[COFF::IMPORT_TABLE]);
392 IO.mapOptional("ResourceTable", PH.DataDirectories[COFF::RESOURCE_TABLE]);
393 IO.mapOptional("ExceptionTable", PH.DataDirectories[COFF::EXCEPTION_TABLE]);
394 IO.mapOptional("CertificateTable", PH.DataDirectories[COFF::CERTIFICATE_TABLE]);
395 IO.mapOptional("BaseRelocationTable",
396 PH.DataDirectories[COFF::BASE_RELOCATION_TABLE]);
397 IO.mapOptional("Debug", PH.DataDirectories[COFF::DEBUG]);
398 IO.mapOptional("Architecture", PH.DataDirectories[COFF::ARCHITECTURE]);
399 IO.mapOptional("GlobalPtr", PH.DataDirectories[COFF::GLOBAL_PTR]);
400 IO.mapOptional("TlsTable", PH.DataDirectories[COFF::TLS_TABLE]);
401 IO.mapOptional("LoadConfigTable",
402 PH.DataDirectories[COFF::LOAD_CONFIG_TABLE]);
403 IO.mapOptional("BoundImport", PH.DataDirectories[COFF::BOUND_IMPORT]);
404 IO.mapOptional("IAT", PH.DataDirectories[COFF::IAT]);
405 IO.mapOptional("DelayImportDescriptor",
406 PH.DataDirectories[COFF::DELAY_IMPORT_DESCRIPTOR]);
407 IO.mapOptional("ClrRuntimeHeader",
408 PH.DataDirectories[COFF::CLR_RUNTIME_HEADER]);
409 }
410
308411 void MappingTraits::mapping(IO &IO, COFF::header &H) {
309412 MappingNormalization NM(IO, H.Machine);
310413 MappingNormalization NC(IO,
379482 IO, Sec.Header.Characteristics);
380483 IO.mapRequired("Name", Sec.Name);
381484 IO.mapRequired("Characteristics", NC->Characteristics);
485 IO.mapOptional("VirtualAddress", Sec.Header.VirtualAddress, 0U);
486 IO.mapOptional("VirtualSize", Sec.Header.VirtualSize, 0U);
382487 IO.mapOptional("Alignment", Sec.Alignment);
383488 IO.mapRequired("SectionData", Sec.SectionData);
384489 IO.mapOptional("Relocations", Sec.Relocations);
385490 }
386491
387492 void MappingTraits::mapping(IO &IO, COFFYAML::Object &Obj) {
493 IO.mapOptional("OptionalHeader", Obj.OptionalHeader);
388494 IO.mapRequired("header", Obj.Header);
389495 IO.mapRequired("sections", Obj.Sections);
390496 IO.mapRequired("symbols", Obj.Symbols);
1919 class COFFDumper {
2020 const object::COFFObjectFile &Obj;
2121 COFFYAML::Object YAMLObj;
22 template
23 void dumpOptionalHeader(T OptionalHeader);
2224 void dumpHeader();
2325 void dumpSections(unsigned numSections);
2426 void dumpSymbols(unsigned numSymbols);
3133 }
3234
3335 COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) {
36 const object::pe32_header *PE32Header = nullptr;
37 Obj.getPE32Header(PE32Header);
38 if (PE32Header) {
39 dumpOptionalHeader(PE32Header);
40 } else {
41 const object::pe32plus_header *PE32PlusHeader = nullptr;
42 Obj.getPE32PlusHeader(PE32PlusHeader);
43 if (PE32PlusHeader) {
44 dumpOptionalHeader(PE32PlusHeader);
45 }
46 }
3447 dumpHeader();
3548 dumpSections(Obj.getNumberOfSections());
3649 dumpSymbols(Obj.getNumberOfSymbols());
3750 }
3851
52 template void COFFDumper::dumpOptionalHeader(T OptionalHeader) {
53 YAMLObj.OptionalHeader = COFFYAML::PEHeader();
54 YAMLObj.OptionalHeader->Header.AddressOfEntryPoint =
55 OptionalHeader->AddressOfEntryPoint;
56 YAMLObj.OptionalHeader->Header.AddressOfEntryPoint =
57 OptionalHeader->AddressOfEntryPoint;
58 YAMLObj.OptionalHeader->Header.ImageBase = OptionalHeader->ImageBase;
59 YAMLObj.OptionalHeader->Header.SectionAlignment =
60 OptionalHeader->SectionAlignment;
61 YAMLObj.OptionalHeader->Header.FileAlignment = OptionalHeader->FileAlignment;
62 YAMLObj.OptionalHeader->Header.MajorOperatingSystemVersion =
63 OptionalHeader->MajorOperatingSystemVersion;
64 YAMLObj.OptionalHeader->Header.MinorOperatingSystemVersion =
65 OptionalHeader->MinorOperatingSystemVersion;
66 YAMLObj.OptionalHeader->Header.MajorImageVersion =
67 OptionalHeader->MajorImageVersion;
68 YAMLObj.OptionalHeader->Header.MinorImageVersion =
69 OptionalHeader->MinorImageVersion;
70 YAMLObj.OptionalHeader->Header.MajorSubsystemVersion =
71 OptionalHeader->MajorSubsystemVersion;
72 YAMLObj.OptionalHeader->Header.MinorSubsystemVersion =
73 OptionalHeader->MinorSubsystemVersion;
74 YAMLObj.OptionalHeader->Header.Subsystem = OptionalHeader->Subsystem;
75 YAMLObj.OptionalHeader->Header.DLLCharacteristics =
76 OptionalHeader->DLLCharacteristics;
77 YAMLObj.OptionalHeader->Header.SizeOfStackReserve =
78 OptionalHeader->SizeOfStackReserve;
79 YAMLObj.OptionalHeader->Header.SizeOfStackCommit =
80 OptionalHeader->SizeOfStackCommit;
81 YAMLObj.OptionalHeader->Header.SizeOfHeapReserve =
82 OptionalHeader->SizeOfHeapReserve;
83 YAMLObj.OptionalHeader->Header.SizeOfHeapCommit =
84 OptionalHeader->SizeOfHeapCommit;
85 unsigned I = 0;
86 for (auto &DestDD : YAMLObj.OptionalHeader->DataDirectories) {
87 const object::data_directory *DD;
88 if (Obj.getDataDirectory(I++, DD))
89 continue;
90 DestDD = COFF::DataDirectory();
91 DestDD->RelativeVirtualAddress = DD->RelativeVirtualAddress;
92 DestDD->Size = DD->Size;
93 }
94 }
95
3996 void COFFDumper::dumpHeader() {
4097 YAMLObj.Header.Machine = Obj.getMachine();
4198 YAMLObj.Header.Characteristics = Obj.getCharacteristics();
4299 }
43100
44101 void COFFDumper::dumpSections(unsigned NumSections) {
45 std::vector &Sections = YAMLObj.Sections;
46 for (const auto &Section : Obj.sections()) {
47 const object::coff_section *Sect = Obj.getCOFFSection(Section);
48 COFFYAML::Section Sec;
49 Section.getName(Sec.Name);
50 Sec.Header.Characteristics = Sect->Characteristics;
51 Sec.Alignment = Section.getAlignment();
102 std::vector &YAMLSections = YAMLObj.Sections;
103 for (const auto &ObjSection : Obj.sections()) {
104 const object::coff_section *COFFSection = Obj.getCOFFSection(ObjSection);
105 COFFYAML::Section NewYAMLSection;
106 ObjSection.getName(NewYAMLSection.Name);
107 NewYAMLSection.Header.Characteristics = COFFSection->Characteristics;
108 NewYAMLSection.Header.VirtualAddress = ObjSection.getAddress();
109 NewYAMLSection.Header.VirtualSize = COFFSection->VirtualSize;
110 NewYAMLSection.Alignment = ObjSection.getAlignment();
52111
53112 ArrayRef sectionData;
54 if (!Section.isBSS())
55 Obj.getSectionContents(Sect, sectionData);
56 Sec.SectionData = yaml::BinaryRef(sectionData);
113 if (!ObjSection.isBSS())
114 Obj.getSectionContents(COFFSection, sectionData);
115 NewYAMLSection.SectionData = yaml::BinaryRef(sectionData);
57116
58117 std::vector Relocations;
59 for (const auto &Reloc : Section.relocations()) {
118 for (const auto &Reloc : ObjSection.relocations()) {
60119 const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc);
61120 COFFYAML::Relocation Rel;
62121 object::symbol_iterator Sym = Reloc.getSymbol();
65124 Rel.Type = reloc->Type;
66125 Relocations.push_back(Rel);
67126 }
68 Sec.Relocations = Relocations;
69 Sections.push_back(Sec);
127 NewYAMLSection.Relocations = Relocations;
128 YAMLSections.push_back(NewYAMLSection);
70129 }
71130 }
72131
1818 #include "llvm/ADT/StringMap.h"
1919 #include "llvm/ADT/StringSwitch.h"
2020 #include "llvm/Object/COFFYAML.h"
21 #include "llvm/Object/COFF.h"
2122 #include "llvm/Support/Endian.h"
2223 #include "llvm/Support/MemoryBuffer.h"
2324 #include "llvm/Support/SourceMgr.h"
2930 /// This parses a yaml stream that represents a COFF object file.
3031 /// See docs/yaml2obj for the yaml scheema.
3132 struct COFFParser {
32 COFFParser(COFFYAML::Object &Obj) : Obj(Obj) {
33 COFFParser(COFFYAML::Object &Obj)
34 : Obj(Obj), SectionTableStart(0), SectionTableSize(0) {
3335 // A COFF string table always starts with a 4 byte size field. Offsets into
3436 // it include this size, so allocate it now.
3537 StringTable.append(4, char(0));
3840 bool useBigObj() const {
3941 return static_cast(Obj.Sections.size()) >
4042 COFF::MaxNumberOfSections16;
43 }
44
45 bool isPE() const { return Obj.OptionalHeader.hasValue(); }
46 bool is64Bit() const {
47 return Obj.Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64;
48 }
49
50 uint32_t getFileAlignment() const {
51 return Obj.OptionalHeader->Header.FileAlignment;
4152 }
4253
4354 unsigned getHeaderSize() const {
123134
124135 StringMap StringTableMap;
125136 std::string StringTable;
137 uint32_t SectionTableStart;
138 uint32_t SectionTableSize;
126139 };
140
141 // Take a CP and assign addresses and sizes to everything. Returns false if the
142 // layout is not valid to do.
143 static bool layoutOptionalHeader(COFFParser &CP) {
144 if (!CP.isPE())
145 return true;
146 CP.Obj.Header.SizeOfOptionalHeader =
147 (CP.is64Bit() ? sizeof(object::pe32plus_header)
148 : sizeof(object::pe32_header)) +
149 (sizeof(object::data_directory) * (COFF::NUM_DATA_DIRECTORIES + 1));
150 return true;
151 }
127152
128153 // Take a CP and assign addresses and sizes to everything. Returns false if the
129154 // layout is not valid to do.
130155 static bool layoutCOFF(COFFParser &CP) {
131 uint32_t SectionTableStart = 0;
132 uint32_t SectionTableSize = 0;
133
134156 // The section table starts immediately after the header, including the
135157 // optional header.
136 SectionTableStart = CP.getHeaderSize() + CP.Obj.Header.SizeOfOptionalHeader;
137 SectionTableSize = COFF::SectionSize * CP.Obj.Sections.size();
138
139 uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize;
158 CP.SectionTableStart =
159 CP.getHeaderSize() + CP.Obj.Header.SizeOfOptionalHeader;
160 CP.SectionTableSize = COFF::SectionSize * CP.Obj.Sections.size();
161
162 uint32_t CurrentSectionDataOffset =
163 CP.SectionTableStart + CP.SectionTableSize;
140164
141165 // Assign each section data address consecutively.
142 for (std::vector::iterator i = CP.Obj.Sections.begin(),
143 e = CP.Obj.Sections.end();
144 i != e; ++i) {
145 if (i->SectionData.binary_size() > 0) {
146 i->Header.SizeOfRawData = i->SectionData.binary_size();
147 i->Header.PointerToRawData = CurrentSectionDataOffset;
148 CurrentSectionDataOffset += i->Header.SizeOfRawData;
149 if (!i->Relocations.empty()) {
150 i->Header.PointerToRelocations = CurrentSectionDataOffset;
151 i->Header.NumberOfRelocations = i->Relocations.size();
152 CurrentSectionDataOffset += i->Header.NumberOfRelocations *
153 COFF::RelocationSize;
166 for (COFFYAML::Section &S : CP.Obj.Sections) {
167 if (S.SectionData.binary_size() > 0) {
168 CurrentSectionDataOffset = RoundUpToAlignment(
169 CurrentSectionDataOffset, CP.isPE() ? CP.getFileAlignment() : 4);
170 S.Header.SizeOfRawData = S.SectionData.binary_size();
171 if (CP.isPE())
172 S.Header.SizeOfRawData =
173 RoundUpToAlignment(S.Header.SizeOfRawData, CP.getFileAlignment());
174 S.Header.PointerToRawData = CurrentSectionDataOffset;
175 CurrentSectionDataOffset += S.Header.SizeOfRawData;
176 if (!S.Relocations.empty()) {
177 S.Header.PointerToRelocations = CurrentSectionDataOffset;
178 S.Header.NumberOfRelocations = S.Relocations.size();
179 CurrentSectionDataOffset +=
180 S.Header.NumberOfRelocations * COFF::RelocationSize;
154181 }
155 // TODO: Handle alignment.
156182 } else {
157 i->Header.SizeOfRawData = 0;
158 i->Header.PointerToRawData = 0;
183 S.Header.SizeOfRawData = 0;
184 S.Header.PointerToRawData = 0;
159185 }
160186 }
161187
187213 // Store all the allocated start addresses in the header.
188214 CP.Obj.Header.NumberOfSections = CP.Obj.Sections.size();
189215 CP.Obj.Header.NumberOfSymbols = NumberOfSymbols;
190 CP.Obj.Header.PointerToSymbolTable = SymbolTableStart;
216 if (NumberOfSymbols > 0 || CP.StringTable.size() > 4)
217 CP.Obj.Header.PointerToSymbolTable = SymbolTableStart;
218 else
219 CP.Obj.Header.PointerToSymbolTable = 0;
191220
192221 *reinterpret_cast(&CP.StringTable[0])
193222 = CP.StringTable.size();
250279 return NZI;
251280 }
252281
253 bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
282 template
283 static void initializeOptionalHeader(COFFParser &CP, uint16_t Magic, T Header) {
284 memset(Header, 0, sizeof(*Header));
285 Header->Magic = Magic;
286 Header->SectionAlignment = CP.Obj.OptionalHeader->Header.SectionAlignment;
287 uint32_t SizeOfCode = 0, SizeOfInitializedData = 0,
288 SizeOfUninitializedData = 0;
289 uint32_t SizeOfHeaders = RoundUpToAlignment(
290 CP.SectionTableStart + CP.SectionTableSize, Header->SectionAlignment);
291 uint32_t SizeOfImage = SizeOfHeaders;
292 for (const COFFYAML::Section &S : CP.Obj.Sections) {
293 if (S.Header.Characteristics & COFF::IMAGE_SCN_CNT_CODE)
294 SizeOfCode += S.Header.SizeOfRawData;
295 if (S.Header.Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
296 SizeOfInitializedData += S.Header.SizeOfRawData;
297 if (S.Header.Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
298 SizeOfUninitializedData += S.Header.SizeOfRawData;
299 if (S.Name.equals(".text"))
300 Header->BaseOfCode = S.Header.VirtualAddress; // RVA
301 if (S.Header.VirtualAddress)
302 SizeOfImage +=
303 RoundUpToAlignment(S.Header.VirtualSize, Header->SectionAlignment);
304 }
305 Header->SizeOfCode = SizeOfCode;
306 Header->SizeOfInitializedData = SizeOfInitializedData;
307 Header->SizeOfUninitializedData = SizeOfUninitializedData;
308 Header->AddressOfEntryPoint =
309 CP.Obj.OptionalHeader->Header.AddressOfEntryPoint; // RVA
310 Header->ImageBase = CP.Obj.OptionalHeader->Header.ImageBase;
311 Header->FileAlignment = CP.Obj.OptionalHeader->Header.FileAlignment;
312 Header->MajorOperatingSystemVersion =
313 CP.Obj.OptionalHeader->Header.MajorOperatingSystemVersion;
314 Header->MinorOperatingSystemVersion =
315 CP.Obj.OptionalHeader->Header.MinorOperatingSystemVersion;
316 Header->MajorImageVersion =
317 CP.Obj.OptionalHeader->Header.MajorImageVersion;
318 Header->MinorImageVersion =
319 CP.Obj.OptionalHeader->Header.MinorImageVersion;
320 Header->MajorSubsystemVersion =
321 CP.Obj.OptionalHeader->Header.MajorSubsystemVersion;
322 Header->MinorSubsystemVersion =
323 CP.Obj.OptionalHeader->Header.MinorSubsystemVersion;
324 Header->SizeOfImage = SizeOfImage;
325 Header->SizeOfHeaders = SizeOfHeaders;
326 Header->Subsystem = CP.Obj.OptionalHeader->Header.Subsystem;
327 Header->DLLCharacteristics = CP.Obj.OptionalHeader->Header.DLLCharacteristics;
328 Header->SizeOfStackReserve = CP.Obj.OptionalHeader->Header.SizeOfStackReserve;
329 Header->SizeOfStackCommit = CP.Obj.OptionalHeader->Header.SizeOfStackCommit;
330 Header->SizeOfHeapReserve = CP.Obj.OptionalHeader->Header.SizeOfHeapReserve;
331 Header->SizeOfHeapCommit = CP.Obj.OptionalHeader->Header.SizeOfHeapCommit;
332 Header->NumberOfRvaAndSize = COFF::NUM_DATA_DIRECTORIES + 1;
333 }
334
335 static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
336 if (CP.isPE()) {
337 // PE files start with a DOS stub.
338 object::dos_header DH;
339 memset(&DH, 0, sizeof(DH));
340
341 // DOS EXEs start with "MZ" magic.
342 DH.Magic[0] = 'M';
343 DH.Magic[1] = 'Z';
344 // Initializing the AddressOfRelocationTable is strictly optional but
345 // mollifies certain tools which expect it to have a value greater than
346 // 0x40.
347 DH.AddressOfRelocationTable = sizeof(DH);
348 // This is the address of the PE signature.
349 DH.AddressOfNewExeHeader = 128;
350
351 // Write out our DOS stub.
352 OS.write(reinterpret_cast(&DH), sizeof(DH));
353 // Write padding until we reach the position of where our PE signature
354 // should live.
355 OS << num_zeros(DH.AddressOfNewExeHeader - sizeof(DH));
356 // Write out the PE signature.
357 OS.write(COFF::PEMagic, sizeof(COFF::PEMagic));
358 }
254359 if (CP.useBigObj()) {
255360 OS << binary_le(static_cast(COFF::IMAGE_FILE_MACHINE_UNKNOWN))
256361 << binary_le(static_cast(0xffff))
274379 << binary_le(CP.Obj.Header.SizeOfOptionalHeader)
275380 << binary_le(CP.Obj.Header.Characteristics);
276381 }
382 if (CP.isPE()) {
383 if (CP.is64Bit()) {
384 object::pe32plus_header PEH;
385 initializeOptionalHeader(CP, COFF::PE32Header::PE32_PLUS, &PEH);
386 OS.write(reinterpret_cast(&PEH), sizeof(PEH));
387 } else {
388 object::pe32_header PEH;
389 initializeOptionalHeader(CP, COFF::PE32Header::PE32, &PEH);
390 OS.write(reinterpret_cast(&PEH), sizeof(PEH));
391 }
392 for (const Optional &DD :
393 CP.Obj.OptionalHeader->DataDirectories) {
394 if (!DD.hasValue()) {
395 OS << zeros(uint32_t(0));
396 OS << zeros(uint32_t(0));
397 } else {
398 OS << binary_le(DD->RelativeVirtualAddress);
399 OS << binary_le(DD->Size);
400 }
401 }
402 OS << zeros(uint32_t(0));
403 OS << zeros(uint32_t(0));
404 }
277405
278406 // Output section table.
279407 for (std::vector::iterator i = CP.Obj.Sections.begin(),
301429 }
302430
303431 // Output section data.
304 for (std::vector::iterator i = CP.Obj.Sections.begin(),
305 e = CP.Obj.Sections.end();
306 i != e; ++i) {
307 i->SectionData.writeAsBinary(OS);
308 for (unsigned I2 = 0, E2 = i->Relocations.size(); I2 != E2; ++I2) {
309 const COFFYAML::Relocation &R = i->Relocations[I2];
432 for (const COFFYAML::Section &S : CP.Obj.Sections) {
433 if (!S.Header.SizeOfRawData)
434 continue;
435 OS << num_zeros(S.Header.PointerToRawData - OS.tell());
436 S.SectionData.writeAsBinary(OS);
437 OS << num_zeros(S.Header.SizeOfRawData - S.SectionData.binary_size());
438 for (const COFFYAML::Relocation &R : S.Relocations) {
310439 uint32_t SymbolTableIndex = SymbolTableIndexMap[R.SymbolName];
311440 OS << binary_le(R.VirtualAddress)
312441 << binary_le(SymbolTableIndex)
376505 }
377506
378507 // Output string table.
379 OS.write(&CP.StringTable[0], CP.StringTable.size());
508 if (CP.Obj.Header.PointerToSymbolTable)
509 OS.write(&CP.StringTable[0], CP.StringTable.size());
380510 return true;
381511 }
382512
394524 return 1;
395525 }
396526
527 if (!layoutOptionalHeader(CP)) {
528 errs() << "yaml2obj: Failed to layout optional header for COFF file!\n";
529 return 1;
530 }
397531 if (!layoutCOFF(CP)) {
398532 errs() << "yaml2obj: Failed to layout COFF file!\n";
399533 return 1;