1 /* 2 * Copyright (C) 2016 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 ART_DEX2OAT_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ 18 #define ART_DEX2OAT_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ 19 20 #include "arch/instruction_set.h" 21 #include "base/safe_map.h" 22 #include "debug/method_debug_info.h" 23 #include "dex/method_reference.h" 24 #include "linker/relative_patcher.h" 25 26 namespace art { 27 28 class CompiledMethod; 29 class CompiledMethodStorage; 30 class InstructionSetFeatures; 31 32 namespace linker { 33 34 // MultiOatRelativePatcher is a helper class for handling patching across 35 // any number of oat files. It provides storage for method code offsets 36 // and wraps RelativePatcher calls, adjusting relative offsets according 37 // to the value set by SetAdjustment(). 38 class MultiOatRelativePatcher final { 39 public: 40 using const_iterator = SafeMap<MethodReference, uint32_t>::const_iterator; 41 42 MultiOatRelativePatcher(InstructionSet instruction_set, 43 const InstructionSetFeatures* features, 44 CompiledMethodStorage* storage); 45 46 // Mark the start of a new oat file (for statistics retrieval) and set the 47 // adjustment for a new oat file to apply to all relative offsets that are 48 // passed to the MultiOatRelativePatcher. 49 // 50 // The adjustment should be the global offset of the base from which relative 51 // offsets are calculated, such as the start of .rodata for the current oat file. 52 // It must must never point directly to a method's code to avoid relative offsets 53 // with value 0 because this value is used as a missing offset indication in 54 // GetOffset() and an error indication in WriteThunks(). Additionally, it must be 55 // page-aligned, so that it does not skew alignment calculations, say arm64 ADRP. 56 void StartOatFile(uint32_t adjustment); 57 58 // Get relative offset. Returns 0 when the offset has not been set yet. GetOffset(MethodReference method_ref)59 uint32_t GetOffset(MethodReference method_ref) { 60 auto it = method_offset_map_.map.find(method_ref); 61 return (it != method_offset_map_.map.end()) ? it->second - adjustment_ : 0u; 62 } 63 64 // Set the offset. SetOffset(MethodReference method_ref,uint32_t offset)65 void SetOffset(MethodReference method_ref, uint32_t offset) { 66 method_offset_map_.map.Put(method_ref, offset + adjustment_); 67 } 68 69 // Wrapper around RelativePatcher::ReserveSpace(), doing offset adjustment. ReserveSpace(uint32_t offset,const CompiledMethod * compiled_method,MethodReference method_ref)70 uint32_t ReserveSpace(uint32_t offset, 71 const CompiledMethod* compiled_method, 72 MethodReference method_ref) { 73 offset += adjustment_; 74 offset = relative_patcher_->ReserveSpace(offset, compiled_method, method_ref); 75 offset -= adjustment_; 76 return offset; 77 } 78 79 // Wrapper around RelativePatcher::ReserveSpaceEnd(), doing offset adjustment. ReserveSpaceEnd(uint32_t offset)80 uint32_t ReserveSpaceEnd(uint32_t offset) { 81 offset += adjustment_; 82 offset = relative_patcher_->ReserveSpaceEnd(offset); 83 offset -= adjustment_; 84 return offset; 85 } 86 87 // Wrapper around RelativePatcher::WriteThunks(), doing offset adjustment. WriteThunks(OutputStream * out,uint32_t offset)88 uint32_t WriteThunks(OutputStream* out, uint32_t offset) { 89 offset += adjustment_; 90 offset = relative_patcher_->WriteThunks(out, offset); 91 if (offset != 0u) { // 0u indicates write error. 92 offset -= adjustment_; 93 } 94 return offset; 95 } 96 97 // Wrapper around RelativePatcher::PatchCall(), doing offset adjustment. PatchCall(std::vector<uint8_t> * code,uint32_t literal_offset,uint32_t patch_offset,uint32_t target_offset)98 void PatchCall(std::vector<uint8_t>* code, 99 uint32_t literal_offset, 100 uint32_t patch_offset, 101 uint32_t target_offset) { 102 patch_offset += adjustment_; 103 target_offset += adjustment_; 104 relative_patcher_->PatchCall(code, literal_offset, patch_offset, target_offset); 105 } 106 107 // Wrapper around RelativePatcher::PatchPcRelativeReference(), doing offset adjustment. PatchPcRelativeReference(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset,uint32_t target_offset)108 void PatchPcRelativeReference(std::vector<uint8_t>* code, 109 const LinkerPatch& patch, 110 uint32_t patch_offset, 111 uint32_t target_offset) { 112 patch_offset += adjustment_; 113 target_offset += adjustment_; 114 relative_patcher_->PatchPcRelativeReference(code, patch, patch_offset, target_offset); 115 } 116 PatchEntrypointCall(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)117 void PatchEntrypointCall(std::vector<uint8_t>* code, 118 const LinkerPatch& patch, 119 uint32_t patch_offset) { 120 patch_offset += adjustment_; 121 relative_patcher_->PatchEntrypointCall(code, patch, patch_offset); 122 } 123 PatchBakerReadBarrierBranch(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)124 void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code, 125 const LinkerPatch& patch, 126 uint32_t patch_offset) { 127 patch_offset += adjustment_; 128 relative_patcher_->PatchBakerReadBarrierBranch(code, patch, patch_offset); 129 } 130 GenerateThunkDebugInfo(size_t executable_offset)131 std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(size_t executable_offset) { 132 executable_offset += adjustment_; 133 return relative_patcher_->GenerateThunkDebugInfo(executable_offset); 134 } 135 136 // Wrappers around RelativePatcher for statistics retrieval. 137 uint32_t CodeAlignmentSize() const; 138 uint32_t RelativeCallThunksSize() const; 139 uint32_t MiscThunksSize() const; 140 141 private: 142 class ThunkProvider : public RelativePatcherThunkProvider { 143 public: ThunkProvider(CompiledMethodStorage * storage)144 explicit ThunkProvider(CompiledMethodStorage* storage) 145 : storage_(storage) {} 146 147 void GetThunkCode(const LinkerPatch& patch, 148 /*out*/ ArrayRef<const uint8_t>* code, 149 /*out*/ std::string* debug_name) override; 150 151 private: 152 CompiledMethodStorage* storage_; 153 }; 154 155 // Map method reference to assigned offset. 156 // Wrap the map in a class implementing RelativePatcherTargetProvider. 157 class MethodOffsetMap : public RelativePatcherTargetProvider { 158 public: 159 std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) override; 160 SafeMap<MethodReference, uint32_t> map; 161 }; 162 163 ThunkProvider thunk_provider_; 164 MethodOffsetMap method_offset_map_; 165 std::unique_ptr<RelativePatcher> relative_patcher_; 166 uint32_t adjustment_; 167 InstructionSet instruction_set_; 168 169 uint32_t start_size_code_alignment_; 170 uint32_t start_size_relative_call_thunks_; 171 uint32_t start_size_misc_thunks_; 172 173 friend class MultiOatRelativePatcherTest; 174 175 DISALLOW_COPY_AND_ASSIGN(MultiOatRelativePatcher); 176 }; 177 178 } // namespace linker 179 } // namespace art 180 181 #endif // ART_DEX2OAT_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ 182