Index: third_party/courgette/assembly_program.cc |
=================================================================== |
--- third_party/courgette/assembly_program.cc (revision 15668) |
+++ third_party/courgette/assembly_program.cc (working copy) |
@@ -1,373 +0,0 @@ |
-// Copyright (c) 2009 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 "third_party/courgette/assembly_program.h" |
- |
-#include <memory.h> |
-#include <algorithm> |
-#include <map> |
-#include <set> |
-#include <sstream> |
-#include <vector> |
- |
-#include "base/logging.h" |
- |
-#include "third_party/courgette/courgette.h" |
-#include "third_party/courgette/encoded_program.h" |
- |
-namespace courgette { |
- |
-// Opcodes of simple assembly language |
-enum OP { |
- ORIGIN, // ORIGIN <rva> - set current address for assembly. |
- MAKERELOCS, // Generates a base relocation table. |
- DEFBYTE, // DEFBYTE <value> - emit a byte literal. |
- REL32, // REL32 <label> - emit a rel32 encoded reference to 'label'. |
- ABS32, // REL32 <label> - emit am abs32 encoded reference to 'label'. |
- LAST_OP |
-}; |
- |
-// Base class for instructions. Because we have so many instructions we want to |
-// keep them as small as possible. For this reason we avoid virtual functions. |
-// |
-class Instruction { |
- public: |
- OP op() const { return static_cast<OP>(op_); } |
- |
- protected: |
- explicit Instruction(OP op) : op_(op), info_(0) {} |
- Instruction(OP op, unsigned int info) : op_(op), info_(info) {} |
- |
- uint32 op_ : 4; // A few bits to store the OP code. |
- uint32 info_ : 28; // Remaining bits in first word available to subclass. |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(Instruction); |
-}; |
- |
-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 base relocation table. |
-class MakeRelocsInstruction : public Instruction { |
- public: |
- MakeRelocsInstruction() : Instruction(MAKERELOCS) {} |
-}; |
- |
-// Emits a single byte. |
-class ByteInstruction : public Instruction { |
- public: |
- explicit ByteInstruction(uint8 value) : Instruction(DEFBYTE, value) {} |
- uint8 byte_value() const { return info_; } |
-}; |
- |
-// 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_; } |
- private: |
- Label* label_; |
-}; |
- |
-} // namespace |
- |
-AssemblyProgram::AssemblyProgram() |
- : image_base_(0), |
- byte_instruction_cache_(NULL) { |
-} |
- |
-static void DeleteContainedLabels(const RVAToLabel& labels) { |
- for (RVAToLabel::const_iterator p = labels.begin(); p != labels.end(); ++p) |
- delete p->second; |
-} |
- |
-AssemblyProgram::~AssemblyProgram() { |
- for (size_t i = 0; i < instructions_.size(); ++i) { |
- Instruction* instruction = instructions_[i]; |
- if (instruction->op() != DEFBYTE) // Will be in byte_instruction_cache_. |
- delete instruction; |
- } |
- if (byte_instruction_cache_) { |
- for (size_t i = 0; i < 256; ++i) |
- delete byte_instruction_cache_[i]; |
- delete[] byte_instruction_cache_; |
- } |
- DeleteContainedLabels(rel32_labels_); |
- DeleteContainedLabels(abs32_labels_); |
-} |
- |
-void AssemblyProgram::EmitMakeRelocsInstruction() { |
- Emit(new MakeRelocsInstruction()); |
-} |
- |
-void AssemblyProgram::EmitOriginInstruction(RVA rva) { |
- Emit(new OriginInstruction(rva)); |
-} |
- |
-void AssemblyProgram::EmitByteInstruction(uint8 byte) { |
- Emit(GetByteInstruction(byte)); |
-} |
- |
-void AssemblyProgram::EmitRel32(Label* label) { |
- Emit(new InstructionWithLabel(REL32, label)); |
-} |
- |
-void AssemblyProgram::EmitAbs32(Label* label) { |
- Emit(new InstructionWithLabel(ABS32, 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<const InstructionWithLabel*>(instruction)->label(); |
- return NULL; |
-} |
- |
-Label* AssemblyProgram::InstructionRel32Label( |
- const Instruction* instruction) const { |
- if (instruction->op() == REL32) |
- return static_cast<const InstructionWithLabel*>(instruction)->label(); |
- return NULL; |
-} |
- |
-Label* AssemblyProgram::FindLabel(RVA rva, RVAToLabel* labels) { |
- Label*& slot = (*labels)[rva]; |
- if (slot == 0) { |
- slot = new Label(rva); |
- } |
- return slot; |
-} |
- |
-void AssemblyProgram::UnassignIndexes(RVAToLabel* labels) { |
- for (RVAToLabel::iterator p = labels->begin(); p != labels->end(); ++p) { |
- Label* current = p->second; |
- current->index_ = Label::kNoIndex; |
- } |
-} |
- |
-// DefaultAssignIndexes takes a set of labels and assigns indexes in increasing |
-// address order. |
-// |
-void AssemblyProgram::DefaultAssignIndexes(RVAToLabel* labels) { |
- int index = 0; |
- for (RVAToLabel::iterator p = labels->begin(); p != labels->end(); ++p) { |
- Label* current = p->second; |
- if (current->index_ != Label::kNoIndex) |
- NOTREACHED(); |
- current->index_ = index; |
- ++index; |
- } |
-} |
- |
-// AssignRemainingIndexes assigns indexes to any addresses (labels) that are not |
-// yet assigned an index. |
-// |
-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 |
- // grow even bigger, but the number of addresses is a better starting size |
- // than empty. |
- std::vector<bool> available(labels->size(), true); |
- int used = 0; |
- |
- for (RVAToLabel::iterator p = labels->begin(); p != labels->end(); ++p) { |
- size_t index = p->second->index_; |
- if (index != Label::kNoIndex) { |
- while (index >= available.size()) |
- available.push_back(true); |
- available.at(index) = false; |
- ++used; |
- } |
- } |
- |
- LOG(INFO) << used << " of " << labels->size() << " labels pre-assigned"; |
- |
- // Are there any unused labels that happen to be adjacent following a used |
- // label? |
- // |
- int fill_forward_count = 0; |
- Label* prev = 0; |
- for (RVAToLabel::iterator p = labels->begin(); p != labels->end(); ++p) { |
- Label* current = p->second; |
- if (current->index_ == Label::kNoIndex) { |
- size_t index = 0; |
- if (prev && prev->index_ != Label::kNoIndex) |
- index = prev->index_ + 1; |
- if (index < available.size() && available.at(index)) { |
- current->index_ = index; |
- available.at(index) = false; |
- ++fill_forward_count; |
- } |
- } |
- prev = current; |
- } |
- |
- // Are there any unused labels that happen to be adjacent preceeding a used |
- // label? |
- // |
- int fill_backward_count = 0; |
- int backward_refs = 0; |
- prev = 0; |
- for (RVAToLabel::reverse_iterator p = labels->rbegin(); |
- p != labels->rend(); |
- ++p) { |
- Label* current = p->second; |
- if (current->index_ == Label::kNoIndex) { |
- int prev_index; |
- if (prev) |
- prev_index = prev->index_; |
- else |
- prev_index = available.size(); |
- if (prev_index != 0 && |
- prev_index != Label::kNoIndex && |
- available.at(prev_index - 1)) { |
- current->index_ = prev_index - 1; |
- available.at(current->index_) = false; |
- ++fill_backward_count; |
- } |
- } |
- prev = current; |
- } |
- |
- // Fill in any remaining indexes |
- int fill_infill_count = 0; |
- int index = 0; |
- for (RVAToLabel::iterator p = labels->begin(); p != labels->end(); ++p) { |
- Label* current = p->second; |
- if (current->index_ == Label::kNoIndex) { |
- while (!available.at(index)) { |
- ++index; |
- } |
- current->index_ = index; |
- available.at(index) = false; |
- ++index; |
- ++fill_infill_count; |
- } |
- } |
- |
- LOG(INFO) << " fill" |
- << " forward " << fill_forward_count << " " |
- << " backward " << fill_backward_count << " " |
- << " infill " << fill_infill_count; |
-} |
- |
-typedef void (EncodedProgram::*DefineLabelMethod)(int index, RVA value); |
- |
-static void DefineLabels(const RVAToLabel& labels, |
- EncodedProgram* encoded_format, |
- DefineLabelMethod define_label) { |
- for (RVAToLabel::const_iterator p = labels.begin(); p != labels.end(); ++p) { |
- Label* label = p->second; |
- (encoded_format->*define_label)(label->index_, label->rva_); |
- } |
-} |
- |
-EncodedProgram* AssemblyProgram::Encode() const { |
- EncodedProgram* encoded = new EncodedProgram(); |
- |
- encoded->set_image_base(image_base_); |
- DefineLabels(abs32_labels_, encoded, &EncodedProgram::DefineAbs32Label); |
- DefineLabels(rel32_labels_, encoded, &EncodedProgram::DefineRel32Label); |
- encoded->EndLabels(); |
- |
- for (size_t i = 0; i < instructions_.size(); ++i) { |
- Instruction* instruction = instructions_[i]; |
- |
- switch (instruction->op()) { |
- case ORIGIN: { |
- OriginInstruction* org = static_cast<OriginInstruction*>(instruction); |
- encoded->AddOrigin(org->origin_rva()); |
- break; |
- } |
- case DEFBYTE: { |
- uint8 b = static_cast<ByteInstruction*>(instruction)->byte_value(); |
- encoded->AddCopy(1, &b); |
- break; |
- } |
- case REL32: { |
- Label* label = static_cast<InstructionWithLabel*>(instruction)->label(); |
- encoded->AddRel32(label->index_); |
- break; |
- } |
- case ABS32: { |
- Label* label = static_cast<InstructionWithLabel*>(instruction)->label(); |
- encoded->AddAbs32(label->index_); |
- break; |
- } |
- case MAKERELOCS: { |
- encoded->AddMakeRelocs(); |
- break; |
- } |
- default: { |
- NOTREACHED() << "Unknown Insn OP kind"; |
- } |
- } |
- } |
- |
- return encoded; |
-} |
- |
-Instruction* AssemblyProgram::GetByteInstruction(uint8 byte) { |
- if (!byte_instruction_cache_) { |
- byte_instruction_cache_ = new Instruction*[256]; |
- for (int i = 0; i < 256; ++i) { |
- byte_instruction_cache_[i] = new ByteInstruction(static_cast<uint8>(i)); |
- } |
- } |
- |
- return byte_instruction_cache_[byte]; |
-} |
- |
-//////////////////////////////////////////////////////////////////////////////// |
- |
-Status Encode(AssemblyProgram* program, EncodedProgram** output) { |
- *output = NULL; |
- EncodedProgram *encoded = program->Encode(); |
- if (encoded) { |
- *output = encoded; |
- return C_OK; |
- } else { |
- return C_GENERAL_ERROR; |
- } |
-} |
- |
-} // namespace courgette |
- |