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 // 18 // Generated machine code. 19 20 #ifndef BERBERIS_ASSEMBLER_MACHINE_CODE_H_ 21 #define BERBERIS_ASSEMBLER_MACHINE_CODE_H_ 22 23 #include <cstdint> 24 #include <string> 25 26 #include "berberis/base/arena_alloc.h" 27 #include "berberis/base/arena_vector.h" 28 #include "berberis/base/forever_map.h" 29 #include "berberis/base/macros.h" // DISALLOW_COPY_AND_ASSIGN 30 31 #if defined(__riscv) 32 #include <sys/cachectl.h> 33 #endif 34 35 namespace berberis { 36 37 enum class InstructionSize { 38 // x86 assembly has 1 byte instructions. 39 OneByte, 40 // riscv and arm64 assembly have 4 bytes instructions. 41 FourBytes, 42 }; 43 44 enum class RelocationType { 45 // Convert absolute address to PC-relative displacement. 46 // Ensure displacement fits in 32-bit value. 47 RelocAbsToDisp32, 48 // Add recovery point and recovery code to global recovery code map. 49 // TODO(eaeltsin): have recovery map for each region instead! 50 RelocRecoveryPoint, 51 }; 52 53 using RecoveryMap = ForeverMap<uintptr_t, uintptr_t>; 54 55 // Generated machine code for host architecture. Used by trampolines 56 // and JIT translator. 57 // NOTE: this class is not intended for concurrent usage by multiple threads. 58 class MachineCode { 59 public: MachineCode()60 MachineCode() : code_(&arena_), relocations_(&arena_) { 61 // The amount is chosen according to the performance of spec2000 benchmarks. 62 code_.reserve(1024); 63 } 64 arena()65 Arena* arena() { return &arena_; } 66 67 // TODO(eaeltsin): this will include const pool size when supported. install_size()68 [[nodiscard]] uint32_t install_size() const { return code_.size(); } 69 code_offset()70 [[nodiscard]] uint32_t code_offset() const { return code_.size(); } 71 72 template <typename T> AddrAs(uint32_t offset)73 T* AddrAs(uint32_t offset) { 74 return reinterpret_cast<T*>(AddrOf(offset)); 75 } 76 77 template <typename T> AddrAs(uint32_t offset)78 [[nodiscard]] const T* AddrAs(uint32_t offset) const { 79 return reinterpret_cast<const T*>(AddrOf(offset)); 80 } 81 82 template <typename T> Add(const T & v)83 void Add(const T& v) { 84 memcpy(AddrAs<T>(Grow(sizeof(T))), &v, sizeof(T)); 85 } 86 87 template <typename T> AddSequence(const T * v,uint32_t count)88 void AddSequence(const T* v, uint32_t count) { 89 memcpy(AddrAs<T>(Grow(sizeof(T) * count)), v, sizeof(T) * count); 90 } 91 AddU8(uint8_t v)92 void AddU8(uint8_t v) { code_.push_back(v); } 93 94 void AsString(std::string* result, InstructionSize insn_size) const; 95 AddRelocation(uint32_t dst,RelocationType type,uint32_t pc,intptr_t data)96 void AddRelocation(uint32_t dst, RelocationType type, uint32_t pc, intptr_t data) { 97 relocations_.push_back(Relocation{dst, type, pc, data}); 98 } 99 100 // Install to executable memory. 101 template <typename ExecRegionType> Install(ExecRegionType * exec,const uint8_t * code,RecoveryMap * recovery_map)102 void Install(ExecRegionType* exec, const uint8_t* code, RecoveryMap* recovery_map) { 103 PerformRelocations(code, recovery_map); 104 exec->Write(code, AddrAs<uint8_t>(0), code_.size()); 105 #if defined(__riscv) 106 __riscv_flush_icache((void*)code, (void*)(code + code_.size()), 0); 107 #endif 108 } 109 110 // Install to writable memory. InstallUnsafe(uint8_t * code,RecoveryMap * recovery_map)111 void InstallUnsafe(uint8_t* code, RecoveryMap* recovery_map) { 112 PerformRelocations(code, recovery_map); 113 memcpy(code, AddrAs<uint8_t>(0), code_.size()); 114 } 115 116 // Print generated code to stderr. 117 void DumpCode(InstructionSize insn_size) const; 118 119 private: 120 struct Relocation { 121 uint32_t dst; 122 RelocationType type; 123 uint32_t pc; 124 intptr_t data; 125 }; 126 using RelocationList = ArenaVector<Relocation>; 127 128 [[nodiscard]] uint8_t* AddrOf(uint32_t offset); 129 [[nodiscard]] const uint8_t* AddrOf(uint32_t offset) const; 130 uint32_t Grow(uint32_t count); 131 132 // Relocate the code, in assumption it is to be installed at address 'code'. 133 void PerformRelocations(const uint8_t* code, RecoveryMap* recovery_map); 134 135 Arena arena_; 136 ArenaVector<uint8_t> code_; 137 RelocationList relocations_; 138 139 DISALLOW_COPY_AND_ASSIGN(MachineCode); 140 }; 141 142 } // namespace berberis 143 144 #endif // BERBERIS_ASSEMBLER_MACHINE_CODE_H_ 145