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