181ad6265SDimitry Andric //===- COFFWriter.cpp -----------------------------------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric
981ad6265SDimitry Andric #include "COFFWriter.h"
1081ad6265SDimitry Andric #include "COFFObject.h"
1181ad6265SDimitry Andric #include "llvm/ADT/ArrayRef.h"
1281ad6265SDimitry Andric #include "llvm/ADT/StringRef.h"
1381ad6265SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
1481ad6265SDimitry Andric #include "llvm/Object/COFF.h"
1581ad6265SDimitry Andric #include "llvm/Support/Errc.h"
1681ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h"
1781ad6265SDimitry Andric #include <cstddef>
1881ad6265SDimitry Andric #include <cstdint>
1981ad6265SDimitry Andric
2081ad6265SDimitry Andric namespace llvm {
2181ad6265SDimitry Andric namespace objcopy {
2281ad6265SDimitry Andric namespace coff {
2381ad6265SDimitry Andric
2481ad6265SDimitry Andric using namespace object;
2581ad6265SDimitry Andric using namespace COFF;
2681ad6265SDimitry Andric
finalizeRelocTargets()2781ad6265SDimitry Andric Error COFFWriter::finalizeRelocTargets() {
2881ad6265SDimitry Andric for (Section &Sec : Obj.getMutableSections()) {
2981ad6265SDimitry Andric for (Relocation &R : Sec.Relocs) {
3081ad6265SDimitry Andric const Symbol *Sym = Obj.findSymbol(R.Target);
3181ad6265SDimitry Andric if (Sym == nullptr)
3281ad6265SDimitry Andric return createStringError(object_error::invalid_symbol_index,
3381ad6265SDimitry Andric "relocation target '%s' (%zu) not found",
3481ad6265SDimitry Andric R.TargetName.str().c_str(), R.Target);
3581ad6265SDimitry Andric R.Reloc.SymbolTableIndex = Sym->RawIndex;
3681ad6265SDimitry Andric }
3781ad6265SDimitry Andric }
3881ad6265SDimitry Andric return Error::success();
3981ad6265SDimitry Andric }
4081ad6265SDimitry Andric
finalizeSymbolContents()4181ad6265SDimitry Andric Error COFFWriter::finalizeSymbolContents() {
4281ad6265SDimitry Andric for (Symbol &Sym : Obj.getMutableSymbols()) {
4381ad6265SDimitry Andric if (Sym.TargetSectionId <= 0) {
4481ad6265SDimitry Andric // Undefined, or a special kind of symbol. These negative values
4581ad6265SDimitry Andric // are stored in the SectionNumber field which is unsigned.
4681ad6265SDimitry Andric Sym.Sym.SectionNumber = static_cast<uint32_t>(Sym.TargetSectionId);
4781ad6265SDimitry Andric } else {
4881ad6265SDimitry Andric const Section *Sec = Obj.findSection(Sym.TargetSectionId);
4981ad6265SDimitry Andric if (Sec == nullptr)
5081ad6265SDimitry Andric return createStringError(object_error::invalid_symbol_index,
5181ad6265SDimitry Andric "symbol '%s' points to a removed section",
5281ad6265SDimitry Andric Sym.Name.str().c_str());
5381ad6265SDimitry Andric Sym.Sym.SectionNumber = Sec->Index;
5481ad6265SDimitry Andric
5581ad6265SDimitry Andric if (Sym.Sym.NumberOfAuxSymbols == 1 &&
5681ad6265SDimitry Andric Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) {
5781ad6265SDimitry Andric coff_aux_section_definition *SD =
5881ad6265SDimitry Andric reinterpret_cast<coff_aux_section_definition *>(
5981ad6265SDimitry Andric Sym.AuxData[0].Opaque);
6081ad6265SDimitry Andric uint32_t SDSectionNumber;
6181ad6265SDimitry Andric if (Sym.AssociativeComdatTargetSectionId == 0) {
6281ad6265SDimitry Andric // Not a comdat associative section; just set the Number field to
6381ad6265SDimitry Andric // the number of the section itself.
6481ad6265SDimitry Andric SDSectionNumber = Sec->Index;
6581ad6265SDimitry Andric } else {
6681ad6265SDimitry Andric Sec = Obj.findSection(Sym.AssociativeComdatTargetSectionId);
6781ad6265SDimitry Andric if (Sec == nullptr)
6881ad6265SDimitry Andric return createStringError(
6981ad6265SDimitry Andric object_error::invalid_symbol_index,
7081ad6265SDimitry Andric "symbol '%s' is associative to a removed section",
7181ad6265SDimitry Andric Sym.Name.str().c_str());
7281ad6265SDimitry Andric SDSectionNumber = Sec->Index;
7381ad6265SDimitry Andric }
7481ad6265SDimitry Andric // Update the section definition with the new section number.
7581ad6265SDimitry Andric SD->NumberLowPart = static_cast<uint16_t>(SDSectionNumber);
7681ad6265SDimitry Andric SD->NumberHighPart = static_cast<uint16_t>(SDSectionNumber >> 16);
7781ad6265SDimitry Andric }
7881ad6265SDimitry Andric }
7981ad6265SDimitry Andric // Check that we actually have got AuxData to match the weak symbol target
8081ad6265SDimitry Andric // we want to set. Only >= 1 would be required, but only == 1 makes sense.
8181ad6265SDimitry Andric if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) {
8281ad6265SDimitry Andric coff_aux_weak_external *WE =
8381ad6265SDimitry Andric reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData[0].Opaque);
8481ad6265SDimitry Andric const Symbol *Target = Obj.findSymbol(*Sym.WeakTargetSymbolId);
8581ad6265SDimitry Andric if (Target == nullptr)
8681ad6265SDimitry Andric return createStringError(object_error::invalid_symbol_index,
8781ad6265SDimitry Andric "symbol '%s' is missing its weak target",
8881ad6265SDimitry Andric Sym.Name.str().c_str());
8981ad6265SDimitry Andric WE->TagIndex = Target->RawIndex;
9081ad6265SDimitry Andric }
9181ad6265SDimitry Andric }
9281ad6265SDimitry Andric return Error::success();
9381ad6265SDimitry Andric }
9481ad6265SDimitry Andric
layoutSections()9581ad6265SDimitry Andric void COFFWriter::layoutSections() {
9681ad6265SDimitry Andric for (auto &S : Obj.getMutableSections()) {
9781ad6265SDimitry Andric if (S.Header.SizeOfRawData > 0)
9881ad6265SDimitry Andric S.Header.PointerToRawData = FileSize;
99*bdd1243dSDimitry Andric else
100*bdd1243dSDimitry Andric S.Header.PointerToRawData = 0;
10181ad6265SDimitry Andric FileSize += S.Header.SizeOfRawData; // For executables, this is already
10281ad6265SDimitry Andric // aligned to FileAlignment.
10381ad6265SDimitry Andric if (S.Relocs.size() >= 0xffff) {
10481ad6265SDimitry Andric S.Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
10581ad6265SDimitry Andric S.Header.NumberOfRelocations = 0xffff;
10681ad6265SDimitry Andric S.Header.PointerToRelocations = FileSize;
10781ad6265SDimitry Andric FileSize += sizeof(coff_relocation);
10881ad6265SDimitry Andric } else {
10981ad6265SDimitry Andric S.Header.NumberOfRelocations = S.Relocs.size();
11081ad6265SDimitry Andric S.Header.PointerToRelocations = S.Relocs.size() ? FileSize : 0;
11181ad6265SDimitry Andric }
11281ad6265SDimitry Andric
11381ad6265SDimitry Andric FileSize += S.Relocs.size() * sizeof(coff_relocation);
11481ad6265SDimitry Andric FileSize = alignTo(FileSize, FileAlignment);
11581ad6265SDimitry Andric
11681ad6265SDimitry Andric if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
11781ad6265SDimitry Andric SizeOfInitializedData += S.Header.SizeOfRawData;
11881ad6265SDimitry Andric }
11981ad6265SDimitry Andric }
12081ad6265SDimitry Andric
finalizeStringTable()12181ad6265SDimitry Andric Expected<size_t> COFFWriter::finalizeStringTable() {
12281ad6265SDimitry Andric for (const auto &S : Obj.getSections())
12381ad6265SDimitry Andric if (S.Name.size() > COFF::NameSize)
12481ad6265SDimitry Andric StrTabBuilder.add(S.Name);
12581ad6265SDimitry Andric
12681ad6265SDimitry Andric for (const auto &S : Obj.getSymbols())
12781ad6265SDimitry Andric if (S.Name.size() > COFF::NameSize)
12881ad6265SDimitry Andric StrTabBuilder.add(S.Name);
12981ad6265SDimitry Andric
13081ad6265SDimitry Andric StrTabBuilder.finalize();
13181ad6265SDimitry Andric
13281ad6265SDimitry Andric for (auto &S : Obj.getMutableSections()) {
13381ad6265SDimitry Andric memset(S.Header.Name, 0, sizeof(S.Header.Name));
13481ad6265SDimitry Andric if (S.Name.size() <= COFF::NameSize) {
13581ad6265SDimitry Andric // Short names can go in the field directly.
13681ad6265SDimitry Andric memcpy(S.Header.Name, S.Name.data(), S.Name.size());
13781ad6265SDimitry Andric } else {
13881ad6265SDimitry Andric // Offset of the section name in the string table.
13981ad6265SDimitry Andric size_t Offset = StrTabBuilder.getOffset(S.Name);
14081ad6265SDimitry Andric if (!COFF::encodeSectionName(S.Header.Name, Offset))
14181ad6265SDimitry Andric return createStringError(object_error::invalid_section_index,
14281ad6265SDimitry Andric "COFF string table is greater than 64GB, "
14381ad6265SDimitry Andric "unable to encode section name offset");
14481ad6265SDimitry Andric }
14581ad6265SDimitry Andric }
14681ad6265SDimitry Andric for (auto &S : Obj.getMutableSymbols()) {
14781ad6265SDimitry Andric if (S.Name.size() > COFF::NameSize) {
14881ad6265SDimitry Andric S.Sym.Name.Offset.Zeroes = 0;
14981ad6265SDimitry Andric S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name);
15081ad6265SDimitry Andric } else {
15181ad6265SDimitry Andric strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize);
15281ad6265SDimitry Andric }
15381ad6265SDimitry Andric }
15481ad6265SDimitry Andric return StrTabBuilder.getSize();
15581ad6265SDimitry Andric }
15681ad6265SDimitry Andric
15781ad6265SDimitry Andric template <class SymbolTy>
finalizeSymbolTable()15881ad6265SDimitry Andric std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
15981ad6265SDimitry Andric size_t RawSymIndex = 0;
16081ad6265SDimitry Andric for (auto &S : Obj.getMutableSymbols()) {
16181ad6265SDimitry Andric // Symbols normally have NumberOfAuxSymbols set correctly all the time.
16281ad6265SDimitry Andric // For file symbols, we need to know the output file's symbol size to be
16381ad6265SDimitry Andric // able to calculate the number of slots it occupies.
16481ad6265SDimitry Andric if (!S.AuxFile.empty())
16581ad6265SDimitry Andric S.Sym.NumberOfAuxSymbols =
16681ad6265SDimitry Andric alignTo(S.AuxFile.size(), sizeof(SymbolTy)) / sizeof(SymbolTy);
16781ad6265SDimitry Andric S.RawIndex = RawSymIndex;
16881ad6265SDimitry Andric RawSymIndex += 1 + S.Sym.NumberOfAuxSymbols;
16981ad6265SDimitry Andric }
17081ad6265SDimitry Andric return std::make_pair(RawSymIndex * sizeof(SymbolTy), sizeof(SymbolTy));
17181ad6265SDimitry Andric }
17281ad6265SDimitry Andric
finalize(bool IsBigObj)17381ad6265SDimitry Andric Error COFFWriter::finalize(bool IsBigObj) {
17481ad6265SDimitry Andric size_t SymTabSize, SymbolSize;
17581ad6265SDimitry Andric std::tie(SymTabSize, SymbolSize) = IsBigObj
17681ad6265SDimitry Andric ? finalizeSymbolTable<coff_symbol32>()
17781ad6265SDimitry Andric : finalizeSymbolTable<coff_symbol16>();
17881ad6265SDimitry Andric
17981ad6265SDimitry Andric if (Error E = finalizeRelocTargets())
18081ad6265SDimitry Andric return E;
18181ad6265SDimitry Andric if (Error E = finalizeSymbolContents())
18281ad6265SDimitry Andric return E;
18381ad6265SDimitry Andric
18481ad6265SDimitry Andric size_t SizeOfHeaders = 0;
18581ad6265SDimitry Andric FileAlignment = 1;
18681ad6265SDimitry Andric size_t PeHeaderSize = 0;
18781ad6265SDimitry Andric if (Obj.IsPE) {
18881ad6265SDimitry Andric Obj.DosHeader.AddressOfNewExeHeader =
18981ad6265SDimitry Andric sizeof(Obj.DosHeader) + Obj.DosStub.size();
19081ad6265SDimitry Andric SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic);
19181ad6265SDimitry Andric
19281ad6265SDimitry Andric FileAlignment = Obj.PeHeader.FileAlignment;
19381ad6265SDimitry Andric Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size();
19481ad6265SDimitry Andric
19581ad6265SDimitry Andric PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header);
19681ad6265SDimitry Andric SizeOfHeaders +=
19781ad6265SDimitry Andric PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
19881ad6265SDimitry Andric }
19981ad6265SDimitry Andric Obj.CoffFileHeader.NumberOfSections = Obj.getSections().size();
20081ad6265SDimitry Andric SizeOfHeaders +=
20181ad6265SDimitry Andric IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
20281ad6265SDimitry Andric SizeOfHeaders += sizeof(coff_section) * Obj.getSections().size();
20381ad6265SDimitry Andric SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
20481ad6265SDimitry Andric
20581ad6265SDimitry Andric Obj.CoffFileHeader.SizeOfOptionalHeader =
20681ad6265SDimitry Andric PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
20781ad6265SDimitry Andric
20881ad6265SDimitry Andric FileSize = SizeOfHeaders;
20981ad6265SDimitry Andric SizeOfInitializedData = 0;
21081ad6265SDimitry Andric
21181ad6265SDimitry Andric layoutSections();
21281ad6265SDimitry Andric
21381ad6265SDimitry Andric if (Obj.IsPE) {
21481ad6265SDimitry Andric Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
21581ad6265SDimitry Andric Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
21681ad6265SDimitry Andric
21781ad6265SDimitry Andric if (!Obj.getSections().empty()) {
21881ad6265SDimitry Andric const Section &S = Obj.getSections().back();
21981ad6265SDimitry Andric Obj.PeHeader.SizeOfImage =
22081ad6265SDimitry Andric alignTo(S.Header.VirtualAddress + S.Header.VirtualSize,
22181ad6265SDimitry Andric Obj.PeHeader.SectionAlignment);
22281ad6265SDimitry Andric }
22381ad6265SDimitry Andric
22481ad6265SDimitry Andric // If the PE header had a checksum, clear it, since it isn't valid
22581ad6265SDimitry Andric // any longer. (We don't calculate a new one.)
22681ad6265SDimitry Andric Obj.PeHeader.CheckSum = 0;
22781ad6265SDimitry Andric }
22881ad6265SDimitry Andric
22981ad6265SDimitry Andric Expected<size_t> StrTabSizeOrErr = finalizeStringTable();
23081ad6265SDimitry Andric if (!StrTabSizeOrErr)
23181ad6265SDimitry Andric return StrTabSizeOrErr.takeError();
23281ad6265SDimitry Andric
23381ad6265SDimitry Andric size_t StrTabSize = *StrTabSizeOrErr;
23481ad6265SDimitry Andric
23581ad6265SDimitry Andric size_t PointerToSymbolTable = FileSize;
23681ad6265SDimitry Andric // StrTabSize <= 4 is the size of an empty string table, only consisting
23781ad6265SDimitry Andric // of the length field.
23881ad6265SDimitry Andric if (SymTabSize == 0 && StrTabSize <= 4 && Obj.IsPE) {
23981ad6265SDimitry Andric // For executables, don't point to the symbol table and skip writing
24081ad6265SDimitry Andric // the length field, if both the symbol and string tables are empty.
24181ad6265SDimitry Andric PointerToSymbolTable = 0;
24281ad6265SDimitry Andric StrTabSize = 0;
24381ad6265SDimitry Andric }
24481ad6265SDimitry Andric
24581ad6265SDimitry Andric size_t NumRawSymbols = SymTabSize / SymbolSize;
24681ad6265SDimitry Andric Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable;
24781ad6265SDimitry Andric Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols;
24881ad6265SDimitry Andric FileSize += SymTabSize + StrTabSize;
24981ad6265SDimitry Andric FileSize = alignTo(FileSize, FileAlignment);
25081ad6265SDimitry Andric
25181ad6265SDimitry Andric return Error::success();
25281ad6265SDimitry Andric }
25381ad6265SDimitry Andric
writeHeaders(bool IsBigObj)25481ad6265SDimitry Andric void COFFWriter::writeHeaders(bool IsBigObj) {
25581ad6265SDimitry Andric uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
25681ad6265SDimitry Andric if (Obj.IsPE) {
25781ad6265SDimitry Andric memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader));
25881ad6265SDimitry Andric Ptr += sizeof(Obj.DosHeader);
25981ad6265SDimitry Andric memcpy(Ptr, Obj.DosStub.data(), Obj.DosStub.size());
26081ad6265SDimitry Andric Ptr += Obj.DosStub.size();
26181ad6265SDimitry Andric memcpy(Ptr, PEMagic, sizeof(PEMagic));
26281ad6265SDimitry Andric Ptr += sizeof(PEMagic);
26381ad6265SDimitry Andric }
26481ad6265SDimitry Andric if (!IsBigObj) {
26581ad6265SDimitry Andric memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader));
26681ad6265SDimitry Andric Ptr += sizeof(Obj.CoffFileHeader);
26781ad6265SDimitry Andric } else {
26881ad6265SDimitry Andric // Generate a coff_bigobj_file_header, filling it in with the values
26981ad6265SDimitry Andric // from Obj.CoffFileHeader. All extra fields that don't exist in
27081ad6265SDimitry Andric // coff_file_header can be set to hardcoded values.
27181ad6265SDimitry Andric coff_bigobj_file_header BigObjHeader;
27281ad6265SDimitry Andric BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN;
27381ad6265SDimitry Andric BigObjHeader.Sig2 = 0xffff;
27481ad6265SDimitry Andric BigObjHeader.Version = BigObjHeader::MinBigObjectVersion;
27581ad6265SDimitry Andric BigObjHeader.Machine = Obj.CoffFileHeader.Machine;
27681ad6265SDimitry Andric BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp;
27781ad6265SDimitry Andric memcpy(BigObjHeader.UUID, BigObjMagic, sizeof(BigObjMagic));
27881ad6265SDimitry Andric BigObjHeader.unused1 = 0;
27981ad6265SDimitry Andric BigObjHeader.unused2 = 0;
28081ad6265SDimitry Andric BigObjHeader.unused3 = 0;
28181ad6265SDimitry Andric BigObjHeader.unused4 = 0;
28281ad6265SDimitry Andric // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
28381ad6265SDimitry Andric // get the original one instead.
28481ad6265SDimitry Andric BigObjHeader.NumberOfSections = Obj.getSections().size();
28581ad6265SDimitry Andric BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable;
28681ad6265SDimitry Andric BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols;
28781ad6265SDimitry Andric
28881ad6265SDimitry Andric memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader));
28981ad6265SDimitry Andric Ptr += sizeof(BigObjHeader);
29081ad6265SDimitry Andric }
29181ad6265SDimitry Andric if (Obj.IsPE) {
29281ad6265SDimitry Andric if (Obj.Is64) {
29381ad6265SDimitry Andric memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader));
29481ad6265SDimitry Andric Ptr += sizeof(Obj.PeHeader);
29581ad6265SDimitry Andric } else {
29681ad6265SDimitry Andric pe32_header PeHeader;
29781ad6265SDimitry Andric copyPeHeader(PeHeader, Obj.PeHeader);
29881ad6265SDimitry Andric // The pe32plus_header (stored in Object) lacks the BaseOfData field.
29981ad6265SDimitry Andric PeHeader.BaseOfData = Obj.BaseOfData;
30081ad6265SDimitry Andric
30181ad6265SDimitry Andric memcpy(Ptr, &PeHeader, sizeof(PeHeader));
30281ad6265SDimitry Andric Ptr += sizeof(PeHeader);
30381ad6265SDimitry Andric }
30481ad6265SDimitry Andric for (const auto &DD : Obj.DataDirectories) {
30581ad6265SDimitry Andric memcpy(Ptr, &DD, sizeof(DD));
30681ad6265SDimitry Andric Ptr += sizeof(DD);
30781ad6265SDimitry Andric }
30881ad6265SDimitry Andric }
30981ad6265SDimitry Andric for (const auto &S : Obj.getSections()) {
31081ad6265SDimitry Andric memcpy(Ptr, &S.Header, sizeof(S.Header));
31181ad6265SDimitry Andric Ptr += sizeof(S.Header);
31281ad6265SDimitry Andric }
31381ad6265SDimitry Andric }
31481ad6265SDimitry Andric
writeSections()31581ad6265SDimitry Andric void COFFWriter::writeSections() {
31681ad6265SDimitry Andric for (const auto &S : Obj.getSections()) {
31781ad6265SDimitry Andric uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
31881ad6265SDimitry Andric S.Header.PointerToRawData;
31981ad6265SDimitry Andric ArrayRef<uint8_t> Contents = S.getContents();
32081ad6265SDimitry Andric std::copy(Contents.begin(), Contents.end(), Ptr);
32181ad6265SDimitry Andric
32281ad6265SDimitry Andric // For executable sections, pad the remainder of the raw data size with
32381ad6265SDimitry Andric // 0xcc, which is int3 on x86.
32481ad6265SDimitry Andric if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
32581ad6265SDimitry Andric S.Header.SizeOfRawData > Contents.size())
32681ad6265SDimitry Andric memset(Ptr + Contents.size(), 0xcc,
32781ad6265SDimitry Andric S.Header.SizeOfRawData - Contents.size());
32881ad6265SDimitry Andric
32981ad6265SDimitry Andric Ptr += S.Header.SizeOfRawData;
33081ad6265SDimitry Andric
33181ad6265SDimitry Andric if (S.Relocs.size() >= 0xffff) {
33281ad6265SDimitry Andric object::coff_relocation R;
33381ad6265SDimitry Andric R.VirtualAddress = S.Relocs.size() + 1;
33481ad6265SDimitry Andric R.SymbolTableIndex = 0;
33581ad6265SDimitry Andric R.Type = 0;
33681ad6265SDimitry Andric memcpy(Ptr, &R, sizeof(R));
33781ad6265SDimitry Andric Ptr += sizeof(R);
33881ad6265SDimitry Andric }
33981ad6265SDimitry Andric for (const auto &R : S.Relocs) {
34081ad6265SDimitry Andric memcpy(Ptr, &R.Reloc, sizeof(R.Reloc));
34181ad6265SDimitry Andric Ptr += sizeof(R.Reloc);
34281ad6265SDimitry Andric }
34381ad6265SDimitry Andric }
34481ad6265SDimitry Andric }
34581ad6265SDimitry Andric
writeSymbolStringTables()34681ad6265SDimitry Andric template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
34781ad6265SDimitry Andric uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
34881ad6265SDimitry Andric Obj.CoffFileHeader.PointerToSymbolTable;
34981ad6265SDimitry Andric for (const auto &S : Obj.getSymbols()) {
35081ad6265SDimitry Andric // Convert symbols back to the right size, from coff_symbol32.
35181ad6265SDimitry Andric copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
35281ad6265SDimitry Andric S.Sym);
35381ad6265SDimitry Andric Ptr += sizeof(SymbolTy);
35481ad6265SDimitry Andric if (!S.AuxFile.empty()) {
35581ad6265SDimitry Andric // For file symbols, just write the string into the aux symbol slots,
35681ad6265SDimitry Andric // assuming that the unwritten parts are initialized to zero in the memory
35781ad6265SDimitry Andric // mapped file.
35881ad6265SDimitry Andric std::copy(S.AuxFile.begin(), S.AuxFile.end(), Ptr);
35981ad6265SDimitry Andric Ptr += S.Sym.NumberOfAuxSymbols * sizeof(SymbolTy);
36081ad6265SDimitry Andric } else {
36181ad6265SDimitry Andric // For other auxillary symbols, write their opaque payload into one symbol
36281ad6265SDimitry Andric // table slot each. For big object files, the symbols are larger than the
36381ad6265SDimitry Andric // opaque auxillary symbol struct and we leave padding at the end of each
36481ad6265SDimitry Andric // entry.
36581ad6265SDimitry Andric for (const AuxSymbol &AuxSym : S.AuxData) {
36681ad6265SDimitry Andric ArrayRef<uint8_t> Ref = AuxSym.getRef();
36781ad6265SDimitry Andric std::copy(Ref.begin(), Ref.end(), Ptr);
36881ad6265SDimitry Andric Ptr += sizeof(SymbolTy);
36981ad6265SDimitry Andric }
37081ad6265SDimitry Andric }
37181ad6265SDimitry Andric }
37281ad6265SDimitry Andric if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) {
37381ad6265SDimitry Andric // Always write a string table in object files, even an empty one.
37481ad6265SDimitry Andric StrTabBuilder.write(Ptr);
37581ad6265SDimitry Andric Ptr += StrTabBuilder.getSize();
37681ad6265SDimitry Andric }
37781ad6265SDimitry Andric }
37881ad6265SDimitry Andric
write(bool IsBigObj)37981ad6265SDimitry Andric Error COFFWriter::write(bool IsBigObj) {
38081ad6265SDimitry Andric if (Error E = finalize(IsBigObj))
38181ad6265SDimitry Andric return E;
38281ad6265SDimitry Andric
38381ad6265SDimitry Andric Buf = WritableMemoryBuffer::getNewMemBuffer(FileSize);
38481ad6265SDimitry Andric if (!Buf)
38581ad6265SDimitry Andric return createStringError(llvm::errc::not_enough_memory,
38681ad6265SDimitry Andric "failed to allocate memory buffer of " +
38781ad6265SDimitry Andric Twine::utohexstr(FileSize) + " bytes.");
38881ad6265SDimitry Andric
38981ad6265SDimitry Andric writeHeaders(IsBigObj);
39081ad6265SDimitry Andric writeSections();
39181ad6265SDimitry Andric if (IsBigObj)
39281ad6265SDimitry Andric writeSymbolStringTables<coff_symbol32>();
39381ad6265SDimitry Andric else
39481ad6265SDimitry Andric writeSymbolStringTables<coff_symbol16>();
39581ad6265SDimitry Andric
39681ad6265SDimitry Andric if (Obj.IsPE)
39781ad6265SDimitry Andric if (Error E = patchDebugDirectory())
39881ad6265SDimitry Andric return E;
39981ad6265SDimitry Andric
40081ad6265SDimitry Andric // TODO: Implement direct writing to the output stream (without intermediate
40181ad6265SDimitry Andric // memory buffer Buf).
40281ad6265SDimitry Andric Out.write(Buf->getBufferStart(), Buf->getBufferSize());
40381ad6265SDimitry Andric return Error::success();
40481ad6265SDimitry Andric }
40581ad6265SDimitry Andric
virtualAddressToFileAddress(uint32_t RVA)40681ad6265SDimitry Andric Expected<uint32_t> COFFWriter::virtualAddressToFileAddress(uint32_t RVA) {
40781ad6265SDimitry Andric for (const auto &S : Obj.getSections()) {
40881ad6265SDimitry Andric if (RVA >= S.Header.VirtualAddress &&
40981ad6265SDimitry Andric RVA < S.Header.VirtualAddress + S.Header.SizeOfRawData)
41081ad6265SDimitry Andric return S.Header.PointerToRawData + RVA - S.Header.VirtualAddress;
41181ad6265SDimitry Andric }
41281ad6265SDimitry Andric return createStringError(object_error::parse_failed,
41381ad6265SDimitry Andric "debug directory payload not found");
41481ad6265SDimitry Andric }
41581ad6265SDimitry Andric
41681ad6265SDimitry Andric // Locate which sections contain the debug directories, iterate over all
41781ad6265SDimitry Andric // the debug_directory structs in there, and set the PointerToRawData field
41881ad6265SDimitry Andric // in all of them, according to their new physical location in the file.
patchDebugDirectory()41981ad6265SDimitry Andric Error COFFWriter::patchDebugDirectory() {
42081ad6265SDimitry Andric if (Obj.DataDirectories.size() <= DEBUG_DIRECTORY)
42181ad6265SDimitry Andric return Error::success();
42281ad6265SDimitry Andric const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
42381ad6265SDimitry Andric if (Dir->Size <= 0)
42481ad6265SDimitry Andric return Error::success();
42581ad6265SDimitry Andric for (const auto &S : Obj.getSections()) {
42681ad6265SDimitry Andric if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress &&
42781ad6265SDimitry Andric Dir->RelativeVirtualAddress <
42881ad6265SDimitry Andric S.Header.VirtualAddress + S.Header.SizeOfRawData) {
42981ad6265SDimitry Andric if (Dir->RelativeVirtualAddress + Dir->Size >
43081ad6265SDimitry Andric S.Header.VirtualAddress + S.Header.SizeOfRawData)
43181ad6265SDimitry Andric return createStringError(object_error::parse_failed,
43281ad6265SDimitry Andric "debug directory extends past end of section");
43381ad6265SDimitry Andric
43481ad6265SDimitry Andric size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
43581ad6265SDimitry Andric uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
43681ad6265SDimitry Andric S.Header.PointerToRawData + Offset;
43781ad6265SDimitry Andric uint8_t *End = Ptr + Dir->Size;
43881ad6265SDimitry Andric while (Ptr < End) {
43981ad6265SDimitry Andric debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr);
44081ad6265SDimitry Andric if (Debug->PointerToRawData) {
44181ad6265SDimitry Andric if (Expected<uint32_t> FilePosOrErr =
44281ad6265SDimitry Andric virtualAddressToFileAddress(Debug->AddressOfRawData))
44381ad6265SDimitry Andric Debug->PointerToRawData = *FilePosOrErr;
44481ad6265SDimitry Andric else
44581ad6265SDimitry Andric return FilePosOrErr.takeError();
44681ad6265SDimitry Andric }
44781ad6265SDimitry Andric Ptr += sizeof(debug_directory);
44881ad6265SDimitry Andric Offset += sizeof(debug_directory);
44981ad6265SDimitry Andric }
45081ad6265SDimitry Andric // Debug directory found and patched, all done.
45181ad6265SDimitry Andric return Error::success();
45281ad6265SDimitry Andric }
45381ad6265SDimitry Andric }
45481ad6265SDimitry Andric return createStringError(object_error::parse_failed,
45581ad6265SDimitry Andric "debug directory not found");
45681ad6265SDimitry Andric }
45781ad6265SDimitry Andric
write()45881ad6265SDimitry Andric Error COFFWriter::write() {
45981ad6265SDimitry Andric bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16;
46081ad6265SDimitry Andric if (IsBigObj && Obj.IsPE)
46181ad6265SDimitry Andric return createStringError(object_error::parse_failed,
46281ad6265SDimitry Andric "too many sections for executable");
46381ad6265SDimitry Andric return write(IsBigObj);
46481ad6265SDimitry Andric }
46581ad6265SDimitry Andric
46681ad6265SDimitry Andric } // end namespace coff
46781ad6265SDimitry Andric } // end namespace objcopy
46881ad6265SDimitry Andric } // end namespace llvm
469