Index: courgette/assembly_program.cc |
diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc |
index 531b6850730f4466fbbabde16d7e7ce74bc829e4..58c16b4a0235fa83dd7339ee3515415df74db648 100644 |
--- a/courgette/assembly_program.cc |
+++ b/courgette/assembly_program.cc |
@@ -2,111 +2,31 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <stddef.h> |
+ |
#include "courgette/assembly_program.h" |
-#include "base/callback.h" |
#include "base/logging.h" |
-#include "courgette/courgette.h" |
-#include "courgette/disassembler.h" |
#include "courgette/encoded_program.h" |
+#include "courgette/instruction_utils.h" |
namespace courgette { |
namespace { |
-// Sets the current address for the emitting instructions. |
-class OriginInstruction : public Instruction { |
- public: |
- explicit OriginInstruction(RVA rva) : Instruction(ORIGIN, 0), rva_(rva) {} |
- RVA origin_rva() const { return rva_; } |
- private: |
- RVA rva_; |
-}; |
- |
-// Emits an entire PE base relocation table. |
-class PeRelocsInstruction : public Instruction { |
- public: |
- PeRelocsInstruction() : Instruction(MAKEPERELOCS) {} |
-}; |
- |
-// Emits an ELF relocation table. |
-class ElfRelocsInstruction : public Instruction { |
+// An instruction receptor that adds each received abs32/rel32 Label* to the |
+// matching VECTOR member variable. Template VECTOR allows code reuse for |
+// counting (CountingVector) and storage (std::vector). |
+template <template <typename T, typename... Args> class CONTAINER> |
+class LabelReceptor : public InstructionReceptor { |
public: |
- ElfRelocsInstruction() : Instruction(MAKEELFRELOCS) {} |
-}; |
+ using VECTOR = CONTAINER<Label*>; |
-// Emits an ELF ARM relocation table. |
-class ElfARMRelocsInstruction : public Instruction { |
- public: |
- ElfARMRelocsInstruction() : Instruction(MAKEELFARMRELOCS) {} |
-}; |
+ LabelReceptor() = default; |
+ ~LabelReceptor() override = default; |
-// Emits a single byte. |
-class ByteInstruction : public Instruction { |
- public: |
- explicit ByteInstruction(uint8_t value) : Instruction(DEFBYTE, value) {} |
- uint8_t byte_value() const { return info_; } |
-}; |
- |
-// 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_; } |
- |
- private: |
- const uint8_t* values_; |
- size_t len_; |
-}; |
- |
-// 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(); |
- } |
- Label* label() const { return label_; } |
- protected: |
- Label* label_; |
-}; |
- |
-// 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_; } |
- |
- private: |
- uint16_t compressed_op_; |
- const uint8_t* arm_op_; |
- uint16_t op_size_; |
-}; |
- |
-/******** InstructionCountReceptor ********/ |
- |
-// An InstructionReceptor that counts space occupied by emitted instructions. |
-class InstructionCountReceptor : public InstructionReceptor { |
- public: |
- InstructionCountReceptor() = default; |
- |
- size_t abs_count() const { return abs_count_; } |
- size_t rel_count() const { return rel_count_; } |
+ VECTOR* mutable_abs32_vector() { return &abs32_vector_; } |
+ VECTOR* mutable_rel32_vector() { return &rel32_vector_; } |
// InstructionReceptor: |
CheckBool EmitPeRelocs() override { return true; } |
@@ -118,156 +38,38 @@ class InstructionCountReceptor : public InstructionReceptor { |
return true; |
} |
CheckBool EmitRel32(Label* label) override { |
- ++rel_count_; |
+ rel32_vector_.push_back(label); |
return true; |
} |
CheckBool EmitRel32ARM(uint16_t op, |
Label* label, |
const uint8_t* arm_op, |
uint16_t op_size) override { |
- ++rel_count_; |
+ rel32_vector_.push_back(label); |
return true; |
} |
CheckBool EmitAbs32(Label* label) override { |
- ++abs_count_; |
+ abs32_vector_.push_back(label); |
return true; |
} |
CheckBool EmitAbs64(Label* label) override { |
- ++abs_count_; |
+ abs32_vector_.push_back(label); |
return true; |
} |
private: |
- size_t abs_count_ = 0; |
- size_t rel_count_ = 0; |
- |
- DISALLOW_COPY_AND_ASSIGN(InstructionCountReceptor); |
-}; |
- |
-/******** InstructionStoreReceptor ********/ |
- |
-// An InstructionReceptor that stores emitted instructions. |
-class InstructionStoreReceptor : public InstructionReceptor { |
- public: |
- InstructionStoreReceptor(AssemblyProgram* program, bool annotate_labels) |
- : program_(program), annotate_labels_(annotate_labels) { |
- CHECK(program_); |
- } |
- |
- // TODO(huangs): 2017/04: Add Reserve(). |
- |
- // InstructionReceptor: |
- // TODO(huangs): 2017/04: Move implementations here. |
- CheckBool EmitPeRelocs() override { return program_->EmitPeRelocs(); } |
- CheckBool EmitElfRelocation() override { |
- return program_->EmitElfRelocation(); |
- } |
- CheckBool EmitElfARMRelocation() override { |
- return program_->EmitElfARMRelocation(); |
- } |
- CheckBool EmitOrigin(RVA rva) override { return program_->EmitOrigin(rva); } |
- CheckBool EmitSingleByte(uint8_t byte) override { |
- return program_->EmitSingleByte(byte); |
- } |
- CheckBool EmitMultipleBytes(const uint8_t* bytes, size_t len) override { |
- return program_->EmitMultipleBytes(bytes, len); |
- } |
- CheckBool EmitRel32(Label* label) override { |
- if (annotate_labels_) |
- program_->mutable_rel32_label_annotations()->push_back(label); |
- return program_->EmitRel32(label); |
- } |
- CheckBool EmitRel32ARM(uint16_t op, |
- Label* label, |
- const uint8_t* arm_op, |
- uint16_t op_size) override { |
- if (annotate_labels_) |
- program_->mutable_rel32_label_annotations()->push_back(label); |
- return program_->EmitRel32ARM(op, label, arm_op, op_size); |
- } |
- CheckBool EmitAbs32(Label* label) override { |
- if (annotate_labels_) |
- program_->mutable_abs32_label_annotations()->push_back(label); |
- return program_->EmitAbs32(label); |
- } |
- CheckBool EmitAbs64(Label* label) override { |
- if (annotate_labels_) |
- program_->mutable_abs32_label_annotations()->push_back(label); |
- return program_->EmitAbs64(label); |
- } |
- |
- private: |
- AssemblyProgram* program_; |
- const bool annotate_labels_; |
+ VECTOR abs32_vector_; |
+ VECTOR rel32_vector_; |
- DISALLOW_COPY_AND_ASSIGN(InstructionStoreReceptor); |
+ DISALLOW_COPY_AND_ASSIGN(LabelReceptor); |
}; |
} // namespace |
-/******** AssemblyProgram ********/ |
- |
AssemblyProgram::AssemblyProgram(ExecutableType kind, uint64_t image_base) |
: kind_(kind), image_base_(image_base) {} |
-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() = default; |
void AssemblyProgram::PrecomputeLabels(RvaVisitor* abs32_visitor, |
RvaVisitor* rel32_visitor) { |
@@ -315,157 +117,30 @@ Label* AssemblyProgram::FindRel32Label(RVA rva) { |
return rel32_label_manager_.Find(rva); |
} |
-CheckBool AssemblyProgram::GenerateInstructions(const InstructionGenerator& gen, |
- bool annotate_labels) { |
- // Pass 1: Count storage space required and reserve in advance. |
- InstructionCountReceptor count_receptor; |
+CheckBool AssemblyProgram::AnnotateLabels(const InstructionGenerator& gen) { |
+ // Pass 1: Compute required space. |
+ LabelReceptor<CountingVector> count_receptor; |
if (!gen.Run(&count_receptor)) |
return false; |
- if (annotate_labels) { |
- DCHECK(abs32_label_annotations_.empty()); |
- abs32_label_annotations_.reserve(count_receptor.abs_count()); |
- DCHECK(rel32_label_annotations_.empty()); |
- rel32_label_annotations_.reserve(count_receptor.rel_count()); |
- } |
- |
- // Pass 2: Emit all instructions to reserved buffer (uses Phase 1 count). |
- // Populates |abs32_label_annotations_| and |re32_label_annotations_| if |
- // |annotate_labels| is true. |
- InstructionStoreReceptor store_receptor(this, annotate_labels); |
- return gen.Run(&store_receptor); |
-} |
- |
-CheckBool AssemblyProgram::Emit(ScopedInstruction instruction) { |
- if (!instruction || !instructions_.push_back(instruction.get())) |
+ // Pass 2: Reserve and store annotations. |
+ LabelReceptor<std::vector> annotate_receptor; |
+ annotate_receptor.mutable_abs32_vector()->reserve( |
+ count_receptor.mutable_abs32_vector()->size()); |
+ annotate_receptor.mutable_rel32_vector()->reserve( |
+ count_receptor.mutable_rel32_vector()->size()); |
+ if (!gen.Run(&annotate_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); |
+ // Move results to |abs32_label_annotations_| and |re32_label_annotations_|. |
+ abs32_label_annotations_.swap(*annotate_receptor.mutable_abs32_vector()); |
+ rel32_label_annotations_.swap(*annotate_receptor.mutable_rel32_vector()); |
+ return true; |
} |
-std::unique_ptr<EncodedProgram> AssemblyProgram::Encode() const { |
- std::unique_ptr<EncodedProgram> encoded(new EncodedProgram()); |
- |
+bool AssemblyProgram::PrepareEncodedProgram(EncodedProgram* encoded) const { |
encoded->set_image_base(image_base_); |
- |
- if (!encoded->ImportLabels(abs32_label_manager_, rel32_label_manager_)) |
- return nullptr; |
- |
- for (size_t i = 0; i < instructions_.size(); ++i) { |
- Instruction* instruction = instructions_[i]; |
- |
- 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"; |
- } |
- } |
- } |
- |
- 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, |
- std::unique_ptr<EncodedProgram>* output) { |
- // Explicitly release any memory associated with the output before encoding. |
- output->reset(); |
- |
- *output = program.Encode(); |
- return (*output) ? C_OK : C_GENERAL_ERROR; |
+ return encoded->ImportLabels(abs32_label_manager_, rel32_label_manager_); |
} |
} // namespace courgette |