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, |