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