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 // GNU-assembler inspired names: https://sourceware.org/binutils/docs-2.42/as.html#g_t8byte 65 template <typename... Args> Byte(Args...args)66 void Byte(Args... args) { 67 static_assert((std::is_same_v<Args, uint8_t> && ...)); 68 (Emit8(args), ...); 69 } 70 71 template <typename... Args> TwoByte(Args...args)72 void TwoByte(Args... args) { 73 static_assert((std::is_same_v<Args, uint16_t> && ...)); 74 (Emit16(args), ...); 75 } 76 77 template <typename... Args> FourByte(Args...args)78 void FourByte(Args... args) { 79 static_assert((std::is_same_v<Args, uint32_t> && ...)); 80 (Emit32(args), ...); 81 } 82 83 template <typename... Args> EigthByte(Args...args)84 void EigthByte(Args... args) { 85 static_assert((std::is_same_v<Args, uint64_t> && ...)); 86 (Emit64(args), ...); 87 } 88 89 // Macro operations. Emit8(uint8_t v)90 void Emit8(uint8_t v) { code_->AddU8(v); } 91 Emit16(int16_t v)92 void Emit16(int16_t v) { code_->Add<int16_t>(v); } 93 Emit32(int32_t v)94 void Emit32(int32_t v) { code_->Add<int32_t>(v); } 95 Emit64(int64_t v)96 void Emit64(int64_t v) { code_->Add<int64_t>(v); } 97 98 template <typename T> EmitSequence(const T * v,uint32_t count)99 void EmitSequence(const T* v, uint32_t count) { 100 code_->AddSequence(v, sizeof(T) * count); 101 } 102 Bind(Label * label)103 void Bind(Label* label) { label->Bind(pc()); } 104 MakeLabel()105 Label* MakeLabel() { return NewInArena<Label>(code_->arena()); } 106 SetRecoveryPoint(Label * recovery_label)107 void SetRecoveryPoint(Label* recovery_label) { 108 jumps_.push_back(Jump{recovery_label, pc(), true}); 109 } 110 111 protected: 112 template <typename T> AddrAs(uint32_t offset)113 T* AddrAs(uint32_t offset) { 114 return code_->AddrAs<T>(offset); 115 } 116 AddRelocation(uint32_t dst,RelocationType type,uint32_t pc,intptr_t data)117 void AddRelocation(uint32_t dst, RelocationType type, uint32_t pc, intptr_t data) { 118 code_->AddRelocation(dst, type, pc, data); 119 } 120 121 // These are 'static' relocations, resolved when code is finalized. 122 // We also have 'dynamic' relocations, resolved when code is installed. 123 struct Jump { 124 const Label* label; 125 // Position of field to store offset. Note: unless it's recovery label precomputed 126 // "distance from the end of instruction" is stored there. 127 // 128 // This is needed because we keep pointer to the rip-offset field while value stored 129 // there is counted from the end of instruction (on x86) or, sometimes, from the end 130 // of next instruction (ARM). 131 uint32_t pc; 132 bool is_recovery; 133 }; 134 using JumpList = ArenaVector<Jump>; 135 JumpList jumps_; 136 137 private: 138 MachineCode* code_; 139 140 DISALLOW_IMPLICIT_CONSTRUCTORS(AssemblerBase); 141 }; 142 143 } // namespace berberis 144 145 #endif // BERBERIS_ASSEMBLER_COMMON_H_ 146