diff options
| author | Rui Ueyama <ruiu@google.com> | 2013-11-19 22:12:26 +0000 |
|---|---|---|
| committer | Rui Ueyama <ruiu@google.com> | 2013-11-19 22:12:26 +0000 |
| commit | 4eb61120b5569e3ff2c580d536e1e31a1b9753a7 (patch) | |
| tree | fc53bed219c9c144afcbdb37b8cf417199e23dd1 | |
| parent | c0df47dfedade527a97361c9d2c7c92cb95932e2 (diff) | |
| download | bcm5719-llvm-4eb61120b5569e3ff2c580d536e1e31a1b9753a7.tar.gz bcm5719-llvm-4eb61120b5569e3ff2c580d536e1e31a1b9753a7.zip | |
Do not inline large member functions.
This should improve code readability as the class definitions are now
more readable than before.
llvm-svn: 195159
| -rw-r--r-- | lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp | 1047 |
1 files changed, 553 insertions, 494 deletions
diff --git a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp index af864d4ee55..ebd6470fe05 100644 --- a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp @@ -129,105 +129,9 @@ private: /// A PEHeaderChunk represents PE header including COFF header. class PEHeaderChunk : public HeaderChunk { public: - explicit PEHeaderChunk(const PECOFFLinkingContext &context) : HeaderChunk() { - // Set the size of the chunk and initialize the header with null bytes. - _size = sizeof(llvm::COFF::PEMagic) + sizeof(_coffHeader) - + sizeof(_peHeader); - std::memset(&_coffHeader, 0, sizeof(_coffHeader)); - std::memset(&_peHeader, 0, sizeof(_peHeader)); - - _coffHeader.Machine = context.getMachineType(); - _coffHeader.TimeDateStamp = time(NULL); - - // The size of PE header including optional data directory is always 224. - _coffHeader.SizeOfOptionalHeader = 224; - - // Attributes of the executable. - uint16_t characteristics = llvm::COFF::IMAGE_FILE_32BIT_MACHINE | - llvm::COFF::IMAGE_FILE_EXECUTABLE_IMAGE; - if (context.getLargeAddressAware()) - characteristics |= llvm::COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE; - if (context.getSwapRunFromCD()) - characteristics |= llvm::COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; - if (context.getSwapRunFromNet()) - characteristics |= llvm::COFF::IMAGE_FILE_NET_RUN_FROM_SWAP; - if (!context.getBaseRelocationEnabled()) - characteristics |= llvm::COFF::IMAGE_FILE_RELOCS_STRIPPED; - - _coffHeader.Characteristics = characteristics; - - // 0x10b indicates a normal PE32 executable. For PE32+ it should be 0x20b. - _peHeader.Magic = 0x10b; - - // The address of entry point relative to ImageBase. Windows executable - // usually starts at address 0x401000. - _peHeader.AddressOfEntryPoint = 0x1000; - - // The address of the executable when loaded into memory. The default for - // DLLs is 0x10000000. The default for executables is 0x400000. - _peHeader.ImageBase = context.getBaseAddress(); - - // Sections should be page-aligned when loaded into memory, which is 4KB on - // x86. - _peHeader.SectionAlignment = context.getSectionDefaultAlignment(); - - // Sections in an executable file on disk should be sector-aligned (512 byte). - _peHeader.FileAlignment = SECTOR_SIZE; - - // The version number of the resultant executable/DLL. The number is purely - // informative, and neither the linker nor the loader won't use it. User can - // set the value using /version command line option. Default is 0.0. - PECOFFLinkingContext::Version imageVersion = context.getImageVersion(); - _peHeader.MajorImageVersion = imageVersion.majorVersion; - _peHeader.MinorImageVersion = imageVersion.minorVersion; - - // The required Windows version number. This is the internal version and - // shouldn't be confused with product name. Windows 7 is version 6.1 and - // Windows 8 is 6.2, for example. - PECOFFLinkingContext::Version minOSVersion = context.getMinOSVersion(); - _peHeader.MajorOperatingSystemVersion = minOSVersion.majorVersion; - _peHeader.MinorOperatingSystemVersion = minOSVersion.minorVersion; - _peHeader.MajorSubsystemVersion = minOSVersion.majorVersion; - _peHeader.MinorSubsystemVersion = minOSVersion.minorVersion; - - _peHeader.Subsystem = context.getSubsystem(); - - // Despite its name, DLL characteristics field has meaning both for - // executables and DLLs. We are not very sure if the following bits must - // be set, but regular binaries seem to have these bits, so we follow - // them. - uint16_t dllCharacteristics = - llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_SEH; - if (context.isTerminalServerAware()) - dllCharacteristics |= - llvm::COFF::IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; - if (context.isNxCompat()) - dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; - if (context.getDynamicBaseEnabled()) - dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; - if (!context.getAllowBind()) - dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_BIND; - if (!context.getAllowIsolation()) - dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; - _peHeader.DLLCharacteristics = dllCharacteristics; - - _peHeader.SizeOfStackReserve = context.getStackReserve(); - _peHeader.SizeOfStackCommit = context.getStackCommit(); - _peHeader.SizeOfHeapReserve = context.getHeapReserve(); - _peHeader.SizeOfHeapCommit = context.getHeapCommit(); - - // The number of data directory entries. We always have 16 entries. - _peHeader.NumberOfRvaAndSize = 16; - } + explicit PEHeaderChunk(const PECOFFLinkingContext &context); - virtual void write(uint8_t *fileBuffer) { - fileBuffer += fileOffset(); - std::memcpy(fileBuffer, llvm::COFF::PEMagic, sizeof(llvm::COFF::PEMagic)); - fileBuffer += sizeof(llvm::COFF::PEMagic); - std::memcpy(fileBuffer, &_coffHeader, sizeof(_coffHeader)); - fileBuffer += sizeof(_coffHeader); - std::memcpy(fileBuffer, &_peHeader, sizeof(_peHeader)); - } + virtual void write(uint8_t *fileBuffer); virtual void setSizeOfHeaders(uint64_t size) { // Must be multiple of FileAlignment. @@ -281,14 +185,7 @@ private: /// An AtomChunk represents a section containing atoms. class AtomChunk : public Chunk { public: - virtual void write(uint8_t *fileBuffer) { - for (const auto *layout : _atomLayouts) { - const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); - ArrayRef<uint8_t> rawContent = atom->rawContent(); - std::memcpy(fileBuffer + layout->_fileOffset, rawContent.data(), - rawContent.size()); - } - } + virtual void write(uint8_t *fileBuffer); /// Add all atoms to the given map. This data will be used to do relocation. void buildAtomToVirtualAddr(std::map<const Atom *, uint64_t> &atomRva) { @@ -298,74 +195,9 @@ public: void applyRelocations(uint8_t *fileBuffer, std::map<const Atom *, uint64_t> &atomRva, - uint64_t imageBaseAddress) { - for (const auto *layout : _atomLayouts) { - const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); - for (const Reference *ref : *atom) { - auto relocSite = reinterpret_cast<ulittle32_t *>( - fileBuffer + layout->_fileOffset + ref->offsetInAtom()); - uint64_t targetAddr = atomRva[ref->target()]; - // Also account for whatever offset is already stored at the relocation site. - targetAddr += *relocSite; - - // Skip if this reference is not for relocation. - if (ref->kind() < lld::Reference::kindTargetLow) - continue; - - switch (ref->kind()) { - case llvm::COFF::IMAGE_REL_I386_ABSOLUTE: - // This relocation is no-op. - break; - case llvm::COFF::IMAGE_REL_I386_DIR32: - // Set target's 32-bit VA. - *relocSite = targetAddr + imageBaseAddress; - break; - case llvm::COFF::IMAGE_REL_I386_DIR32NB: - // Set target's 32-bit RVA. - *relocSite = targetAddr; - break; - case llvm::COFF::IMAGE_REL_I386_REL32: { - // Set 32-bit relative address of the target. This relocation is - // usually used for relative branch or call instruction. - uint32_t disp = atomRva[atom] + ref->offsetInAtom() + 4; - *relocSite = targetAddr - disp; - break; - } - default: - llvm_unreachable("Unsupported relocation kind"); - } - } - } - } - - /// Print atom VAs. Used only for debugging. - void printAtomAddresses(uint64_t baseAddr) { - for (const auto *layout : _atomLayouts) { - const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); - uint64_t addr = layout->_virtualAddr; - llvm::dbgs() << llvm::format("0x%08llx: ", addr + baseAddr) - << (atom->name().empty() ? "(anonymous)" : atom->name()) - << "\n"; - } - } - - /// List all virtual addresses (and not relative virtual addresses) that need - /// to be fixed up if image base is relocated. The only relocation type that - /// needs to be fixed is DIR32 on i386. REL32 is not (and should not be) - /// fixed up because it's PC-relative. - void addBaseRelocations(std::vector<uint64_t> &relocSites) { - // TODO: llvm-objdump doesn't support parsing the base relocation table, so - // we can't really test this at the moment. As a temporary solution, we - // should output debug messages with atom names and addresses so that we - // can inspect relocations, and fix the tests (base-reloc.test, maybe - // others) to use those messages. - for (const auto *layout : _atomLayouts) { - const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); - for (const Reference *ref : *atom) - if (ref->kind() == llvm::COFF::IMAGE_REL_I386_DIR32) - relocSites.push_back(layout->_virtualAddr + ref->offsetInAtom()); - } - } + uint64_t imageBaseAddress); + void printAtomAddresses(uint64_t baseAddr); + void addBaseRelocations(std::vector<uint64_t> &relocSites); // Set the file offset of the beginning of this section. virtual void setFileOffset(uint64_t fileOffset) { @@ -426,22 +258,7 @@ public: _baseRelocSize = size; } - virtual void write(uint8_t *fileBuffer) { - if (!_atomLayouts.empty()) { - assert(_atomLayouts.size() == 1); - const AtomLayout *layout = _atomLayouts[0]; - ArrayRef<uint8_t> content = static_cast<const DefinedAtom *>(layout->_atom)->rawContent(); - std::memcpy(fileBuffer + _fileOffset, content.data(), content.size()); - } - - // Write base relocation table entry. - int baseRelocOffset = llvm::COFF::DataDirectoryIndex::BASE_RELOCATION_TABLE - * sizeof(llvm::object::data_directory); - auto *baseReloc = reinterpret_cast<llvm::object::data_directory *>( - fileBuffer + _fileOffset + baseRelocOffset); - baseReloc->RelativeVirtualAddress = _baseRelocAddr; - baseReloc->Size = _baseRelocSize; - } + virtual void write(uint8_t *fileBuffer); private: uint32_t _baseRelocAddr; @@ -478,123 +295,32 @@ public: virtual uint32_t getVirtualAddress() { return _sectionHeader.VirtualAddress; } - virtual llvm::object::coff_section &getSectionHeader() { - // Fix up section size before returning it. VirtualSize should be the size - // of the actual content, and SizeOfRawData should be aligned to the section - // alignment. - _sectionHeader.VirtualSize = _size; - _sectionHeader.SizeOfRawData = size(); - return _sectionHeader; - } - - ulittle32_t getSectionCharacteristics() { - return _sectionHeader.Characteristics; - } + virtual llvm::object::coff_section &getSectionHeader(); - void appendAtom(const DefinedAtom *atom) { - // Atom may have to be at a proper alignment boundary. If so, move the - // pointer to make a room after the last atom before adding new one. - _size = llvm::RoundUpToAlignment(_size, 1 << atom->alignment().powerOf2); + ulittle32_t getSectionCharacteristics(); - // Create an AtomLayout and move the current pointer. - auto *layout = new (_alloc) AtomLayout(atom, _size, _size); - _atomLayouts.push_back(layout); - _size += atom->size(); - } + void appendAtom(const DefinedAtom *atom); static bool classof(const Chunk *c) { return c->getKind() == kindSection; } protected: - SectionChunk(StringRef sectionName, uint32_t characteristics) - : AtomChunk(kindSection), - _sectionHeader(createSectionHeader(sectionName, characteristics)) { - // The section should be aligned to disk sector. - _align = SECTOR_SIZE; - } + SectionChunk(StringRef sectionName, uint32_t characteristics); void buildContents(const File &linkedFile, - bool (*isEligible)(const DefinedAtom *)) { - // Extract atoms from the linked file and append them to this section. - for (const DefinedAtom *atom : linkedFile.defined()) { - assert(atom->sectionChoice() == DefinedAtom::sectionBasedOnContent); - if (isEligible(atom)) - appendAtom(atom); - } - - // Now that we have a list of atoms that to be written in this section, - // and we know the size of the section. Let's write them to the section - // header. VirtualSize should be the size of the actual content, and - // SizeOfRawData should be aligned to the section alignment. - _sectionHeader.VirtualSize = _size; - _sectionHeader.SizeOfRawData = size(); - } + bool (*isEligible)(const DefinedAtom *)); private: llvm::object::coff_section - createSectionHeader(StringRef sectionName, uint32_t characteristics) const { - llvm::object::coff_section header; - - // Section name equal to or shorter than 8 byte fits in the section - // header. Longer names should be stored to string table, which is not - // implemented yet. - if (sizeof(header.Name) < sectionName.size()) - llvm_unreachable("Cannot handle section name longer than 8 byte"); - - // Name field must be NUL-padded. If the name is exactly 8 byte long, - // there's no terminating NUL. - std::memset(header.Name, 0, sizeof(header.Name)); - std::strncpy(header.Name, sectionName.data(), sizeof(header.Name)); - - header.VirtualSize = 0; - header.VirtualAddress = 0; - header.SizeOfRawData = 0; - header.PointerToRawData = 0; - header.PointerToRelocations = 0; - header.PointerToLinenumbers = 0; - header.NumberOfRelocations = 0; - header.NumberOfLinenumbers = 0; - header.Characteristics = characteristics; - return header; - } + createSectionHeader(StringRef sectionName, uint32_t characteristics) const; llvm::object::coff_section _sectionHeader; mutable llvm::BumpPtrAllocator _alloc; }; -void SectionHeaderTableChunk::addSection(SectionChunk *chunk) { - _sections.push_back(chunk); -} - -uint64_t SectionHeaderTableChunk::size() const { - return _sections.size() * sizeof(llvm::object::coff_section); -} - -void SectionHeaderTableChunk::write(uint8_t *fileBuffer) { - uint64_t offset = 0; - fileBuffer += fileOffset(); - for (const auto &chunk : _sections) { - const llvm::object::coff_section &header = chunk->getSectionHeader(); - std::memcpy(fileBuffer + offset, &header, sizeof(header)); - offset += sizeof(header); - } -} - // \brief A TextSectionChunk represents a .text section. class TextSectionChunk : public SectionChunk { public: - virtual void write(uint8_t *fileBuffer) { - if (_atomLayouts.empty()) - return; - // Fill the section with INT 3 (0xCC) rather than NUL, so that the - // disassembler will not interpret a garbage between atoms as the beginning - // of multi-byte machine code. This does not change the behavior of - // resulting binary but help debugging. - uint8_t *start = fileBuffer + _atomLayouts.front()->_fileOffset; - uint8_t *end = fileBuffer + _atomLayouts.back()->_fileOffset; - memset(start, 0xCC, end - start); - - SectionChunk::write(fileBuffer); - } + virtual void write(uint8_t *fileBuffer); TextSectionChunk(const File &linkedFile) : SectionChunk(".text", characteristics) { @@ -716,24 +442,7 @@ public: BaseRelocChunk(const File &linkedFile) : SectionChunk(".reloc", characteristics), _file(linkedFile) {} - /// Creates .reloc section content from the other sections. The content of - /// .reloc is basically a list of relocation sites. The relocation sites are - /// divided into blocks. Each block represents the base relocation for a 4K - /// page. - /// - /// By dividing 32 bit RVAs into blocks, COFF saves disk and memory space for - /// the base relocation. A block consists of a 32 bit page RVA and 16 bit - /// relocation entries which represent offsets in the page. That is a more - /// compact representation than a simple vector of 32 bit RVAs. - void setContents(ChunkVectorT &chunks) { - std::vector<uint64_t> relocSites = listRelocSites(chunks); - PageOffsetT blocks = groupByPage(relocSites); - for (auto &i : blocks) { - uint64_t pageAddr = i.first; - const std::vector<uint16_t> &offsetsInPage = i.second; - appendAtom(createBaseRelocBlock(_file, pageAddr, offsetsInPage)); - } - } + void setContents(ChunkVectorT &chunks); private: // When loaded into memory, reloc section should be readable and writable. @@ -744,222 +453,413 @@ private: // Returns a list of RVAs that needs to be relocated if the binary is loaded // at an address different from its preferred one. - std::vector<uint64_t> listRelocSites(ChunkVectorT &chunks) { - std::vector<uint64_t> ret; - for (auto &cp : chunks) - if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp)) - chunk->addBaseRelocations(ret); - return ret; - } + std::vector<uint64_t> listRelocSites(ChunkVectorT &chunks); // Divide the given RVAs into blocks. - PageOffsetT groupByPage(std::vector<uint64_t> relocSites) { - PageOffsetT blocks; - uint64_t mask = static_cast<uint64_t>(PAGE_SIZE) - 1; - for (uint64_t addr : relocSites) - blocks[addr & ~mask].push_back(addr & mask); - return blocks; - } + PageOffsetT groupByPage(std::vector<uint64_t> relocSites); // Create the content of a relocation block. DefinedAtom *createBaseRelocBlock(const File &file, uint64_t pageAddr, - const std::vector<uint16_t> &offsets) { - // Relocation blocks should be padded with IMAGE_REL_I386_ABSOLUTE to be - // aligned to a DWORD size boundary. - uint32_t size = llvm::RoundUpToAlignment(sizeof(ulittle32_t) * 2 - + sizeof(ulittle16_t) * offsets.size(), sizeof(ulittle32_t)); - std::vector<uint8_t> contents(size); - uint8_t *ptr = &contents[0]; - - // The first four bytes is the page RVA. - *reinterpret_cast<ulittle32_t *>(ptr) = pageAddr; - ptr += sizeof(ulittle32_t); - - // The second four bytes is the size of the block, including the the page - // RVA and this size field. - *reinterpret_cast<ulittle32_t *>(ptr) = size; - ptr += sizeof(ulittle32_t); - - // The rest of the block consists of offsets in the page. - for (uint16_t offset : offsets) { - assert(offset < PAGE_SIZE); - uint16_t val = (llvm::COFF::IMAGE_REL_BASED_HIGHLOW << 12) | offset; - *reinterpret_cast<ulittle16_t *>(ptr) = val; - ptr += sizeof(ulittle16_t); - } - return new (_alloc) BaseRelocAtom(file, std::move(contents)); - } + const std::vector<uint16_t> &offsets); mutable llvm::BumpPtrAllocator _alloc; const File &_file; }; -} // end anonymous namespace +PEHeaderChunk::PEHeaderChunk(const PECOFFLinkingContext &context) + : HeaderChunk() { + // Set the size of the chunk and initialize the header with null bytes. + _size = sizeof(llvm::COFF::PEMagic) + sizeof(_coffHeader) + sizeof(_peHeader); + std::memset(&_coffHeader, 0, sizeof(_coffHeader)); + std::memset(&_peHeader, 0, sizeof(_peHeader)); + + _coffHeader.Machine = context.getMachineType(); + _coffHeader.TimeDateStamp = time(NULL); + + // The size of PE header including optional data directory is always 224. + _coffHeader.SizeOfOptionalHeader = 224; + + // Attributes of the executable. + uint16_t characteristics = llvm::COFF::IMAGE_FILE_32BIT_MACHINE | + llvm::COFF::IMAGE_FILE_EXECUTABLE_IMAGE; + if (context.getLargeAddressAware()) + characteristics |= llvm::COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE; + if (context.getSwapRunFromCD()) + characteristics |= llvm::COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; + if (context.getSwapRunFromNet()) + characteristics |= llvm::COFF::IMAGE_FILE_NET_RUN_FROM_SWAP; + if (!context.getBaseRelocationEnabled()) + characteristics |= llvm::COFF::IMAGE_FILE_RELOCS_STRIPPED; + + _coffHeader.Characteristics = characteristics; + + // 0x10b indicates a normal PE32 executable. For PE32+ it should be 0x20b. + _peHeader.Magic = 0x10b; + + // The address of entry point relative to ImageBase. Windows executable + // usually starts at address 0x401000. + _peHeader.AddressOfEntryPoint = 0x1000; + + // The address of the executable when loaded into memory. The default for + // DLLs is 0x10000000. The default for executables is 0x400000. + _peHeader.ImageBase = context.getBaseAddress(); + + // Sections should be page-aligned when loaded into memory, which is 4KB on + // x86. + _peHeader.SectionAlignment = context.getSectionDefaultAlignment(); + + // Sections in an executable file on disk should be sector-aligned (512 byte). + _peHeader.FileAlignment = SECTOR_SIZE; + + // The version number of the resultant executable/DLL. The number is purely + // informative, and neither the linker nor the loader won't use it. User can + // set the value using /version command line option. Default is 0.0. + PECOFFLinkingContext::Version imageVersion = context.getImageVersion(); + _peHeader.MajorImageVersion = imageVersion.majorVersion; + _peHeader.MinorImageVersion = imageVersion.minorVersion; + + // The required Windows version number. This is the internal version and + // shouldn't be confused with product name. Windows 7 is version 6.1 and + // Windows 8 is 6.2, for example. + PECOFFLinkingContext::Version minOSVersion = context.getMinOSVersion(); + _peHeader.MajorOperatingSystemVersion = minOSVersion.majorVersion; + _peHeader.MinorOperatingSystemVersion = minOSVersion.minorVersion; + _peHeader.MajorSubsystemVersion = minOSVersion.majorVersion; + _peHeader.MinorSubsystemVersion = minOSVersion.minorVersion; + + _peHeader.Subsystem = context.getSubsystem(); + + // Despite its name, DLL characteristics field has meaning both for + // executables and DLLs. We are not very sure if the following bits must + // be set, but regular binaries seem to have these bits, so we follow + // them. + uint16_t dllCharacteristics = llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_SEH; + if (context.isTerminalServerAware()) + dllCharacteristics |= + llvm::COFF::IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; + if (context.isNxCompat()) + dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; + if (context.getDynamicBaseEnabled()) + dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; + if (!context.getAllowBind()) + dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_BIND; + if (!context.getAllowIsolation()) + dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; + _peHeader.DLLCharacteristics = dllCharacteristics; + + _peHeader.SizeOfStackReserve = context.getStackReserve(); + _peHeader.SizeOfStackCommit = context.getStackCommit(); + _peHeader.SizeOfHeapReserve = context.getHeapReserve(); + _peHeader.SizeOfHeapCommit = context.getHeapCommit(); + + // The number of data directory entries. We always have 16 entries. + _peHeader.NumberOfRvaAndSize = 16; +} -class ExecutableWriter : public Writer { -public: - explicit ExecutableWriter(const PECOFFLinkingContext &context) - : _PECOFFLinkingContext(context), _numSections(0), - _imageSizeInMemory(PAGE_SIZE), _imageSizeOnDisk(0) {} +void PEHeaderChunk::write(uint8_t *fileBuffer) { + fileBuffer += fileOffset(); + std::memcpy(fileBuffer, llvm::COFF::PEMagic, sizeof(llvm::COFF::PEMagic)); + fileBuffer += sizeof(llvm::COFF::PEMagic); + std::memcpy(fileBuffer, &_coffHeader, sizeof(_coffHeader)); + fileBuffer += sizeof(_coffHeader); + std::memcpy(fileBuffer, &_peHeader, sizeof(_peHeader)); +} + +void AtomChunk::write(uint8_t *fileBuffer) { + for (const auto *layout : _atomLayouts) { + const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); + ArrayRef<uint8_t> rawContent = atom->rawContent(); + std::memcpy(fileBuffer + layout->_fileOffset, rawContent.data(), + rawContent.size()); + } +} - // Create all chunks that consist of the output file. - void build(const File &linkedFile) { - // Create file chunks and add them to the list. - auto *dosStub = new DOSStubChunk(_PECOFFLinkingContext); - auto *peHeader = new PEHeaderChunk(_PECOFFLinkingContext); - auto *dataDirectory = new DataDirectoryChunk(linkedFile); - auto *sectionTable = new SectionHeaderTableChunk(); - auto *text = new TextSectionChunk(linkedFile); - auto *rdata = new RDataSectionChunk(linkedFile); - auto *data = new DataSectionChunk(linkedFile); - auto *bss = new BssSectionChunk(linkedFile); - BaseRelocChunk *baseReloc = nullptr; - if (_PECOFFLinkingContext.getBaseRelocationEnabled()) - baseReloc = new BaseRelocChunk(linkedFile); - - addChunk(dosStub); - addChunk(peHeader); - addChunk(dataDirectory); - addChunk(sectionTable); - - // Do not add the empty section. Windows loader does not like a section of - // size zero and rejects such executable. - if (text->size()) - addSectionChunk(text, sectionTable); - if (rdata->size()) - addSectionChunk(rdata, sectionTable); - if (data->size()) - addSectionChunk(data, sectionTable); - if (bss->size()) - addSectionChunk(bss, sectionTable); - - // Now that we know the addresses of all defined atoms that needs to be - // relocated. So we can create the ".reloc" section which contains all the - // relocation sites. - if (baseReloc) { - baseReloc->setContents(_chunks); - if (baseReloc->size()) { - addSectionChunk(baseReloc, sectionTable); - dataDirectory->setBaseRelocField(baseReloc->getSectionRva(), - baseReloc->rawSize()); +void AtomChunk::applyRelocations(uint8_t *fileBuffer, + std::map<const Atom *, uint64_t> &atomRva, + uint64_t imageBaseAddress) { + for (const auto *layout : _atomLayouts) { + const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); + for (const Reference *ref : *atom) { + auto relocSite = reinterpret_cast<ulittle32_t *>( + fileBuffer + layout->_fileOffset + ref->offsetInAtom()); + uint64_t targetAddr = atomRva[ref->target()]; + // Also account for whatever offset is already stored at the relocation + // site. + targetAddr += *relocSite; + + // Skip if this reference is not for relocation. + if (ref->kind() < lld::Reference::kindTargetLow) + continue; + + switch (ref->kind()) { + case llvm::COFF::IMAGE_REL_I386_ABSOLUTE: + // This relocation is no-op. + break; + case llvm::COFF::IMAGE_REL_I386_DIR32: + // Set target's 32-bit VA. + *relocSite = targetAddr + imageBaseAddress; + break; + case llvm::COFF::IMAGE_REL_I386_DIR32NB: + // Set target's 32-bit RVA. + *relocSite = targetAddr; + break; + case llvm::COFF::IMAGE_REL_I386_REL32: { + // Set 32-bit relative address of the target. This relocation is + // usually used for relative branch or call instruction. + uint32_t disp = atomRva[atom] + ref->offsetInAtom() + 4; + *relocSite = targetAddr - disp; + break; + } + default: + llvm_unreachable("Unsupported relocation kind"); } } + } +} - setImageSizeOnDisk(); - - // Now that we know the size and file offset of sections. Set the file - // header accordingly. - peHeader->setSizeOfCode(calcSizeOfCode()); - if (text->size()) { - peHeader->setBaseOfCode(text->getVirtualAddress()); - } - if (rdata->size()) { - peHeader->setBaseOfData(rdata->getVirtualAddress()); - } else if (data->size()) { - peHeader->setBaseOfData(data->getVirtualAddress()); - } - peHeader->setSizeOfInitializedData(calcSizeOfInitializedData()); - peHeader->setSizeOfUninitializedData(calcSizeOfUninitializedData()); - peHeader->setNumberOfSections(_numSections); - peHeader->setSizeOfImage(_imageSizeInMemory); +/// Print atom VAs. Used only for debugging. +void AtomChunk::printAtomAddresses(uint64_t baseAddr) { + for (const auto *layout : _atomLayouts) { + const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); + uint64_t addr = layout->_virtualAddr; + llvm::dbgs() << llvm::format("0x%08llx: ", addr + baseAddr) + << (atom->name().empty() ? "(anonymous)" : atom->name()) + << "\n"; + } +} - // The combined size of the DOS, PE and section headers including garbage - // between the end of the header and the beginning of the first section. - peHeader->setSizeOfHeaders(dosStub->size() + peHeader->size() + - sectionTable->size() + dataDirectory->size()); +/// List all virtual addresses (and not relative virtual addresses) that need +/// to be fixed up if image base is relocated. The only relocation type that +/// needs to be fixed is DIR32 on i386. REL32 is not (and should not be) +/// fixed up because it's PC-relative. +void AtomChunk::addBaseRelocations(std::vector<uint64_t> &relocSites) { + // TODO: llvm-objdump doesn't support parsing the base relocation table, so + // we can't really test this at the moment. As a temporary solution, we + // should output debug messages with atom names and addresses so that we + // can inspect relocations, and fix the tests (base-reloc.test, maybe + // others) to use those messages. + for (const auto *layout : _atomLayouts) { + const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom); + for (const Reference *ref : *atom) + if (ref->kind() == llvm::COFF::IMAGE_REL_I386_DIR32) + relocSites.push_back(layout->_virtualAddr + ref->offsetInAtom()); + } +} - setAddressOfEntryPoint(text, peHeader); +void DataDirectoryChunk::write(uint8_t *fileBuffer) { + if (!_atomLayouts.empty()) { + assert(_atomLayouts.size() == 1); + const AtomLayout *layout = _atomLayouts[0]; + ArrayRef<uint8_t> content = + static_cast<const DefinedAtom *>(layout->_atom)->rawContent(); + std::memcpy(fileBuffer + _fileOffset, content.data(), content.size()); } - virtual error_code writeFile(const File &linkedFile, StringRef path) { - this->build(linkedFile); + // Write base relocation table entry. + int baseRelocOffset = llvm::COFF::DataDirectoryIndex::BASE_RELOCATION_TABLE * + sizeof(llvm::object::data_directory); + auto *baseReloc = reinterpret_cast<llvm::object::data_directory *>( + fileBuffer + _fileOffset + baseRelocOffset); + baseReloc->RelativeVirtualAddress = _baseRelocAddr; + baseReloc->Size = _baseRelocSize; +} + +llvm::object::coff_section &SectionChunk::getSectionHeader() { + // Fix up section size before returning it. VirtualSize should be the size + // of the actual content, and SizeOfRawData should be aligned to the section + // alignment. + _sectionHeader.VirtualSize = _size; + _sectionHeader.SizeOfRawData = size(); + return _sectionHeader; +} + +ulittle32_t SectionChunk::getSectionCharacteristics() { + return _sectionHeader.Characteristics; +} + +void SectionChunk::appendAtom(const DefinedAtom *atom) { + // Atom may have to be at a proper alignment boundary. If so, move the + // pointer to make a room after the last atom before adding new one. + _size = llvm::RoundUpToAlignment(_size, 1 << atom->alignment().powerOf2); - uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size(); - OwningPtr<llvm::FileOutputBuffer> buffer; - error_code ec = llvm::FileOutputBuffer::create( - path, totalSize, buffer, llvm::FileOutputBuffer::F_executable); - if (ec) - return ec; + // Create an AtomLayout and move the current pointer. + auto *layout = new (_alloc) AtomLayout(atom, _size, _size); + _atomLayouts.push_back(layout); + _size += atom->size(); +} + +SectionChunk::SectionChunk(StringRef sectionName, uint32_t characteristics) + : AtomChunk(kindSection), + _sectionHeader(createSectionHeader(sectionName, characteristics)) { + // The section should be aligned to disk sector. + _align = SECTOR_SIZE; +} - for (const auto &chunk : _chunks) - chunk->write(buffer->getBufferStart()); - applyAllRelocations(buffer->getBufferStart()); - DEBUG(printAllAtomAddresses()); - return buffer->commit(); +void SectionChunk::buildContents(const File &linkedFile, + bool (*isEligible)(const DefinedAtom *)) { + // Extract atoms from the linked file and append them to this section. + for (const DefinedAtom *atom : linkedFile.defined()) { + assert(atom->sectionChoice() == DefinedAtom::sectionBasedOnContent); + if (isEligible(atom)) + appendAtom(atom); } -private: - /// Apply relocations to the output file buffer. This two pass. In the first - /// pass, we visit all atoms to create a map from atom to its virtual - /// address. In the second pass, we visit all relocation references to fix - /// up addresses in the buffer. - void applyAllRelocations(uint8_t *bufferStart) { - for (auto &cp : _chunks) - if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) - chunk->applyRelocations(bufferStart, atomRva, - _PECOFFLinkingContext.getBaseAddress()); - } - - /// Print atom VAs. Used only for debugging. - void printAllAtomAddresses() { - for (auto &cp : _chunks) - if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) - chunk->printAtomAddresses(_PECOFFLinkingContext.getBaseAddress()); - } - - void addChunk(Chunk *chunk) { - _chunks.push_back(std::unique_ptr<Chunk>(chunk)); - } - - void addSectionChunk(SectionChunk *chunk, - SectionHeaderTableChunk *table) { - _chunks.push_back(std::unique_ptr<Chunk>(chunk)); - table->addSection(chunk); - _numSections++; - - // Compute and set the starting address of sections when loaded in - // memory. They are different from positions on disk because sections need - // to be sector-aligned on disk but page-aligned in memory. - chunk->setVirtualAddress(_imageSizeInMemory); - chunk->buildAtomToVirtualAddr(atomRva); - _imageSizeInMemory = llvm::RoundUpToAlignment( - _imageSizeInMemory + chunk->size(), PAGE_SIZE); - } - - void setImageSizeOnDisk() { - for (auto &chunk : _chunks) { - // Compute and set the offset of the chunk in the output file. - _imageSizeOnDisk = llvm::RoundUpToAlignment(_imageSizeOnDisk, - chunk->align()); - chunk->setFileOffset(_imageSizeOnDisk); - _imageSizeOnDisk += chunk->size(); - } + // Now that we have a list of atoms that to be written in this section, + // and we know the size of the section. Let's write them to the section + // header. VirtualSize should be the size of the actual content, and + // SizeOfRawData should be aligned to the section alignment. + _sectionHeader.VirtualSize = _size; + _sectionHeader.SizeOfRawData = size(); +} + +llvm::object::coff_section +SectionChunk::createSectionHeader(StringRef sectionName, + uint32_t characteristics) const { + llvm::object::coff_section header; + + // Section name equal to or shorter than 8 byte fits in the section + // header. Longer names should be stored to string table, which is not + // implemented yet. + if (sizeof(header.Name) < sectionName.size()) + llvm_unreachable("Cannot handle section name longer than 8 byte"); + + // Name field must be NUL-padded. If the name is exactly 8 byte long, + // there's no terminating NUL. + std::memset(header.Name, 0, sizeof(header.Name)); + std::strncpy(header.Name, sectionName.data(), sizeof(header.Name)); + + header.VirtualSize = 0; + header.VirtualAddress = 0; + header.SizeOfRawData = 0; + header.PointerToRawData = 0; + header.PointerToRelocations = 0; + header.PointerToLinenumbers = 0; + header.NumberOfRelocations = 0; + header.NumberOfLinenumbers = 0; + header.Characteristics = characteristics; + return header; +} + +void TextSectionChunk::write(uint8_t *fileBuffer) { + if (_atomLayouts.empty()) + return; + // Fill the section with INT 3 (0xCC) rather than NUL, so that the + // disassembler will not interpret a garbage between atoms as the beginning + // of multi-byte machine code. This does not change the behavior of + // resulting binary but help debugging. + uint8_t *start = fileBuffer + _atomLayouts.front()->_fileOffset; + uint8_t *end = fileBuffer + _atomLayouts.back()->_fileOffset; + memset(start, 0xCC, end - start); + SectionChunk::write(fileBuffer); +} + +void SectionHeaderTableChunk::addSection(SectionChunk *chunk) { + _sections.push_back(chunk); +} + +uint64_t SectionHeaderTableChunk::size() const { + return _sections.size() * sizeof(llvm::object::coff_section); +} + +void SectionHeaderTableChunk::write(uint8_t *fileBuffer) { + uint64_t offset = 0; + fileBuffer += fileOffset(); + for (const auto &chunk : _sections) { + const llvm::object::coff_section &header = chunk->getSectionHeader(); + std::memcpy(fileBuffer + offset, &header, sizeof(header)); + offset += sizeof(header); } +} - void setAddressOfEntryPoint(TextSectionChunk *text, PEHeaderChunk *peHeader) { - // Find the virtual address of the entry point symbol if any. - // PECOFF spec says that entry point for dll images is optional, in which - // case it must be set to 0. - if (_PECOFFLinkingContext.entrySymbolName().empty() && - _PECOFFLinkingContext.getImageType() - == PECOFFLinkingContext::IMAGE_DLL) { - peHeader->setAddressOfEntryPoint(0); - } else { - uint64_t entryPointAddress = text->getAtomVirtualAddress( - _PECOFFLinkingContext.entrySymbolName()); - if (entryPointAddress != 0) - peHeader->setAddressOfEntryPoint(entryPointAddress); - } +/// Creates .reloc section content from the other sections. The content of +/// .reloc is basically a list of relocation sites. The relocation sites are +/// divided into blocks. Each block represents the base relocation for a 4K +/// page. +/// +/// By dividing 32 bit RVAs into blocks, COFF saves disk and memory space for +/// the base relocation. A block consists of a 32 bit page RVA and 16 bit +/// relocation entries which represent offsets in the page. That is a more +/// compact representation than a simple vector of 32 bit RVAs. +void BaseRelocChunk::setContents(ChunkVectorT &chunks) { + std::vector<uint64_t> relocSites = listRelocSites(chunks); + PageOffsetT blocks = groupByPage(relocSites); + for (auto &i : blocks) { + uint64_t pageAddr = i.first; + const std::vector<uint16_t> &offsetsInPage = i.second; + appendAtom(createBaseRelocBlock(_file, pageAddr, offsetsInPage)); } +} + +// Returns a list of RVAs that needs to be relocated if the binary is loaded +// at an address different from its preferred one. +std::vector<uint64_t> BaseRelocChunk::listRelocSites(ChunkVectorT &chunks) { + std::vector<uint64_t> ret; + for (auto &cp : chunks) + if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp)) + chunk->addBaseRelocations(ret); + return ret; +} + +// Divide the given RVAs into blocks. +BaseRelocChunk::PageOffsetT +BaseRelocChunk::groupByPage(std::vector<uint64_t> relocSites) { + PageOffsetT blocks; + uint64_t mask = static_cast<uint64_t>(PAGE_SIZE) - 1; + for (uint64_t addr : relocSites) + blocks[addr & ~mask].push_back(addr & mask); + return blocks; +} - uint64_t calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) { - uint64_t ret = 0; - for (auto &cp : _chunks) - if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp)) - if (chunk->getSectionCharacteristics() & sectionType) - ret += chunk->size(); - return ret; +// Create the content of a relocation block. +DefinedAtom * +BaseRelocChunk::createBaseRelocBlock(const File &file, uint64_t pageAddr, + const std::vector<uint16_t> &offsets) { + // Relocation blocks should be padded with IMAGE_REL_I386_ABSOLUTE to be + // aligned to a DWORD size boundary. + uint32_t size = llvm::RoundUpToAlignment( + sizeof(ulittle32_t) * 2 + sizeof(ulittle16_t) * offsets.size(), + sizeof(ulittle32_t)); + std::vector<uint8_t> contents(size); + uint8_t *ptr = &contents[0]; + + // The first four bytes is the page RVA. + *reinterpret_cast<ulittle32_t *>(ptr) = pageAddr; + ptr += sizeof(ulittle32_t); + + // The second four bytes is the size of the block, including the the page + // RVA and this size field. + *reinterpret_cast<ulittle32_t *>(ptr) = size; + ptr += sizeof(ulittle32_t); + + // The rest of the block consists of offsets in the page. + for (uint16_t offset : offsets) { + assert(offset < PAGE_SIZE); + uint16_t val = (llvm::COFF::IMAGE_REL_BASED_HIGHLOW << 12) | offset; + *reinterpret_cast<ulittle16_t *>(ptr) = val; + ptr += sizeof(ulittle16_t); } + return new (_alloc) BaseRelocAtom(file, std::move(contents)); +} + +} // end anonymous namespace + +class ExecutableWriter : public Writer { +public: + explicit ExecutableWriter(const PECOFFLinkingContext &context) + : _PECOFFLinkingContext(context), _numSections(0), + _imageSizeInMemory(PAGE_SIZE), _imageSizeOnDisk(0) {} + + void build(const File &linkedFile); + virtual error_code writeFile(const File &linkedFile, StringRef path); + +private: + void applyAllRelocations(uint8_t *bufferStart); + void printAllAtomAddresses(); + void addChunk(Chunk *chunk); + void addSectionChunk(SectionChunk *chunk, SectionHeaderTableChunk *table); + void setImageSizeOnDisk(); + void setAddressOfEntryPoint(TextSectionChunk *text, PEHeaderChunk *peHeader); + uint64_t calcSectionSize(llvm::COFF::SectionCharacteristics sectionType); uint64_t calcSizeOfInitializedData() { return calcSectionSize(llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA); @@ -991,6 +891,165 @@ private: std::map<const Atom *, uint64_t> atomRva; }; +// Create all chunks that consist of the output file. +void ExecutableWriter::build(const File &linkedFile) { + // Create file chunks and add them to the list. + auto *dosStub = new DOSStubChunk(_PECOFFLinkingContext); + auto *peHeader = new PEHeaderChunk(_PECOFFLinkingContext); + auto *dataDirectory = new DataDirectoryChunk(linkedFile); + auto *sectionTable = new SectionHeaderTableChunk(); + auto *text = new TextSectionChunk(linkedFile); + auto *rdata = new RDataSectionChunk(linkedFile); + auto *data = new DataSectionChunk(linkedFile); + auto *bss = new BssSectionChunk(linkedFile); + BaseRelocChunk *baseReloc = nullptr; + if (_PECOFFLinkingContext.getBaseRelocationEnabled()) + baseReloc = new BaseRelocChunk(linkedFile); + + addChunk(dosStub); + addChunk(peHeader); + addChunk(dataDirectory); + addChunk(sectionTable); + + // Do not add the empty section. Windows loader does not like a section of + // size zero and rejects such executable. + if (text->size()) + addSectionChunk(text, sectionTable); + if (rdata->size()) + addSectionChunk(rdata, sectionTable); + if (data->size()) + addSectionChunk(data, sectionTable); + if (bss->size()) + addSectionChunk(bss, sectionTable); + + // Now that we know the addresses of all defined atoms that needs to be + // relocated. So we can create the ".reloc" section which contains all the + // relocation sites. + if (baseReloc) { + baseReloc->setContents(_chunks); + if (baseReloc->size()) { + addSectionChunk(baseReloc, sectionTable); + dataDirectory->setBaseRelocField(baseReloc->getSectionRva(), + baseReloc->rawSize()); + } + } + + setImageSizeOnDisk(); + + // Now that we know the size and file offset of sections. Set the file + // header accordingly. + peHeader->setSizeOfCode(calcSizeOfCode()); + if (text->size()) { + peHeader->setBaseOfCode(text->getVirtualAddress()); + } + if (rdata->size()) { + peHeader->setBaseOfData(rdata->getVirtualAddress()); + } else if (data->size()) { + peHeader->setBaseOfData(data->getVirtualAddress()); + } + peHeader->setSizeOfInitializedData(calcSizeOfInitializedData()); + peHeader->setSizeOfUninitializedData(calcSizeOfUninitializedData()); + peHeader->setNumberOfSections(_numSections); + peHeader->setSizeOfImage(_imageSizeInMemory); + + // The combined size of the DOS, PE and section headers including garbage + // between the end of the header and the beginning of the first section. + peHeader->setSizeOfHeaders(dosStub->size() + peHeader->size() + + sectionTable->size() + dataDirectory->size()); + + setAddressOfEntryPoint(text, peHeader); +} + +error_code ExecutableWriter::writeFile(const File &linkedFile, StringRef path) { + this->build(linkedFile); + + uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size(); + OwningPtr<llvm::FileOutputBuffer> buffer; + error_code ec = llvm::FileOutputBuffer::create( + path, totalSize, buffer, llvm::FileOutputBuffer::F_executable); + if (ec) + return ec; + + for (const auto &chunk : _chunks) + chunk->write(buffer->getBufferStart()); + applyAllRelocations(buffer->getBufferStart()); + DEBUG(printAllAtomAddresses()); + return buffer->commit(); +} + +/// Apply relocations to the output file buffer. This two pass. In the first +/// pass, we visit all atoms to create a map from atom to its virtual +/// address. In the second pass, we visit all relocation references to fix +/// up addresses in the buffer. +void ExecutableWriter::applyAllRelocations(uint8_t *bufferStart) { + for (auto &cp : _chunks) + if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) + chunk->applyRelocations(bufferStart, atomRva, + _PECOFFLinkingContext.getBaseAddress()); +} + +/// Print atom VAs. Used only for debugging. +void ExecutableWriter::printAllAtomAddresses() { + for (auto &cp : _chunks) + if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) + chunk->printAtomAddresses(_PECOFFLinkingContext.getBaseAddress()); +} + +void ExecutableWriter::addChunk(Chunk *chunk) { + _chunks.push_back(std::unique_ptr<Chunk>(chunk)); +} + +void ExecutableWriter::addSectionChunk(SectionChunk *chunk, + SectionHeaderTableChunk *table) { + _chunks.push_back(std::unique_ptr<Chunk>(chunk)); + table->addSection(chunk); + _numSections++; + + // Compute and set the starting address of sections when loaded in + // memory. They are different from positions on disk because sections need + // to be sector-aligned on disk but page-aligned in memory. + chunk->setVirtualAddress(_imageSizeInMemory); + chunk->buildAtomToVirtualAddr(atomRva); + _imageSizeInMemory = + llvm::RoundUpToAlignment(_imageSizeInMemory + chunk->size(), PAGE_SIZE); +} + +void ExecutableWriter::setImageSizeOnDisk() { + for (auto &chunk : _chunks) { + // Compute and set the offset of the chunk in the output file. + _imageSizeOnDisk = + llvm::RoundUpToAlignment(_imageSizeOnDisk, chunk->align()); + chunk->setFileOffset(_imageSizeOnDisk); + _imageSizeOnDisk += chunk->size(); + } +} + +void ExecutableWriter::setAddressOfEntryPoint(TextSectionChunk *text, + PEHeaderChunk *peHeader) { + // Find the virtual address of the entry point symbol if any. + // PECOFF spec says that entry point for dll images is optional, in which + // case it must be set to 0. + if (_PECOFFLinkingContext.entrySymbolName().empty() && + _PECOFFLinkingContext.getImageType() == PECOFFLinkingContext::IMAGE_DLL) { + peHeader->setAddressOfEntryPoint(0); + } else { + uint64_t entryPointAddress = + text->getAtomVirtualAddress(_PECOFFLinkingContext.entrySymbolName()); + if (entryPointAddress != 0) + peHeader->setAddressOfEntryPoint(entryPointAddress); + } +} + +uint64_t ExecutableWriter::calcSectionSize( + llvm::COFF::SectionCharacteristics sectionType) { + uint64_t ret = 0; + for (auto &cp : _chunks) + if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp)) + if (chunk->getSectionCharacteristics() & sectionType) + ret += chunk->size(); + return ret; +} + } // end namespace pecoff std::unique_ptr<Writer> createWriterPECOFF(const PECOFFLinkingContext &info) { |

