1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef BERBERIS_ASSEMBLER_COMMON_H_ 18 #define BERBERIS_ASSEMBLER_COMMON_H_ 19 20 #include <stdint.h> 21 22 #include <string> 23 #include <utility> 24 25 #include "berberis/assembler/machine_code.h" 26 #include "berberis/base/arena_alloc.h" 27 #include "berberis/base/arena_vector.h" 28 #include "berberis/base/logging.h" 29 #include "berberis/base/macros.h" // DISALLOW_IMPLICIT_CONSTRUCTORS 30 31 namespace berberis { 32 33 class AssemblerBase { 34 public: AssemblerBase(MachineCode * code)35 explicit AssemblerBase(MachineCode* code) : jumps_(code->arena()), code_(code) {} 36 ~AssemblerBase()37 ~AssemblerBase() {} 38 39 class Label { 40 public: Label()41 Label() : position_(kInvalid) {} 42 43 // Label position is offset from the start of MachineCode 44 // where it is bound to. position()45 uint32_t position() const { return position_; } 46 Bind(uint32_t position)47 void Bind(uint32_t position) { 48 CHECK(!IsBound()); 49 position_ = position; 50 } 51 IsBound()52 bool IsBound() const { return position_ != kInvalid; } 53 54 protected: 55 static const uint32_t kInvalid = 0xffffffff; 56 uint32_t position_; 57 58 private: 59 DISALLOW_COPY_AND_ASSIGN(Label); 60 }; 61 pc()62 uint32_t pc() const { return code_->code_offset(); } 63 64 // Macro operations. Emit8(uint8_t v)65 void Emit8(uint8_t v) { code_->AddU8(v); } 66 Emit16(int16_t v)67 void Emit16(int16_t v) { code_->Add<int16_t>(v); } 68 Emit32(int32_t v)69 void Emit32(int32_t v) { code_->Add<int32_t>(v); } 70 Emit64(int64_t v)71 void Emit64(int64_t v) { code_->Add<int64_t>(v); } 72 73 template <typename T> EmitSequence(const T * v,uint32_t count)74 void EmitSequence(const T* v, uint32_t count) { 75 code_->AddSequence(v, sizeof(T) * count); 76 } 77 Bind(Label * label)78 void Bind(Label* label) { label->Bind(pc()); } 79 MakeLabel()80 Label* MakeLabel() { return NewInArena<Label>(code_->arena()); } 81 SetRecoveryPoint(Label * recovery_label)82 void SetRecoveryPoint(Label* recovery_label) { 83 jumps_.push_back(Jump{recovery_label, pc(), true}); 84 } 85 86 protected: 87 template <typename T> AddrAs(uint32_t offset)88 T* AddrAs(uint32_t offset) { 89 return code_->AddrAs<T>(offset); 90 } 91 AddRelocation(uint32_t dst,RelocationType type,uint32_t pc,intptr_t data)92 void AddRelocation(uint32_t dst, RelocationType type, uint32_t pc, intptr_t data) { 93 code_->AddRelocation(dst, type, pc, data); 94 } 95 96 // These are 'static' relocations, resolved when code is finalized. 97 // We also have 'dynamic' relocations, resolved when code is installed. 98 struct Jump { 99 const Label* label; 100 // Position of field to store offset. Note: unless it's recovery label precomputed 101 // "distance from the end of instruction" is stored there. 102 // 103 // This is needed because we keep pointer to the rip-offset field while value stored 104 // there is counted from the end of instruction (on x86) or, sometimes, from the end 105 // of next instruction (ARM). 106 uint32_t pc; 107 bool is_recovery; 108 }; 109 typedef ArenaVector<Jump> JumpList; 110 JumpList jumps_; 111 112 private: 113 MachineCode* code_; 114 115 DISALLOW_IMPLICIT_CONSTRUCTORS(AssemblerBase); 116 }; 117 118 } // namespace berberis 119 120 #endif // BERBERIS_ASSEMBLER_COMMON_H_ 121