1944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko/* 2944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * Copyright (C) 2016 The Android Open Source Project 3944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * 4944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * Licensed under the Apache License, Version 2.0 (the "License"); 5944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * you may not use this file except in compliance with the License. 6944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * You may obtain a copy of the License at 7944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * 8944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * http://www.apache.org/licenses/LICENSE-2.0 9944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * 10944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * Unless required by applicable law or agreed to in writing, software 11944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * distributed under the License is distributed on an "AS IS" BASIS, 12944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * See the License for the specific language governing permissions and 14944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * limitations under the License. 15944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko */ 16944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 17944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#ifndef ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ 18944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#define ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ 19944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 20944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "arch/instruction_set.h" 21944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "method_reference.h" 22944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "relative_patcher.h" 23944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "safe_map.h" 24944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 25944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markonamespace art { 26944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 27944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markoclass CompiledMethod; 28944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markoclass LinkerPatch; 29944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markoclass InstructionSetFeatures; 30944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 31944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markonamespace linker { 32944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 33944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko// MultiOatRelativePatcher is a helper class for handling patching across 34944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko// any number of oat files. It provides storage for method code offsets 35944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko// and wraps RelativePatcher calls, adjusting relative offsets according 36944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko// to the value set by SetAdjustment(). 37944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markoclass MultiOatRelativePatcher FINAL { 38944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko public: 39944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko using const_iterator = 40944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko SafeMap<MethodReference, uint32_t, MethodReferenceComparator>::const_iterator; 41944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 42944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko MultiOatRelativePatcher(InstructionSet instruction_set, const InstructionSetFeatures* features); 43944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 44944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Mark the start of a new oat file (for statistics retrieval) and set the 45944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // adjustment for a new oat file to apply to all relative offsets that are 46944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // passed to the MultiOatRelativePatcher. 47944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // 48944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // The adjustment should be the global offset of the base from which relative 49944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // offsets are calculated, such as the start of .rodata for the current oat file. 50944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // It must must never point directly to a method's code to avoid relative offsets 51944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // with value 0 because this value is used as a missing offset indication in 52944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // GetOffset() and an error indication in WriteThunks(). Additionally, it must be 53944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // page-aligned, so that it does not skew alignment calculations, say arm64 ADRP. 54944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko void StartOatFile(uint32_t adjustment); 55944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 56944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Get relative offset. Returns 0 when the offset has not been set yet. 57944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t GetOffset(MethodReference method_ref) { 58944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko auto it = method_offset_map_.map.find(method_ref); 59944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko return (it != method_offset_map_.map.end()) ? it->second - adjustment_ : 0u; 60944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko } 61944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 62944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Set the offset. 63944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko void SetOffset(MethodReference method_ref, uint32_t offset) { 64944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko method_offset_map_.map.Put(method_ref, offset + adjustment_); 65944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko } 66944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 67944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Wrapper around RelativePatcher::ReserveSpace(), doing offset adjustment. 68944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t ReserveSpace(uint32_t offset, 69944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko const CompiledMethod* compiled_method, 70944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko MethodReference method_ref) { 71944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko offset += adjustment_; 72944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko offset = relative_patcher_->ReserveSpace(offset, compiled_method, method_ref); 73944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko offset -= adjustment_; 74944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko return offset; 75944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko } 76944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 77944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Wrapper around RelativePatcher::ReserveSpaceEnd(), doing offset adjustment. 78944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t ReserveSpaceEnd(uint32_t offset) { 79944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko offset += adjustment_; 80944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko offset = relative_patcher_->ReserveSpaceEnd(offset); 81944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko offset -= adjustment_; 82944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko return offset; 83944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko } 84944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 85944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Wrapper around RelativePatcher::WriteThunks(), doing offset adjustment. 86944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t WriteThunks(OutputStream* out, uint32_t offset) { 87944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko offset += adjustment_; 88944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko offset = relative_patcher_->WriteThunks(out, offset); 89944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko if (offset != 0u) { // 0u indicates write error. 90944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko offset -= adjustment_; 91944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko } 92944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko return offset; 93944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko } 94944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 95944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Wrapper around RelativePatcher::PatchCall(), doing offset adjustment. 96944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko void PatchCall(std::vector<uint8_t>* code, 97944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t literal_offset, 98944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t patch_offset, 99944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t target_offset) { 100944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko patch_offset += adjustment_; 101944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko target_offset += adjustment_; 102944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko relative_patcher_->PatchCall(code, literal_offset, patch_offset, target_offset); 103944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko } 104944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 105944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Wrapper around RelativePatcher::PatchDexCacheReference(), doing offset adjustment. 106cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko void PatchPcRelativeReference(std::vector<uint8_t>* code, 107cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko const LinkerPatch& patch, 108cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko uint32_t patch_offset, 109cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko uint32_t target_offset) { 110944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko patch_offset += adjustment_; 111944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko target_offset += adjustment_; 112cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko relative_patcher_->PatchPcRelativeReference(code, patch, patch_offset, target_offset); 113944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko } 114944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 115944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Wrappers around RelativePatcher for statistics retrieval. 116944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t CodeAlignmentSize() const; 117944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t RelativeCallThunksSize() const; 118944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t MiscThunksSize() const; 119944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 120944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko private: 121944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Map method reference to assigned offset. 122944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko // Wrap the map in a class implementing linker::RelativePatcherTargetProvider. 123944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko class MethodOffsetMap : public linker::RelativePatcherTargetProvider { 124944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko public: 125944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) OVERRIDE; 126944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko SafeMap<MethodReference, uint32_t, MethodReferenceComparator> map; 127944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko }; 128944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 129944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko MethodOffsetMap method_offset_map_; 130944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko std::unique_ptr<RelativePatcher> relative_patcher_; 131944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t adjustment_; 132944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko InstructionSet instruction_set_; 133944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 134944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t start_size_code_alignment_; 135944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t start_size_relative_call_thunks_; 136944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko uint32_t start_size_misc_thunks_; 137944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 138944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko friend class MultiOatRelativePatcherTest; 139944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 140944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko DISALLOW_COPY_AND_ASSIGN(MultiOatRelativePatcher); 141944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}; 142944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 143944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko} // namespace linker 144944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko} // namespace art 145944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko 146944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#endif // ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_ 147