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