<commit_before>//===- lib/ReaderWriter/PECOFF/WriterPECOFF.cpp ---------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// PE/COFF file consists of DOS Header, PE Header, COFF Header and Section
/// Tables followed by raw section data.
///
/// This writer is responsible for writing Core Linker results to an Windows
/// executable file.
///
/// This writer currently supports 32 bit PE/COFF for x86 processor only.
///
//===----------------------------------------------------------------------===//

#include "Atoms.h"
#include "WriterImportLibrary.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/Writer.h"
#include "lld/ReaderWriter/AtomLayout.h"
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Format.h"
#include <algorithm>
#include <cstdlib>
#include <map>
#include <time.h>
#include <vector>

#define DEBUG_TYPE "WriterPECOFF"

using llvm::COFF::DataDirectoryIndex;
using llvm::object::coff_runtime_function_x64;
using llvm::support::ulittle16_t;
using llvm::support::ulittle32_t;
using llvm::support::ulittle64_t;

namespace lld {
namespace pecoff {

// Disk sector size. Some data needs to be aligned at disk sector boundary in
// file.
static const int SECTOR_SIZE = 512;

namespace {
class SectionChunk;

/// A Chunk is an abstract contiguous range in an output file.
class Chunk {
public:
  enum Kind {
    kindHeader,
    kindSection,
    kindStringTable,
    kindAtomChunk
  };

  explicit Chunk(Kind kind) : _kind(kind), _size(0) {}
  virtual ~Chunk() {}
  virtual void write(uint8_t *buffer) = 0;
  virtual uint64_t size() const { return _size; }
  virtual uint64_t onDiskSize() const { return size(); }
  virtual uint64_t align() const { return 1; }

  uint64_t fileOffset() const { return _fileOffset; }
  void setFileOffset(uint64_t fileOffset) { _fileOffset = fileOffset; }
  Kind getKind() const { return _kind; }

protected:
  Kind _kind;
  uint64_t _size;
  uint64_t _fileOffset;
};

/// A HeaderChunk is an abstract class to represent a file header for
/// PE/COFF. The data in the header chunk is metadata about program and will
/// be consumed by the windows loader. HeaderChunks are not mapped to memory
/// when executed.
class HeaderChunk : public Chunk {
public:
  HeaderChunk() : Chunk(kindHeader) {}

  static bool classof(const Chunk *c) { return c->getKind() == kindHeader; }
};

/// A DOSStubChunk represents the DOS compatible header at the beginning
/// of PE/COFF files.
class DOSStubChunk : public HeaderChunk {
public:
  explicit DOSStubChunk(const PECOFFLinkingContext &ctx)
      : HeaderChunk(), _context(ctx) {
    // Minimum size of DOS stub is 64 bytes. The next block (PE header) needs to
    // be aligned on 8 byte boundary.
    size_t size = std::max(_context.getDosStub().size(), (size_t)64);
    _size = llvm::RoundUpToAlignment(size, 8);
  }

  void write(uint8_t *buffer) override {
    ArrayRef<uint8_t> array = _context.getDosStub();
    std::memcpy(buffer, array.data(), array.size());
    auto *header = reinterpret_cast<llvm::object::dos_header *>(buffer);
    header->AddressOfRelocationTable = sizeof(llvm::object::dos_header);
    header->AddressOfNewExeHeader = _size;
  }

private:
  const PECOFFLinkingContext &_context;
};

/// A PEHeaderChunk represents PE header including COFF header.
template <class PEHeader>
class PEHeaderChunk : public HeaderChunk {
public:
  explicit PEHeaderChunk(const PECOFFLinkingContext &ctx);

  void write(uint8_t *buffer) override;

  void setSizeOfHeaders(uint64_t size) {
    // Must be multiple of FileAlignment.
    _peHeader.SizeOfHeaders = llvm::RoundUpToAlignment(size, SECTOR_SIZE);
  }

  void setSizeOfCode(uint64_t size) { _peHeader.SizeOfCode = size; }
  void setBaseOfCode(uint32_t rva) { _peHeader.BaseOfCode = rva; }
  void setBaseOfData(uint32_t rva);
  void setSizeOfImage(uint32_t size) { _peHeader.SizeOfImage = size; }

  void setSizeOfInitializedData(uint64_t size) {
    _peHeader.SizeOfInitializedData = size;
  }

  void setSizeOfUninitializedData(uint64_t size) {
    _peHeader.SizeOfUninitializedData = size;
  }

  void setNumberOfSections(uint32_t num) { _coffHeader.NumberOfSections = num; }
  void setNumberOfSymbols(uint32_t num) { _coffHeader.NumberOfSymbols = num; }

  void setAddressOfEntryPoint(uint32_t address) {
    _peHeader.AddressOfEntryPoint = address;
  }

