Home | History | Annotate | Download | only in linker
      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