| Index: courgette/assembly_program.cc
|
| diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc
|
| index f1502a9ee324e956f034578b1776e9afc3aa29fd..1eb267a0c1696a1e6b8b86af3fc36da0c33abdd2 100644
|
| --- a/courgette/assembly_program.cc
|
| +++ b/courgette/assembly_program.cc
|
| @@ -21,93 +21,286 @@ namespace courgette {
|
|
|
| namespace {
|
|
|
| -// Sets the current address for the emitting instructions.
|
| -class OriginInstruction : public Instruction {
|
| +// AssemblyProgram stores a sequence of instructions. The main uses are:
|
| +// - Serialization (write): InstructionStoreReceptor::Emit*() produces and
|
| +// serializes instructions into AssemblyProgram::instruction_raw_data_.
|
| +// - Encode (read): AssemblyProgram::Encode() iterates over serialized
|
| +// instructions and sends them to EncodedProgram.
|
| +// - Label extraction (read): AssemblyProgram::HandleInstructionLabels()
|
| +// iterates over serialized instructions and process only instructions with
|
| +// Labels.
|
| +
|
| +/******** Instruction ********/
|
| +
|
| +// Each instruction type (AssemblyOp::OP) has a corresponding class, and these
|
| +// classes have a common base class (Instruction). To simplify serialization,
|
| +// we want to write entire objects into buffer using pointer casting. However,
|
| +// the naive approach has 2 problems:
|
| +// (1) C++ struct can add padding, which wastes space.
|
| +// (2) Virtual function usage adds bloat to object size.
|
| +// Problem (1) is solved using #pragma pack() directives. Problem 2 is solved
|
| +// by decoupling storage (Data* structs) from behavior (Instruction* classes).
|
| +
|
| +// Instruction interfaces that don't use templates. Instead of directly storing
|
| +// data, Instruction provides a "view" into a provided buffer, and keeps a
|
| +// "cursor" pointer to access the data. The base interface is only used by
|
| +// "read" use cases (encode & label extraction).
|
| +class Instruction {
|
| public:
|
| - explicit OriginInstruction(RVA rva) : Instruction(ORIGIN, 0), rva_(rva) {}
|
| - RVA origin_rva() const { return rva_; }
|
| + Instruction() = default;
|
| + virtual ~Instruction() = default;
|
| +
|
| +// All data payload for inherited classes of Instruction.
|
| +#pragma pack(push, 1)
|
| + // If we nest these classes then we won't be able to use initializer list.
|
| + struct Data {
|
| + AssemblyOp::OP op;
|
| + };
|
| +
|
| + struct DataWithRVA {
|
| + AssemblyOp::OP op;
|
| + RVA rva;
|
| + };
|
| +
|
| + struct DataWithExecutableType {
|
| + AssemblyOp::OP op;
|
| + ExecutableType exe_type;
|
| + };
|
| +
|
| + struct DataWithByte {
|
| + AssemblyOp::OP op;
|
| + uint8_t byte;
|
| + };
|
| +
|
| + struct DataWithBytesAndSize {
|
| + AssemblyOp::OP op;
|
| + const uint8_t* bytes;
|
| + serialized_size_t size;
|
| + };
|
| +
|
| + struct DataWithLabel {
|
| + AssemblyOp::OP op;
|
| + Label* label;
|
| + };
|
| +
|
| + struct DataWithLabelAndARMRel32 {
|
| + AssemblyOp::OP op;
|
| + Label* label;
|
| + uint16_t compressed_op;
|
| + const uint8_t* arm_op; // TODO(huangs): Looks unused? Remove.
|
| + uint16_t op_size; // TODO(huangs): Looks unused? Remove.
|
| + };
|
| +#pragma pack(pop)
|
| +
|
| + // Getters for basic info.
|
| + virtual AssemblyOp::OP GetOp() const = 0;
|
| + virtual size_t GetSize() const = 0;
|
| +
|
| + // If the instruction located at |it| has a Label, returns it. Otherwise
|
| + // returns null.
|
| + virtual Label* ReadLabel(AssemblyRawDataVector::const_iterator it) const {
|
| + return nullptr;
|
| + }
|
| +
|
| + // Sends the instruction to |encoded|, possibly using config from |prog|.
|
| + virtual bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const = 0;
|
| +
|
| private:
|
| - RVA rva_;
|
| + DISALLOW_COPY_AND_ASSIGN(Instruction);
|
| };
|
|
|
| -// Emits an entire PE base relocation table.
|
| -class PeRelocsInstruction : public Instruction {
|
| - public:
|
| - PeRelocsInstruction() : Instruction(MAKEPERELOCS) {}
|
| -};
|
| +/******** InstructionImpl ********/
|
|
|
| -// Emits an ELF relocation table.
|
| -class ElfRelocsInstruction : public Instruction {
|
| +// Intermediate Instruction class using templates.
|
| +template <int OP_USE, typename DATA_T>
|
| +class InstructionImpl : public Instruction {
|
| public:
|
| - ElfRelocsInstruction() : Instruction(MAKEELFRELOCS) {}
|
| -};
|
| + using This = InstructionImpl<OP_USE, DATA_T>;
|
| +
|
| + static constexpr AssemblyOp::OP kOpUse = static_cast<AssemblyOp::OP>(OP_USE);
|
| + static constexpr size_t kSize = sizeof(DATA_T);
|
| +
|
| + InstructionImpl() {}
|
| + ~InstructionImpl() override = default;
|
| +
|
| + // Instruction:
|
| + AssemblyOp::OP GetOp() const override { return kOpUse; }
|
| + size_t GetSize() const override { return kSize; }
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override = 0;
|
| +
|
| + // Allocates space at end of |raw_data|, and writes |data_in| there.
|
| + CheckBool Serialize(AssemblyRawDataVector* raw_data, DATA_T data_in) {
|
| + size_t pos = raw_data->size();
|
| + if (!raw_data->resize(pos + kSize, 0))
|
| + return false;
|
| + DCHECK(pos + sizeof(DATA_T) <= raw_data->size());
|
| + *reinterpret_cast<DATA_T*>(&(*raw_data)[pos]) = data_in;
|
| + return true;
|
| + }
|
|
|
| -// Emits an ELF ARM relocation table.
|
| -class ElfARMRelocsInstruction : public Instruction {
|
| - public:
|
| - ElfARMRelocsInstruction() : Instruction(MAKEELFARMRELOCS) {}
|
| + protected:
|
| + const DATA_T* SeekRead(AssemblyRawDataVector::const_iterator it) const {
|
| + return reinterpret_cast<const DATA_T*>(&(*it));
|
| + }
|
| };
|
|
|
| -// Emits a single byte.
|
| -class ByteInstruction : public Instruction {
|
| - public:
|
| - explicit ByteInstruction(uint8_t value) : Instruction(DEFBYTE, value) {}
|
| - uint8_t byte_value() const { return info_; }
|
| +/******** InstructionWithLabel ********/
|
| +
|
| +// Common code for the "Label extraction" use case.
|
| +template <int OP_USE, typename DATA_T>
|
| +class InstructionWithLabel : public InstructionImpl<OP_USE, DATA_T> {
|
| + // Instruction:
|
| + Label* ReadLabel(AssemblyRawDataVector::const_iterator it) const override {
|
| + return SeekRead(it)->label;
|
| + }
|
| };
|
|
|
| -// Emits a single byte.
|
| -class BytesInstruction : public Instruction {
|
| - public:
|
| - BytesInstruction(const uint8_t* values, size_t len)
|
| - : Instruction(DEFBYTES, 0), values_(values), len_(len) {}
|
| - const uint8_t* byte_values() const { return values_; }
|
| - size_t len() const { return len_; }
|
| +/******** Instruction*, one for each AssemblyOp:OP value ********/
|
|
|
| - private:
|
| - const uint8_t* values_;
|
| - size_t len_;
|
| +struct InstructionMakePERelocs
|
| + : public InstructionImpl<AssemblyOp::MAKEPERELOCS,
|
| + Instruction::DataWithExecutableType> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + return encoded->AddPeMakeRelocs(SeekRead(it)->exe_type);
|
| + }
|
| + static InstructionMakePERelocs instance;
|
| };
|
| +InstructionMakePERelocs InstructionMakePERelocs::instance;
|
|
|
| -// A ABS32 to REL32 instruction emits a reference to a label's address.
|
| -class InstructionWithLabel : public Instruction {
|
| - public:
|
| - InstructionWithLabel(OP op, Label* label)
|
| - : Instruction(op, 0), label_(label) {
|
| - if (label == NULL) NOTREACHED();
|
| +struct InstructionMakeELFRelocs
|
| + : public InstructionImpl<AssemblyOp::MAKEELFRELOCS, Instruction::Data> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + return encoded->AddElfMakeRelocs();
|
| }
|
| - Label* label() const { return label_; }
|
| - protected:
|
| - Label* label_;
|
| + static InstructionMakeELFRelocs instance;
|
| };
|
| +InstructionMakeELFRelocs InstructionMakeELFRelocs::instance;
|
|
|
| -// An ARM REL32 instruction emits a reference to a label's address and
|
| -// a specially-compressed ARM op.
|
| -class InstructionWithLabelARM : public InstructionWithLabel {
|
| - public:
|
| - InstructionWithLabelARM(OP op,
|
| - uint16_t compressed_op,
|
| - Label* label,
|
| - const uint8_t* arm_op,
|
| - uint16_t op_size)
|
| - : InstructionWithLabel(op, label),
|
| - compressed_op_(compressed_op),
|
| - arm_op_(arm_op),
|
| - op_size_(op_size) {
|
| - if (label == NULL) NOTREACHED();
|
| - }
|
| - uint16_t compressed_op() const { return compressed_op_; }
|
| - const uint8_t* arm_op() const { return arm_op_; }
|
| - uint16_t op_size() const { return op_size_; }
|
| +struct InstructionMakeELFARMRelocs
|
| + : public InstructionImpl<AssemblyOp::MAKEELFARMRELOCS, Instruction::Data> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + return encoded->AddElfARMMakeRelocs();
|
| + }
|
| + static InstructionMakeELFARMRelocs instance;
|
| +};
|
| +InstructionMakeELFARMRelocs InstructionMakeELFARMRelocs::instance;
|
|
|
| - private:
|
| - uint16_t compressed_op_;
|
| - const uint8_t* arm_op_;
|
| - uint16_t op_size_;
|
| +struct InstructionOrigin
|
| + : public InstructionImpl<AssemblyOp::ORIGIN, Instruction::DataWithRVA> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + return encoded->AddOrigin(SeekRead(it)->rva);
|
| + }
|
| + static InstructionOrigin instance;
|
| +};
|
| +InstructionOrigin InstructionOrigin::instance;
|
| +
|
| +struct InstructionSingleByte
|
| + : public InstructionImpl<AssemblyOp::SINGLEBYTE,
|
| + Instruction::DataWithByte> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + return encoded->AddCopy(1, &SeekRead(it)->byte);
|
| + }
|
| + static InstructionSingleByte instance;
|
| +};
|
| +InstructionSingleByte InstructionSingleByte::instance;
|
| +
|
| +struct InstructionMultipleBytes
|
| + : public InstructionImpl<AssemblyOp::MULTIPLEBYTES,
|
| + Instruction::DataWithBytesAndSize> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + const auto* cursor = SeekRead(it);
|
| + return encoded->AddCopy(cursor->size, cursor->bytes);
|
| + }
|
| + static InstructionMultipleBytes instance;
|
| +};
|
| +InstructionMultipleBytes InstructionMultipleBytes::instance;
|
| +
|
| +struct InstructionRel32
|
| + : public InstructionWithLabel<AssemblyOp::REL32,
|
| + Instruction::DataWithLabel> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + return encoded->AddRel32(SeekRead(it)->label->index_);
|
| + }
|
| + static InstructionRel32 instance;
|
| +};
|
| +InstructionRel32 InstructionRel32::instance;
|
| +
|
| +struct InstructionRel32ARM
|
| + : public InstructionWithLabel<AssemblyOp::REL32ARM,
|
| + Instruction::DataWithLabelAndARMRel32> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + const auto* cursor = SeekRead(it);
|
| + return encoded->AddRel32ARM(cursor->compressed_op, cursor->label->index_);
|
| + }
|
| + static InstructionRel32ARM instance;
|
| };
|
| +InstructionRel32ARM InstructionRel32ARM::instance;
|
| +
|
| +struct InstructionAbs32
|
| + : public InstructionWithLabel<AssemblyOp::ABS32,
|
| + Instruction::DataWithLabel> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + return encoded->AddAbs32(SeekRead(it)->label->index_);
|
| + }
|
| + static InstructionAbs32 instance;
|
| +};
|
| +InstructionAbs32 InstructionAbs32::instance;
|
| +
|
| +struct InstructionAbs64
|
| + : public InstructionWithLabel<AssemblyOp::ABS64,
|
| + Instruction::DataWithLabel> {
|
| + bool Encode(AssemblyRawDataVector::const_iterator it,
|
| + EncodedProgram* encoded) const override {
|
| + return encoded->AddAbs64(SeekRead(it)->label->index_);
|
| + }
|
| + static InstructionAbs64 instance;
|
| +};
|
| +InstructionAbs64 InstructionAbs64::instance;
|
| +
|
| +/******** Utility Functions ********/
|
| +
|
| +// A collection of reusable Instruction instances.
|
| +Instruction* FindInstruction(AssemblyOp::OP op) {
|
| + switch (op) {
|
| + case InstructionOrigin::kOpUse:
|
| + return &InstructionOrigin::instance;
|
| + case InstructionMakePERelocs::kOpUse:
|
| + return &InstructionMakePERelocs::instance;
|
| + case InstructionMakeELFRelocs::kOpUse:
|
| + return &InstructionMakeELFRelocs::instance;
|
| + case InstructionSingleByte::kOpUse:
|
| + return &InstructionSingleByte::instance;
|
| + case InstructionRel32::kOpUse:
|
| + return &InstructionRel32::instance;
|
| + case InstructionAbs32::kOpUse:
|
| + return &InstructionAbs32::instance;
|
| + case InstructionRel32ARM::kOpUse:
|
| + return &InstructionRel32ARM::instance;
|
| + case InstructionMakeELFARMRelocs::kOpUse:
|
| + return &InstructionMakeELFARMRelocs::instance;
|
| + case InstructionMultipleBytes::kOpUse:
|
| + return &InstructionMultipleBytes::instance;
|
| + case InstructionAbs64::kOpUse:
|
| + return &InstructionAbs64::instance;
|
| + }
|
| + NOTREACHED();
|
| + return nullptr;
|
| +}
|
|
|
| /******** InstructionCountReceptor ********/
|
|
|
| -// An InstructionReceptor that counts space occupied by emitted instructions.
|
| +// An InstructionReceptor to count space occupied by emitted instructions.
|
| class InstructionCountReceptor : public InstructionReceptor {
|
| public:
|
| InstructionCountReceptor() = default;
|
| @@ -115,26 +308,35 @@ class InstructionCountReceptor : public InstructionReceptor {
|
| size_t size() const { return size_; }
|
|
|
| // InstructionReceptor:
|
| - // TODO(huangs): 2016/11: Populate these with size_ += ...
|
| - CheckBool EmitPeRelocs() override { return true; }
|
| - CheckBool EmitElfRelocation() override { return true; }
|
| - CheckBool EmitElfARMRelocation() override { return true; }
|
| - CheckBool EmitOrigin(RVA rva) override { return true; }
|
| - CheckBool EmitSingleByte(uint8_t byte) override { return true; }
|
| - CheckBool EmitMultipleBytes(const uint8_t* bytes, size_t len) override {
|
| - return true;
|
| + CheckBool EmitPeRelocs() { return Add<InstructionMakePERelocs>(); }
|
| + CheckBool EmitElfRelocation() { return Add<InstructionMakeELFRelocs>(); }
|
| + CheckBool EmitElfARMRelocation() {
|
| + return Add<InstructionMakeELFARMRelocs>();
|
| + }
|
| + CheckBool EmitOrigin(RVA rva) { return Add<InstructionOrigin>(); }
|
| + CheckBool EmitSingleByte(uint8_t byte) {
|
| + return Add<InstructionSingleByte>();
|
| }
|
| - CheckBool EmitRel32(Label* label) override { return true; }
|
| - CheckBool EmitRel32ARM(uint16_t op,
|
| + CheckBool EmitMultipleBytes(const uint8_t* bytes, size_t len) {
|
| + return Add<InstructionMultipleBytes>();
|
| + }
|
| + CheckBool EmitRel32(Label* label) { return Add<InstructionRel32>(); }
|
| + CheckBool EmitRel32ARM(uint16_t compressed_op,
|
| Label* label,
|
| const uint8_t* arm_op,
|
| - uint16_t op_size) override {
|
| - return true;
|
| + uint16_t op_size) {
|
| + return Add<InstructionRel32ARM>();
|
| }
|
| - CheckBool EmitAbs32(Label* label) override { return true; }
|
| - CheckBool EmitAbs64(Label* label) override { return true; }
|
| + CheckBool EmitAbs32(Label* label) { return Add<InstructionAbs32>(); }
|
| + CheckBool EmitAbs64(Label* label) { return Add<InstructionAbs64>(); }
|
|
|
| private:
|
| + template <typename T>
|
| + inline bool Add() {
|
| + size_ += T::kSize;
|
| + return true;
|
| + }
|
| +
|
| size_t size_ = 0;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(InstructionCountReceptor);
|
| @@ -142,50 +344,67 @@ class InstructionCountReceptor : public InstructionReceptor {
|
|
|
| /******** InstructionStoreReceptor ********/
|
|
|
| -// An InstructionReceptor that stores emitted instructions.
|
| +// An InstructionReceptor to store emitted instructions.
|
| class InstructionStoreReceptor : public InstructionReceptor {
|
| public:
|
| - explicit InstructionStoreReceptor(AssemblyProgram* program)
|
| - : program_(program) {
|
| - CHECK(program_);
|
| - }
|
| -
|
| - // TODO(huangs): 2016/11: Add Reserve().
|
| + InstructionStoreReceptor(ExecutableType exe_type,
|
| + AssemblyRawDataVector* raw_data)
|
| + : exe_type_(exe_type), raw_data_(raw_data) {}
|
|
|
| // InstructionReceptor:
|
| - // TODO(huangs): 2016/11: Replace stub with implementation.
|
| - CheckBool EmitPeRelocs() override { return program_->EmitPeRelocs(); }
|
| - CheckBool EmitElfRelocation() override {
|
| - return program_->EmitElfRelocation();
|
| + CheckBool EmitPeRelocs() {
|
| + InstructionMakePERelocs instr;
|
| + return instr.Serialize(raw_data_, {instr.GetOp(), exe_type_});
|
| + }
|
| + CheckBool EmitElfRelocation() {
|
| + InstructionMakeELFRelocs instr;
|
| + return instr.Serialize(raw_data_, {instr.GetOp()});
|
| }
|
| - CheckBool EmitElfARMRelocation() override {
|
| - return program_->EmitElfARMRelocation();
|
| + CheckBool EmitElfARMRelocation() {
|
| + InstructionMakeELFARMRelocs instr;
|
| + return instr.Serialize(raw_data_, {instr.GetOp()});
|
| }
|
| - CheckBool EmitOrigin(RVA rva) override { return program_->EmitOrigin(rva); }
|
| - CheckBool EmitSingleByte(uint8_t byte) override {
|
| - return program_->EmitSingleByte(byte);
|
| + CheckBool EmitOrigin(RVA rva) {
|
| + InstructionOrigin instr;
|
| + return instr.Serialize(raw_data_, {instr.GetOp(), rva});
|
| }
|
| - CheckBool EmitMultipleBytes(const uint8_t* bytes, size_t len) override {
|
| - return program_->EmitMultipleBytes(bytes, len);
|
| + CheckBool EmitSingleByte(uint8_t byte) {
|
| + InstructionSingleByte instr;
|
| + return instr.Serialize(raw_data_, {instr.GetOp(), byte});
|
| }
|
| - CheckBool EmitRel32(Label* label) override {
|
| - return program_->EmitRel32(label);
|
| + CheckBool EmitMultipleBytes(const uint8_t* bytes, size_t len) {
|
| + InstructionMultipleBytes instr;
|
| + return instr.Serialize(
|
| + raw_data_, {instr.GetOp(), bytes, static_cast<serialized_size_t>(len)});
|
| }
|
| - CheckBool EmitRel32ARM(uint16_t op,
|
| + CheckBool EmitRel32(Label* label) {
|
| + InstructionRel32 instr;
|
| + return instr.Serialize(raw_data_, {instr.GetOp(), label});
|
| + }
|
| + CheckBool EmitRel32ARM(uint16_t compressed_op,
|
| Label* label,
|
| const uint8_t* arm_op,
|
| - uint16_t op_size) override {
|
| - return program_->EmitRel32ARM(op, label, arm_op, op_size);
|
| + uint16_t op_size) {
|
| + InstructionRel32ARM instr;
|
| + // Note that |label| is moved before |compressed_op|.
|
| + return instr.Serialize(
|
| + raw_data_, {instr.GetOp(), label, compressed_op, arm_op, op_size});
|
| }
|
| - CheckBool EmitAbs32(Label* label) override {
|
| - return program_->EmitAbs32(label);
|
| + CheckBool EmitAbs32(Label* label) {
|
| + InstructionAbs32 instr;
|
| + return instr.Serialize(raw_data_, {instr.GetOp(), label});
|
| }
|
| - CheckBool EmitAbs64(Label* label) override {
|
| - return program_->EmitAbs64(label);
|
| + CheckBool EmitAbs64(Label* label) {
|
| + InstructionAbs64 instr;
|
| + return instr.Serialize(raw_data_, {instr.GetOp(), label});
|
| }
|
|
|
| private:
|
| - AssemblyProgram* program_;
|
| + // Executable type for PE relocation.
|
| + const ExecutableType exe_type_;
|
| +
|
| + // Storage of raw instruction data, owned by this instance's owner.
|
| + AssemblyRawDataVector* raw_data_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(InstructionStoreReceptor);
|
| };
|
| @@ -194,68 +413,7 @@ class InstructionStoreReceptor : public InstructionReceptor {
|
|
|
| /******** AssemblyProgram ********/
|
|
|
| -AssemblyProgram::AssemblyProgram(ExecutableType kind)
|
| - : kind_(kind), image_base_(0) {
|
| -}
|
| -
|
| -AssemblyProgram::~AssemblyProgram() {
|
| - for (size_t i = 0; i < instructions_.size(); ++i) {
|
| - Instruction* instruction = instructions_[i];
|
| - if (instruction->op() != DEFBYTE) // Owned by byte_instruction_cache_.
|
| - UncheckedDelete(instruction);
|
| - }
|
| - if (byte_instruction_cache_.get()) {
|
| - for (size_t i = 0; i < 256; ++i)
|
| - UncheckedDelete(byte_instruction_cache_[i]);
|
| - }
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitPeRelocs() {
|
| - return Emit(ScopedInstruction(UncheckedNew<PeRelocsInstruction>()));
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitElfRelocation() {
|
| - return Emit(ScopedInstruction(UncheckedNew<ElfRelocsInstruction>()));
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitElfARMRelocation() {
|
| - return Emit(ScopedInstruction(UncheckedNew<ElfARMRelocsInstruction>()));
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitOrigin(RVA rva) {
|
| - return Emit(ScopedInstruction(UncheckedNew<OriginInstruction>(rva)));
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitSingleByte(uint8_t byte) {
|
| - return EmitShared(GetByteInstruction(byte));
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitMultipleBytes(const uint8_t* bytes, size_t len) {
|
| - return Emit(ScopedInstruction(UncheckedNew<BytesInstruction>(bytes, len)));
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitRel32(Label* label) {
|
| - return Emit(
|
| - ScopedInstruction(UncheckedNew<InstructionWithLabel>(REL32, label)));
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitRel32ARM(uint16_t op,
|
| - Label* label,
|
| - const uint8_t* arm_op,
|
| - uint16_t op_size) {
|
| - return Emit(ScopedInstruction(UncheckedNew<InstructionWithLabelARM>(
|
| - REL32ARM, op, label, arm_op, op_size)));
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitAbs32(Label* label) {
|
| - return Emit(
|
| - ScopedInstruction(UncheckedNew<InstructionWithLabel>(ABS32, label)));
|
| -}
|
| -
|
| -CheckBool AssemblyProgram::EmitAbs64(Label* label) {
|
| - return Emit(
|
| - ScopedInstruction(UncheckedNew<InstructionWithLabel>(ABS64, label)));
|
| -}
|
| +AssemblyProgram::AssemblyProgram(ExecutableType kind) : kind_(kind) {}
|
|
|
| void AssemblyProgram::PrecomputeLabels(RvaVisitor* abs32_visitor,
|
| RvaVisitor* rel32_visitor) {
|
| @@ -305,40 +463,45 @@ Label* AssemblyProgram::FindRel32Label(RVA rva) {
|
|
|
| void AssemblyProgram::HandleInstructionLabels(
|
| const AssemblyProgram::LabelHandlerMap& handler_map) const {
|
| - for (const Instruction* instruction : instructions_) {
|
| - LabelHandlerMap::const_iterator it = handler_map.find(instruction->op());
|
| - if (it != handler_map.end()) {
|
| - it->second.Run(
|
| - static_cast<const InstructionWithLabel*>(instruction)->label());
|
| + auto it = instruction_raw_data_.begin();
|
| + auto end = instruction_raw_data_.end();
|
| + while (it < end) {
|
| + // Get the instruction from the operation.
|
| + AssemblyOp::OP op = static_cast<AssemblyOp::OP>(*it);
|
| + Instruction* instr = FindInstruction(op);
|
| + DCHECK_LE(it + instr->GetSize(), end);
|
| +
|
| + // If Label exists and is handled, then handle it.
|
| + Label* label = instr->ReadLabel(it);
|
| + if (label) {
|
| + LabelHandlerMap::const_iterator label_it = handler_map.find(op);
|
| + if (label_it != handler_map.end())
|
| + label_it->second.Run(label);
|
| }
|
| + it += instr->GetSize();
|
| }
|
| }
|
|
|
| CheckBool AssemblyProgram::GenerateInstructions(
|
| const InstructionGenerator& gen) {
|
| + CHECK(instruction_raw_data_.empty());
|
| +
|
| // Pass 1: Count the space needed to store instructions.
|
| InstructionCountReceptor count_receptor;
|
| if (!gen.Run(this, &count_receptor))
|
| return false;
|
|
|
| - // Pass 2: Emit all instructions to preallocated buffer (uses Phase 1 count).
|
| - InstructionStoreReceptor store_receptor(this);
|
| - // TODO(huangs): 2016/11: Pass |count_receptor_->size()| to |store_receptor_|
|
| - // to reserve space for raw data.
|
| - return gen.Run(this, &store_receptor);
|
| -}
|
| + // Reserve space for raw data, using count from Phase 1.
|
| + if (!instruction_raw_data_.reserve(count_receptor.size()))
|
| + return false;
|
|
|
| -CheckBool AssemblyProgram::Emit(ScopedInstruction instruction) {
|
| - if (!instruction || !instructions_.push_back(instruction.get()))
|
| + // Pass 2: Emit all instructions to preallocated buffer (uses Phase 1 count).
|
| + InstructionStoreReceptor store_receptor(kind(), &instruction_raw_data_);
|
| + if (!gen.Run(this, &store_receptor))
|
| return false;
|
| - // Ownership successfully passed to instructions_.
|
| - ignore_result(instruction.release());
|
| - return true;
|
| -}
|
|
|
| -CheckBool AssemblyProgram::EmitShared(Instruction* instruction) {
|
| - DCHECK(!instruction || instruction->op() == DEFBYTE);
|
| - return instruction && instructions_.push_back(instruction);
|
| + CHECK_EQ(count_receptor.size(), instruction_raw_data_.size());
|
| + return true;
|
| }
|
|
|
| void AssemblyProgram::UnassignIndexes(RVAToLabel* labels) {
|
| @@ -367,7 +530,7 @@ void AssemblyProgram::AssignRemainingIndexes(RVAToLabel* labels) {
|
| // An address table compresses best when each index is associated with an
|
| // address that is slight larger than the previous index.
|
|
|
| - // First see which indexes have not been used. The 'available' vector could
|
| + // First see which indexes have not been used. The 'available' vector could
|
| // grow even bigger, but the number of addresses is a better starting size
|
| // than empty.
|
| std::vector<bool> available(labels->size(), true);
|
| @@ -458,106 +621,20 @@ std::unique_ptr<EncodedProgram> AssemblyProgram::Encode() const {
|
| if (!encoded->ImportLabels(abs32_label_manager_, rel32_label_manager_))
|
| return nullptr;
|
|
|
| - for (size_t i = 0; i < instructions_.size(); ++i) {
|
| - Instruction* instruction = instructions_[i];
|
| + auto it = instruction_raw_data_.begin();
|
| + auto end = instruction_raw_data_.end();
|
| + while (it < end) {
|
| + // Get the instruction from the operation.
|
| + AssemblyOp::OP op = static_cast<AssemblyOp::OP>(*it);
|
| + Instruction* instr = FindInstruction(op);
|
| + DCHECK_LE(it + instr->GetSize(), end);
|
|
|
| - switch (instruction->op()) {
|
| - case ORIGIN: {
|
| - OriginInstruction* org = static_cast<OriginInstruction*>(instruction);
|
| - if (!encoded->AddOrigin(org->origin_rva()))
|
| - return nullptr;
|
| - break;
|
| - }
|
| - case DEFBYTE: {
|
| - uint8_t b = static_cast<ByteInstruction*>(instruction)->byte_value();
|
| - if (!encoded->AddCopy(1, &b))
|
| - return nullptr;
|
| - break;
|
| - }
|
| - case DEFBYTES: {
|
| - const uint8_t* byte_values =
|
| - static_cast<BytesInstruction*>(instruction)->byte_values();
|
| - size_t len = static_cast<BytesInstruction*>(instruction)->len();
|
| -
|
| - if (!encoded->AddCopy(len, byte_values))
|
| - return nullptr;
|
| - break;
|
| - }
|
| - case REL32: {
|
| - Label* label = static_cast<InstructionWithLabel*>(instruction)->label();
|
| - if (!encoded->AddRel32(label->index_))
|
| - return nullptr;
|
| - break;
|
| - }
|
| - case REL32ARM: {
|
| - Label* label =
|
| - static_cast<InstructionWithLabelARM*>(instruction)->label();
|
| - uint16_t compressed_op =
|
| - static_cast<InstructionWithLabelARM*>(instruction)->compressed_op();
|
| - if (!encoded->AddRel32ARM(compressed_op, label->index_))
|
| - return nullptr;
|
| - break;
|
| - }
|
| - case ABS32: {
|
| - Label* label = static_cast<InstructionWithLabel*>(instruction)->label();
|
| - if (!encoded->AddAbs32(label->index_))
|
| - return nullptr;
|
| - break;
|
| - }
|
| - case ABS64: {
|
| - Label* label = static_cast<InstructionWithLabel*>(instruction)->label();
|
| - if (!encoded->AddAbs64(label->index_))
|
| - return nullptr;
|
| - break;
|
| - }
|
| - case MAKEPERELOCS: {
|
| - if (!encoded->AddPeMakeRelocs(kind_))
|
| - return nullptr;
|
| - break;
|
| - }
|
| - case MAKEELFRELOCS: {
|
| - if (!encoded->AddElfMakeRelocs())
|
| - return nullptr;
|
| - break;
|
| - }
|
| - case MAKEELFARMRELOCS: {
|
| - if (!encoded->AddElfARMMakeRelocs())
|
| - return nullptr;
|
| - break;
|
| - }
|
| - default: {
|
| - NOTREACHED() << "Unknown Insn OP kind";
|
| - }
|
| - }
|
| + instr->Encode(it, encoded.get());
|
| + it += instr->GetSize();
|
| }
|
| -
|
| return encoded;
|
| }
|
|
|
| -Instruction* AssemblyProgram::GetByteInstruction(uint8_t byte) {
|
| - if (!byte_instruction_cache_) {
|
| - Instruction** ram = nullptr;
|
| - if (!base::UncheckedMalloc(sizeof(Instruction*) * 256,
|
| - reinterpret_cast<void**>(&ram))) {
|
| - return nullptr;
|
| - }
|
| - byte_instruction_cache_.reset(ram);
|
| -
|
| - for (int i = 0; i < 256; ++i) {
|
| - byte_instruction_cache_[i] =
|
| - UncheckedNew<ByteInstruction>(static_cast<uint8_t>(i));
|
| - if (!byte_instruction_cache_[i]) {
|
| - for (int j = 0; j < i; ++j)
|
| - UncheckedDelete(byte_instruction_cache_[j]);
|
| - byte_instruction_cache_.reset();
|
| - return nullptr;
|
| - }
|
| - }
|
| - }
|
| -
|
| - return byte_instruction_cache_[byte];
|
| -}
|
| -
|
| ////////////////////////////////////////////////////////////////////////////////
|
|
|
| Status Encode(const AssemblyProgram& program,
|
|
|