  void setPointerToSymbolTable(uint32_t rva) {
    _coffHeader.PointerToSymbolTable = rva;
  }

private:
  llvm::object::coff_file_header _coffHeader;
  PEHeader _peHeader;
};

/// A SectionHeaderTableChunk represents Section Table Header of PE/COFF
/// format, which is a list of section headers.
class SectionHeaderTableChunk : public HeaderChunk {
public:
  SectionHeaderTableChunk() : HeaderChunk() {}
  void addSection(SectionChunk *chunk);
  uint64_t size() const override;
  void write(uint8_t *buffer) override;

private:
  static llvm::object::coff_section createSectionHeader(SectionChunk *chunk);

  std::vector<SectionChunk *> _sections;
};

class StringTableChunk : public Chunk {
public:
  StringTableChunk() : Chunk(kindStringTable) {}

  static bool classof(const Chunk *c) {
    return c->getKind() == kindStringTable;
  }

  uint32_t addSectionName(StringRef sectionName) {
    if (_stringTable.empty()) {
      // The string table immediately follows the symbol table.
      // We don't really need a symbol table, but some tools (e.g. dumpbin)
      // don't like zero-length symbol table.
      // Make room for the empty symbol slot, which occupies 18 byte.
      // We also need to reserve 4 bytes for the string table header.
      int size = sizeof(llvm::object::coff_symbol16) + 4;
      _stringTable.insert(_stringTable.begin(), size, 0);
    }
    uint32_t offset = _stringTable.size();
    _stringTable.insert(_stringTable.end(), sectionName.begin(),
                        sectionName.end());
    _stringTable.push_back('\0');
    return offset - sizeof(llvm::object::coff_symbol16);
  }

  uint64_t size() const override { return _stringTable.size(); }

  void write(uint8_t *buffer) override {
    if (_stringTable.empty())
      return;
    char *off = _stringTable.data() + sizeof(llvm::object::coff_symbol16);
    *reinterpret_cast<ulittle32_t *>(off) = _stringTable.size();
    std::memcpy(buffer, _stringTable.data(), _stringTable.size());
  }

private:<commit_msg>PECOFF: Fix dummy symbol table in executable.<commit_after>//===- lib/ReaderWriter/PECOFF/WriterPECOFF.cpp ---------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// PE/COFF file consists of DOS Header, PE Header, COFF Header and Section
/// Tables followed by raw section data.
///
/// This writer is responsible for writing Core Linker results to an Windows
/// executable file.
///
/// This writer currently supports 32 bit PE/COFF for x86 processor only.
///
//===----------------------------------------------------------------------===//

#include "Atoms.h"
#include "WriterImportLibrary.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/Writer.h"
#include "lld/ReaderWriter/AtomLayout.h"
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Format.h"
#include <algorithm>
#include <cstdlib>
#include <map>
#include <time.h>
#include <vector>

#define DEBUG_TYPE "WriterPECOFF"

using llvm::COFF::DataDirectoryIndex;
using llvm::object::coff_runtime_function_x64;
using llvm::support::ulittle16_t;
using llvm::support::ulittle32_t;
using llvm::support::ulittle64_t;

namespace lld {
namespace pecoff {

// Disk sector size. Some data needs to be aligned at disk sector boundary in
// file.
static const int SECTOR_SIZE = 512;

namespace {
class SectionChunk;

/// A Chunk is an abstract contiguous range in an output file.
class Chunk {
public:
  enum Kind {
    kindHeader,
    kindSection,
    kindStringTable,
    kindAtomChunk
  };

  explicit Chunk(Kind kind) : _kind(kind), _size(0) {}
  virtual ~Chunk() {}
  virtual void write(uint8_t *buffer) = 0;
  virtual uint64_t size() const { return _size; }
  virtual uint64_t onDiskSize() const { return size(); }
  virtual uint64_t align() const { return 1; }

  uint64_t fileOffset() const { return _fileOffset; }
  void setFileOffset(uint64_t fileOffset) { _fileOffset = fileOffset; }
  Kind getKind() const { return _kind; }

protected:
  Kind _kind;
  uint64_t _size;
  uint64_t _fileOffset;
};

/// A HeaderChunk is an abstract class to represent a file header for
/// PE/COFF. The data in the header chunk is metadata about program and will
/// be consumed by the windows loader. HeaderChunks are not mapped to memory
/// when executed.
class HeaderChunk : public Chunk {
public:
  HeaderChunk() : Chunk(kindHeader) {}

