/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ #define ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ #include "arch/instruction_set.h" #include "method_reference.h" #include "relative_patcher.h" #include "safe_map.h" namespace art { class CompiledMethod; class LinkerPatch; class InstructionSetFeatures; namespace linker { // MultiOatRelativePatcher is a helper class for handling patching across // any number of oat files. It provides storage for method code offsets // and wraps RelativePatcher calls, adjusting relative offsets according // to the value set by SetAdjustment(). class MultiOatRelativePatcher FINAL { public: using const_iterator = SafeMap<MethodReference, uint32_t, MethodReferenceComparator>::const_iterator; MultiOatRelativePatcher(InstructionSet instruction_set, const InstructionSetFeatures* features); // Mark the start of a new oat file (for statistics retrieval) and set the // adjustment for a new oat file to apply to all relative offsets that are // passed to the MultiOatRelativePatcher. // // The adjustment should be the global offset of the base from which relative // offsets are calculated, such as the start of .rodata for the current oat file. // It must must never point directly to a method's code to avoid relative offsets // with value 0 because this value is used as a missing offset indication in // GetOffset() and an error indication in WriteThunks(). Additionally, it must be // page-aligned, so that it does not skew alignment calculations, say arm64 ADRP. void StartOatFile(uint32_t adjustment); // Get relative offset. Returns 0 when the offset has not been set yet. uint32_t GetOffset(MethodReference method_ref) { auto it = method_offset_map_.map.find(method_ref); return (it != method_offset_map_.map.end()) ? it->second - adjustment_ : 0u; } // Set the offset. void SetOffset(MethodReference method_ref, uint32_t offset) { method_offset_map_.map.Put(method_ref, offset + adjustment_); } // Wrapper around RelativePatcher::ReserveSpace(), doing offset adjustment. uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method, MethodReference method_ref) { offset += adjustment_; offset = relative_patcher_->ReserveSpace(offset, compiled_method, method_ref); offset -= adjustment_; return offset; } // Wrapper around RelativePatcher::ReserveSpaceEnd(), doing offset adjustment. uint32_t ReserveSpaceEnd(uint32_t offset) { offset += adjustment_; offset = relative_patcher_->ReserveSpaceEnd(offset); offset -= adjustment_; return offset; } // Wrapper around RelativePatcher::WriteThunks(), doing offset adjustment. uint32_t WriteThunks(OutputStream* out, uint32_t offset) { offset += adjustment_; offset = relative_patcher_->WriteThunks(out, offset); if (offset != 0u) { // 0u indicates write error. offset -= adjustment_; } return offset; } // Wrapper around RelativePatcher::PatchCall(), doing offset adjustment. void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset, uint32_t target_offset) { patch_offset += adjustment_; target_offset += adjustment_; relative_patcher_->PatchCall(code, literal_offset, patch_offset, target_offset); } // Wrapper around RelativePatcher::PatchDexCacheReference(), doing offset adjustment. void PatchPcRelativeReference(std::vector<uint8_t>* code, const LinkerPatch& patch, uint32_t patch_offset, uint32_t target_offset) { patch_offset += adjustment_; target_offset += adjustment_; relative_patcher_->PatchPcRelativeReference(code, patch, patch_offset, target_offset); } // Wrappers around RelativePatcher for statistics retrieval. uint32_t CodeAlignmentSize() const; uint32_t RelativeCallThunksSize() const; uint32_t MiscThunksSize() const; private: // Map method reference to assigned offset. // Wrap the map in a class implementing linker::RelativePatcherTargetProvider. class MethodOffsetMap : public linker::RelativePatcherTargetProvider { public: std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) OVERRIDE; SafeMap<MethodReference, uint32_t, MethodReferenceComparator> map; }; MethodOffsetMap method_offset_map_; std::unique_ptr<RelativePatcher> relative_patcher_; uint32_t adjustment_; InstructionSet instruction_set_; uint32_t start_size_code_alignment_; uint32_t start_size_relative_call_thunks_; uint32_t start_size_misc_thunks_; friend class MultiOatRelativePatcherTest; DISALLOW_COPY_AND_ASSIGN(MultiOatRelativePatcher); }; } // namespace linker } // namespace art #endif // ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_