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.
GetOffset(MethodReference method_ref)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.
SetOffset(MethodReference method_ref,uint32_t 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.
ReserveSpace(uint32_t offset,const CompiledMethod * compiled_method,MethodReference method_ref)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.
ReserveSpaceEnd(uint32_t offset)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.
WriteThunks(OutputStream * out,uint32_t offset)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.
PatchCall(std::vector<uint8_t> * code,uint32_t literal_offset,uint32_t patch_offset,uint32_t target_offset)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.
PatchPcRelativeReference(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset,uint32_t target_offset)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   // Wrappers around RelativePatcher for statistics retrieval.
116   uint32_t CodeAlignmentSize() const;
117   uint32_t RelativeCallThunksSize() const;
118   uint32_t MiscThunksSize() const;
119 
120  private:
121   // Map method reference to assigned offset.
122   // Wrap the map in a class implementing linker::RelativePatcherTargetProvider.
123   class MethodOffsetMap : public linker::RelativePatcherTargetProvider {
124    public:
125     std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) OVERRIDE;
126     SafeMap<MethodReference, uint32_t, MethodReferenceComparator> map;
127   };
128 
129   MethodOffsetMap method_offset_map_;
130   std::unique_ptr<RelativePatcher> relative_patcher_;
131   uint32_t adjustment_;
132   InstructionSet instruction_set_;
133 
134   uint32_t start_size_code_alignment_;
135   uint32_t start_size_relative_call_thunks_;
136   uint32_t start_size_misc_thunks_;
137 
138   friend class MultiOatRelativePatcherTest;
139 
140   DISALLOW_COPY_AND_ASSIGN(MultiOatRelativePatcher);
141 };
142 
143 }  // namespace linker
144 }  // namespace art
145 
146 #endif  // ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_
147