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