• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 CompiledMethodStorage;
30 class InstructionSetFeatures;
31 
32 namespace linker {
33 
34 // MultiOatRelativePatcher is a helper class for handling patching across
35 // any number of oat files. It provides storage for method code offsets
36 // and wraps RelativePatcher calls, adjusting relative offsets according
37 // to the value set by SetAdjustment().
38 class MultiOatRelativePatcher final {
39  public:
40   using const_iterator = SafeMap<MethodReference, uint32_t>::const_iterator;
41 
42   MultiOatRelativePatcher(InstructionSet instruction_set,
43                           const InstructionSetFeatures* features,
44                           CompiledMethodStorage* storage);
45 
46   // Mark the start of a new oat file (for statistics retrieval) and set the
47   // adjustment for a new oat file to apply to all relative offsets that are
48   // passed to the MultiOatRelativePatcher.
49   //
50   // The adjustment should be the global offset of the base from which relative
51   // offsets are calculated, such as the start of .rodata for the current oat file.
52   // It must must never point directly to a method's code to avoid relative offsets
53   // with value 0 because this value is used as a missing offset indication in
54   // GetOffset() and an error indication in WriteThunks(). Additionally, it must be
55   // relative to a page-aligned boundary, so that it does not skew alignment calculations,
56   // say arm64 ADRP.
57   void StartOatFile(uint32_t adjustment);
58 
59   // Get relative offset. Returns 0 when the offset has not been set yet.
GetOffset(MethodReference method_ref)60   uint32_t GetOffset(MethodReference method_ref) {
61     auto it = method_offset_map_.map.find(method_ref);
62     return (it != method_offset_map_.map.end()) ? it->second - adjustment_ : 0u;
63   }
64 
65   // Set the offset.
SetOffset(MethodReference method_ref,uint32_t offset)66   void SetOffset(MethodReference method_ref, uint32_t offset) {
67     method_offset_map_.map.Put(method_ref, offset + adjustment_);
68   }
69 
70   // Wrapper around RelativePatcher::ReserveSpace(), doing offset adjustment.
ReserveSpace(uint32_t offset,const CompiledMethod * compiled_method,MethodReference method_ref)71   uint32_t ReserveSpace(uint32_t offset,
72                         const CompiledMethod* compiled_method,
73                         MethodReference method_ref) {
74     offset += adjustment_;
75     offset = relative_patcher_->ReserveSpace(offset, compiled_method, method_ref);
76     offset -= adjustment_;
77     return offset;
78   }
79 
80   // Wrapper around RelativePatcher::ReserveSpaceEnd(), doing offset adjustment.
ReserveSpaceEnd(uint32_t offset)81   uint32_t ReserveSpaceEnd(uint32_t offset) {
82     offset += adjustment_;
83     offset = relative_patcher_->ReserveSpaceEnd(offset);
84     offset -= adjustment_;
85     return offset;
86   }
87 
88   // Wrapper around RelativePatcher::WriteThunks(), doing offset adjustment.
WriteThunks(OutputStream * out,uint32_t offset)89   uint32_t WriteThunks(OutputStream* out, uint32_t offset) {
90     offset += adjustment_;
91     offset = relative_patcher_->WriteThunks(out, offset);
92     if (offset != 0u) {  // 0u indicates write error.
93       offset -= adjustment_;
94     }
95     return offset;
96   }
97 
98   // 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)99   void PatchCall(std::vector<uint8_t>* code,
100                  uint32_t literal_offset,
101                  uint32_t patch_offset,
102                  uint32_t target_offset) {
103     patch_offset += adjustment_;
104     target_offset += adjustment_;
105     relative_patcher_->PatchCall(code, literal_offset, patch_offset, target_offset);
106   }
107 
108   // Wrapper around RelativePatcher::PatchPcRelativeReference(), doing offset adjustment.
PatchPcRelativeReference(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset,uint32_t target_offset)109   void PatchPcRelativeReference(std::vector<uint8_t>* code,
110                                 const LinkerPatch& patch,
111                                 uint32_t patch_offset,
112                                 uint32_t target_offset) {
113     patch_offset += adjustment_;
114     target_offset += adjustment_;
115     relative_patcher_->PatchPcRelativeReference(code, patch, patch_offset, target_offset);
116   }
117 
PatchEntrypointCall(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)118   void PatchEntrypointCall(std::vector<uint8_t>* code,
119                            const LinkerPatch& patch,
120                            uint32_t patch_offset) {
121     patch_offset += adjustment_;
122     relative_patcher_->PatchEntrypointCall(code, patch, patch_offset);
123   }
124 
PatchBakerReadBarrierBranch(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)125   void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
126                                    const LinkerPatch& patch,
127                                    uint32_t patch_offset) {
128     patch_offset += adjustment_;
129     relative_patcher_->PatchBakerReadBarrierBranch(code, patch, patch_offset);
130   }
131 
GenerateThunkDebugInfo(size_t executable_offset)132   std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(size_t executable_offset) {
133     executable_offset += adjustment_;
134     return relative_patcher_->GenerateThunkDebugInfo(executable_offset);
135   }
136 
137   // Wrappers around RelativePatcher for statistics retrieval.
138   uint32_t CodeAlignmentSize() const;
139   uint32_t RelativeCallThunksSize() const;
140   uint32_t MiscThunksSize() const;
141 
142  private:
143   class ThunkProvider : public RelativePatcherThunkProvider {
144    public:
ThunkProvider(CompiledMethodStorage * storage)145     explicit ThunkProvider(CompiledMethodStorage* storage)
146         : storage_(storage) {}
147 
148     void GetThunkCode(const LinkerPatch& patch,
149                       /*out*/ ArrayRef<const uint8_t>* code,
150                       /*out*/ std::string* debug_name) override;
151 
152    private:
153     CompiledMethodStorage* storage_;
154   };
155 
156   // Map method reference to assigned offset.
157   // Wrap the map in a class implementing RelativePatcherTargetProvider.
158   class MethodOffsetMap : public RelativePatcherTargetProvider {
159    public:
160     std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) override;
161     SafeMap<MethodReference, uint32_t> map;
162   };
163 
164   ThunkProvider thunk_provider_;
165   MethodOffsetMap method_offset_map_;
166   std::unique_ptr<RelativePatcher> relative_patcher_;
167   uint32_t adjustment_;
168   InstructionSet instruction_set_;
169 
170   uint32_t start_size_code_alignment_;
171   uint32_t start_size_relative_call_thunks_;
172   uint32_t start_size_misc_thunks_;
173 
174   friend class MultiOatRelativePatcherTest;
175 
176   DISALLOW_COPY_AND_ASSIGN(MultiOatRelativePatcher);
177 };
178 
179 }  // namespace linker
180 }  // namespace art
181 
182 #endif  // ART_DEX2OAT_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_
183