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