  static bool classof(const Chunk *c) { return c->getKind() == kindHeader; }
};

/// A DOSStubChunk represents the DOS compatible header at the beginning
/// of PE/COFF files.
class DOSStubChunk : public HeaderChunk {
public:
  explicit DOSStubChunk(const PECOFFLinkingContext &ctx)
      : HeaderChunk(), _context(ctx) {
    // Minimum size of DOS stub is 64 bytes. The next block (PE header) needs to
    // be aligned on 8 byte boundary.
    size_t size = std::max(_context.getDosStub().size(), (size_t)64);
    _size = llvm::RoundUpToAlignment(size, 8);
  }

  void write(uint8_t *buffer) override {
    ArrayRef<uint8_t> array = _context.getDosStub();
    std::memcpy(buffer, array.data(), array.size());
    auto *header = reinterpret_cast<llvm::object::dos_header *>(buffer);
    header->AddressOfRelocationTable = sizeof(llvm::object::dos_header);
    header->AddressOfNewExeHeader = _size;
  }

private:
  const PECOFFLinkingContext &_context;
};

/// A PEHeaderChunk represents PE header including COFF header.
template <class PEHeader>
class PEHeaderChunk : public HeaderChunk {
public:
  explicit PEHeaderChunk(const PECOFFLinkingContext &ctx);

  void write(uint8_t *buffer) override;

  void setSizeOfHeaders(uint64_t size) {
    // Must be multiple of FileAlignment.
    _peHeader.SizeOfHeaders = llvm::RoundUpToAlignment(size, SECTOR_SIZE);
  }

  void setSizeOfCode(uint64_t size) { _peHeader.SizeOfCode = size; }
  void setBaseOfCode(uint32_t rva) { _peHeader.BaseOfCode = rva; }
  void setBaseOfData(uint32_t rva);
  void setSizeOfImage(uint32_t size) { _peHeader.SizeOfImage = size; }

  void setSizeOfInitializedData(uint64_t size) {
    _peHeader.SizeOfInitializedData = size;
  }

  void setSizeOfUninitializedData(uint64_t size) {
    _peHeader.SizeOfUninitializedData = size;
  }

  void setNumberOfSections(uint32_t num) { _coffHeader.NumberOfSections = num; }
  void setNumberOfSymbols(uint32_t num) { _coffHeader.NumberOfSymbols = num; }

  void setAddressOfEntryPoint(uint32_t address) {
    _peHeader.AddressOfEntryPoint = address;
  }

  void setPointerToSymbolTable(uint32_t rva) {
    _coffHeader.PointerToSymbolTable = rva;
  }

private:
  llvm::object::coff_file_header _coffHeader;
  PEHeader _peHeader;
};

/// A SectionHeaderTableChunk represents Section Table Header of PE/COFF
/// format, which is a list of section headers.
class SectionHeaderTableChunk : public HeaderChunk {
public:
  SectionHeaderTableChunk() : HeaderChunk() {}
  void addSection(SectionChunk *chunk);
  uint64_t size() const override;
  void write(uint8_t *buffer) override;

private:
  static llvm::object::coff_section createSectionHeader(SectionChunk *chunk);

  std::vector<SectionChunk *> _sections;
};

class StringTableChunk : public Chunk {
public:
  StringTableChunk() : Chunk(kindStringTable) {}

  static bool classof(const Chunk *c) {
    return c->getKind() == kindStringTable;
  }

  uint32_t addSectionName(StringRef sectionName) {
    if (_stringTable.empty()) {
      // The string table immediately follows the symbol table.
      // We don't really need a symbol table, but some tools (e.g. dumpbin)
      // don't like zero-length symbol table.
      // Make room for the empty symbol slot, which occupies 18 byte.
      // We also need to reserve 4 bytes for the string table header.
      int size = sizeof(llvm::object::coff_symbol16) + 4;
      _stringTable.insert(_stringTable.begin(), size, 0);
      // Set the name of the dummy symbol to the first string table entry.
      // It's better than letting dumpbin print out a garabage as a symbol name.
      char *off = _stringTable.data() + 4;
      *reinterpret_cast<ulittle32_t *>(off) = 4;
    }
    uint32_t offset = _stringTable.size();
    _stringTable.insert(_stringTable.end(), sectionName.begin(),
                        sectionName.end());
    _stringTable.push_back('\0');
    return offset - sizeof(llvm::object::coff_symbol16);
  }

  uint64_t size() const override { return _stringTable.size(); }

  void write(uint8_t *buffer) override {
    if (_stringTable.empty())
      return;
    char *off = _stringTable.data() + sizeof(llvm::object::coff_symbol16);
    *reinterpret_cast<ulittle32_t *>(off) = _stringTable.size();
    std::memcpy(buffer, _stringTable.data(), _stringTable.size());
  }

private:
{'fraction_non_alphanumeric': 0.1366742596810934, 'fraction_numerical': 0.012813211845102505, 'mean_word_length': 3.5866797257590597, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '398950', 'n_tokens_mistral': 4482, 'n_tokens_neox': 4350, 'n_words': 1208}