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 // relative to a page-aligned boundary, so that it does not skew alignment calculations, 56 // say arm64 ADRP. 57 void StartOatFile(uint32_t adjustment); 58 59 // Get relative offset. Returns 0 when the offset has not been set yet. GetOffset(MethodReference method_ref)60 uint32_t GetOffset(MethodReference method_ref) { 61 auto it = method_offset_map_.map.find(method_ref); 62 return (it != method_offset_map_.map.end()) ? it->second - adjustment_ : 0u; 63 } 64 65 // Set the offset. SetOffset(MethodReference method_ref,uint32_t offset)66 void SetOffset(MethodReference method_ref, uint32_t offset) { 67 method_offset_map_.map.Put(method_ref, offset + adjustment_); 68 } 69 70 // Wrapper around RelativePatcher::ReserveSpace(), doing offset adjustment. ReserveSpace(uint32_t offset,const CompiledMethod * compiled_method,MethodReference method_ref)71 uint32_t ReserveSpace(uint32_t offset, 72 const CompiledMethod* compiled_method, 73 MethodReference method_ref) { 74 offset += adjustment_; 75 offset = relative_patcher_->ReserveSpace(offset, compiled_method, method_ref); 76 offset -= adjustment_; 77 return offset; 78 } 79 80 // Wrapper around RelativePatcher::ReserveSpaceEnd(), doing offset adjustment. ReserveSpaceEnd(uint32_t offset)81 uint32_t ReserveSpaceEnd(uint32_t offset) { 82 offset += adjustment_; 83 offset = relative_patcher_->ReserveSpaceEnd(offset); 84 offset -= adjustment_; 85 return offset; 86 } 87 88 // Wrapper around RelativePatcher::WriteThunks(), doing offset adjustment. WriteThunks(OutputStream * out,uint32_t offset)89 uint32_t WriteThunks(OutputStream* out, uint32_t offset) { 90 offset += adjustment_; 91 offset = relative_patcher_->WriteThunks(out, offset); 92 if (offset != 0u) { // 0u indicates write error. 93 offset -= adjustment_; 94 } 95 return offset; 96 } 97 98 // 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)99 void PatchCall(std::vector<uint8_t>* code, 100 uint32_t literal_offset, 101 uint32_t patch_offset, 102 uint32_t target_offset) { 103 patch_offset += adjustment_; 104 target_offset += adjustment_; 105 relative_patcher_->PatchCall(code, literal_offset, patch_offset, target_offset); 106 } 107 108 // Wrapper around RelativePatcher::PatchPcRelativeReference(), doing offset adjustment. PatchPcRelativeReference(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset,uint32_t target_offset)109 void PatchPcRelativeReference(std::vector<uint8_t>* code, 110 const LinkerPatch& patch, 111 uint32_t patch_offset, 112 uint32_t target_offset) { 113 patch_offset += adjustment_; 114 target_offset += adjustment_; 115 relative_patcher_->PatchPcRelativeReference(code, patch, patch_offset, target_offset); 116 } 117 PatchEntrypointCall(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)118 void PatchEntrypointCall(std::vector<uint8_t>* code, 119 const LinkerPatch& patch, 120 uint32_t patch_offset) { 121 patch_offset += adjustment_; 122 relative_patcher_->PatchEntrypointCall(code, patch, patch_offset); 123 } 124 PatchBakerReadBarrierBranch(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)125 void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code, 126 const LinkerPatch& patch, 127 uint32_t patch_offset) { 128 patch_offset += adjustment_; 129 relative_patcher_->PatchBakerReadBarrierBranch(code, patch, patch_offset); 130 } 131 GenerateThunkDebugInfo(size_t executable_offset)132 std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(size_t executable_offset) { 133 executable_offset += adjustment_; 134 return relative_patcher_->GenerateThunkDebugInfo(executable_offset); 135 } 136 137 // Wrappers around RelativePatcher for statistics retrieval. 138 uint32_t CodeAlignmentSize() const; 139 uint32_t RelativeCallThunksSize() const; 140 uint32_t MiscThunksSize() const; 141 142 private: 143 class ThunkProvider : public RelativePatcherThunkProvider { 144 public: ThunkProvider(CompiledMethodStorage * storage)145 explicit ThunkProvider(CompiledMethodStorage* storage) 146 : storage_(storage) {} 147 148 void GetThunkCode(const LinkerPatch& patch, 149 /*out*/ ArrayRef<const uint8_t>* code, 150 /*out*/ std::string* debug_name) override; 151 152 private: 153 CompiledMethodStorage* storage_; 154 }; 155 156 // Map method reference to assigned offset. 157 // Wrap the map in a class implementing RelativePatcherTargetProvider. 158 class MethodOffsetMap : public RelativePatcherTargetProvider { 159 public: 160 std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) override; 161 SafeMap<MethodReference, uint32_t> map; 162 }; 163 164 ThunkProvider thunk_provider_; 165 MethodOffsetMap method_offset_map_; 166 std::unique_ptr<RelativePatcher> relative_patcher_; 167 uint32_t adjustment_; 168 InstructionSet instruction_set_; 169 170 uint32_t start_size_code_alignment_; 171 uint32_t start_size_relative_call_thunks_; 172 uint32_t start_size_misc_thunks_; 173 174 friend class MultiOatRelativePatcherTest; 175 176 DISALLOW_COPY_AND_ASSIGN(MultiOatRelativePatcher); 177 }; 178 179 } // namespace linker 180 } // namespace art 181 182 #endif // ART_DEX2OAT_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ 183