// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "courgette/assembly_program.h" #include #include #include #include #include #include "base/logging.h" #include "base/macros.h" #include "courgette/courgette.h" #include "courgette/encoded_program.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 { public: ElfRelocsInstruction() : Instruction(MAKEELFRELOCS) {} }; // Emits an ELF ARM relocation table. class ElfARMRelocsInstruction : public Instruction { public: ElfARMRelocsInstruction() : Instruction(MAKEELFARMRELOCS) {} }; // 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_; }; } // namespace AssemblyProgram::AssemblyProgram(ExecutableType kind) : kind_(kind), image_base_(0) { } static void DeleteContainedLabels(const RVAToLabel& labels) { for (RVAToLabel::const_iterator p = labels.begin(); p != labels.end(); ++p) UncheckedDelete(p->second); } 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]); } DeleteContainedLabels(rel32_labels_); DeleteContainedLabels(abs32_labels_); } CheckBool AssemblyProgram::EmitPeRelocsInstruction() { return Emit(ScopedInstruction(UncheckedNew())); } CheckBool AssemblyProgram::EmitElfRelocationInstruction() { return Emit(ScopedInstruction(UncheckedNew())); } CheckBool AssemblyProgram::EmitElfARMRelocationInstruction() { return Emit(ScopedInstruction(UncheckedNew())); } CheckBool AssemblyProgram::EmitOriginInstruction(RVA rva) { return Emit(ScopedInstruction(UncheckedNew(rva))); } CheckBool AssemblyProgram::EmitByteInstruction(uint8_t byte) { return EmitShared(GetByteInstruction(byte)); } CheckBool AssemblyProgram::EmitBytesInstruction(const uint8_t* values, size_t len) { return Emit(ScopedInstruction(UncheckedNew(values, len))); } CheckBool AssemblyProgram::EmitRel32(Label* label) { return Emit( ScopedInstruction(UncheckedNew(REL32, label))); } CheckBool AssemblyProgram::EmitRel32ARM(uint16_t op, Label* label, const uint8_t* arm_op, uint16_t op_size) { return Emit(ScopedInstruction(UncheckedNew( REL32ARM, op, label, arm_op, op_size))); } CheckBool AssemblyProgram::EmitAbs32(Label* label) { return Emit( ScopedInstruction(UncheckedNew(ABS32, label))); } CheckBool AssemblyProgram::EmitAbs64(Label* label) { return Emit( ScopedInstruction(UncheckedNew(ABS64, label))); } Label* AssemblyProgram::FindOrMakeAbs32Label(RVA rva) { return FindLabel(rva, &abs32_labels_); } Label* AssemblyProgram::FindOrMakeRel32Label(RVA rva) { return FindLabel(rva, &rel32_labels_); } void AssemblyProgram::DefaultAssignIndexes() { DefaultAssignIndexes(&abs32_labels_); DefaultAssignIndexes(&rel32_labels_); } void AssemblyProgram::UnassignIndexes() { UnassignIndexes(&abs32_labels_); UnassignIndexes(&rel32_labels_); } void AssemblyProgram::AssignRemainingIndexes() { AssignRemainingIndexes(&abs32_labels_); AssignRemainingIndexes(&rel32_labels_); } Label* AssemblyProgram::InstructionAbs32Label( const Instruction* instruction) const { if (instruction->op() == ABS32) return static_cast(instruction)->label(); return NULL; } Label* AssemblyProgram::InstructionAbs64Label( const Instruction* instruction) const { if (instruction->op() == ABS64) return static_cast(instruction)->label(); return NULL; } Label* AssemblyProgram::InstructionRel32Label( const Instruction* instruction) const { if (instruction->op() == REL32 || instruction->op() == REL32ARM) { Label* label = static_cast(instruction)->label(); return label; } return NULL; } CheckBool AssemblyProgram::Emit(ScopedInstruction instruction) { if (!instruction || !instructions_.push_back(instruction.get())) 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); } Label* AssemblyProgram::FindLabel(RVA rva, RVAToLabel* labels) { Label*& slot = (*labels)[rva]; if (slot == NULL) { slot = UncheckedNew