xref: /aosp_15_r20/art/dex2oat/linker/multi_oat_relative_patcher.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_DEX2OAT_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_DEX2OAT_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/safe_map.h"
22*795d594fSAndroid Build Coastguard Worker #include "debug/method_debug_info.h"
23*795d594fSAndroid Build Coastguard Worker #include "dex/method_reference.h"
24*795d594fSAndroid Build Coastguard Worker #include "linker/relative_patcher.h"
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker namespace art {
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker class CompiledMethod;
29*795d594fSAndroid Build Coastguard Worker class CompiledMethodStorage;
30*795d594fSAndroid Build Coastguard Worker class InstructionSetFeatures;
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker namespace linker {
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker // MultiOatRelativePatcher is a helper class for handling patching across
35*795d594fSAndroid Build Coastguard Worker // any number of oat files. It provides storage for method code offsets
36*795d594fSAndroid Build Coastguard Worker // and wraps RelativePatcher calls, adjusting relative offsets according
37*795d594fSAndroid Build Coastguard Worker // to the value set by SetAdjustment().
38*795d594fSAndroid Build Coastguard Worker class MultiOatRelativePatcher final {
39*795d594fSAndroid Build Coastguard Worker  public:
40*795d594fSAndroid Build Coastguard Worker   using const_iterator = SafeMap<MethodReference, uint32_t>::const_iterator;
41*795d594fSAndroid Build Coastguard Worker 
42*795d594fSAndroid Build Coastguard Worker   MultiOatRelativePatcher(InstructionSet instruction_set,
43*795d594fSAndroid Build Coastguard Worker                           const InstructionSetFeatures* features,
44*795d594fSAndroid Build Coastguard Worker                           CompiledMethodStorage* storage);
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker   // Mark the start of a new oat file (for statistics retrieval) and set the
47*795d594fSAndroid Build Coastguard Worker   // adjustment for a new oat file to apply to all relative offsets that are
48*795d594fSAndroid Build Coastguard Worker   // passed to the MultiOatRelativePatcher.
49*795d594fSAndroid Build Coastguard Worker   //
50*795d594fSAndroid Build Coastguard Worker   // The adjustment should be the global offset of the base from which relative
51*795d594fSAndroid Build Coastguard Worker   // offsets are calculated, such as the start of .rodata for the current oat file.
52*795d594fSAndroid Build Coastguard Worker   // It must must never point directly to a method's code to avoid relative offsets
53*795d594fSAndroid Build Coastguard Worker   // with value 0 because this value is used as a missing offset indication in
54*795d594fSAndroid Build Coastguard Worker   // GetOffset() and an error indication in WriteThunks(). Additionally, it must be
55*795d594fSAndroid Build Coastguard Worker   // page-aligned, so that it does not skew alignment calculations, say arm64 ADRP.
56*795d594fSAndroid Build Coastguard Worker   void StartOatFile(uint32_t adjustment);
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker   // Get relative offset. Returns 0 when the offset has not been set yet.
GetOffset(MethodReference method_ref)59*795d594fSAndroid Build Coastguard Worker   uint32_t GetOffset(MethodReference method_ref) {
60*795d594fSAndroid Build Coastguard Worker     auto it = method_offset_map_.map.find(method_ref);
61*795d594fSAndroid Build Coastguard Worker     return (it != method_offset_map_.map.end()) ? it->second - adjustment_ : 0u;
62*795d594fSAndroid Build Coastguard Worker   }
63*795d594fSAndroid Build Coastguard Worker 
64*795d594fSAndroid Build Coastguard Worker   // Set the offset.
SetOffset(MethodReference method_ref,uint32_t offset)65*795d594fSAndroid Build Coastguard Worker   void SetOffset(MethodReference method_ref, uint32_t offset) {
66*795d594fSAndroid Build Coastguard Worker     method_offset_map_.map.Put(method_ref, offset + adjustment_);
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker   // Wrapper around RelativePatcher::ReserveSpace(), doing offset adjustment.
ReserveSpace(uint32_t offset,const CompiledMethod * compiled_method,MethodReference method_ref)70*795d594fSAndroid Build Coastguard Worker   uint32_t ReserveSpace(uint32_t offset,
71*795d594fSAndroid Build Coastguard Worker                         const CompiledMethod* compiled_method,
72*795d594fSAndroid Build Coastguard Worker                         MethodReference method_ref) {
73*795d594fSAndroid Build Coastguard Worker     offset += adjustment_;
74*795d594fSAndroid Build Coastguard Worker     offset = relative_patcher_->ReserveSpace(offset, compiled_method, method_ref);
75*795d594fSAndroid Build Coastguard Worker     offset -= adjustment_;
76*795d594fSAndroid Build Coastguard Worker     return offset;
77*795d594fSAndroid Build Coastguard Worker   }
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker   // Wrapper around RelativePatcher::ReserveSpaceEnd(), doing offset adjustment.
ReserveSpaceEnd(uint32_t offset)80*795d594fSAndroid Build Coastguard Worker   uint32_t ReserveSpaceEnd(uint32_t offset) {
81*795d594fSAndroid Build Coastguard Worker     offset += adjustment_;
82*795d594fSAndroid Build Coastguard Worker     offset = relative_patcher_->ReserveSpaceEnd(offset);
83*795d594fSAndroid Build Coastguard Worker     offset -= adjustment_;
84*795d594fSAndroid Build Coastguard Worker     return offset;
85*795d594fSAndroid Build Coastguard Worker   }
86*795d594fSAndroid Build Coastguard Worker 
87*795d594fSAndroid Build Coastguard Worker   // Wrapper around RelativePatcher::WriteThunks(), doing offset adjustment.
WriteThunks(OutputStream * out,uint32_t offset)88*795d594fSAndroid Build Coastguard Worker   uint32_t WriteThunks(OutputStream* out, uint32_t offset) {
89*795d594fSAndroid Build Coastguard Worker     offset += adjustment_;
90*795d594fSAndroid Build Coastguard Worker     offset = relative_patcher_->WriteThunks(out, offset);
91*795d594fSAndroid Build Coastguard Worker     if (offset != 0u) {  // 0u indicates write error.
92*795d594fSAndroid Build Coastguard Worker       offset -= adjustment_;
93*795d594fSAndroid Build Coastguard Worker     }
94*795d594fSAndroid Build Coastguard Worker     return offset;
95*795d594fSAndroid Build Coastguard Worker   }
96*795d594fSAndroid Build Coastguard Worker 
97*795d594fSAndroid Build Coastguard Worker   // 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)98*795d594fSAndroid Build Coastguard Worker   void PatchCall(std::vector<uint8_t>* code,
99*795d594fSAndroid Build Coastguard Worker                  uint32_t literal_offset,
100*795d594fSAndroid Build Coastguard Worker                  uint32_t patch_offset,
101*795d594fSAndroid Build Coastguard Worker                  uint32_t target_offset) {
102*795d594fSAndroid Build Coastguard Worker     patch_offset += adjustment_;
103*795d594fSAndroid Build Coastguard Worker     target_offset += adjustment_;
104*795d594fSAndroid Build Coastguard Worker     relative_patcher_->PatchCall(code, literal_offset, patch_offset, target_offset);
105*795d594fSAndroid Build Coastguard Worker   }
106*795d594fSAndroid Build Coastguard Worker 
107*795d594fSAndroid Build Coastguard Worker   // Wrapper around RelativePatcher::PatchPcRelativeReference(), doing offset adjustment.
PatchPcRelativeReference(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset,uint32_t target_offset)108*795d594fSAndroid Build Coastguard Worker   void PatchPcRelativeReference(std::vector<uint8_t>* code,
109*795d594fSAndroid Build Coastguard Worker                                 const LinkerPatch& patch,
110*795d594fSAndroid Build Coastguard Worker                                 uint32_t patch_offset,
111*795d594fSAndroid Build Coastguard Worker                                 uint32_t target_offset) {
112*795d594fSAndroid Build Coastguard Worker     patch_offset += adjustment_;
113*795d594fSAndroid Build Coastguard Worker     target_offset += adjustment_;
114*795d594fSAndroid Build Coastguard Worker     relative_patcher_->PatchPcRelativeReference(code, patch, patch_offset, target_offset);
115*795d594fSAndroid Build Coastguard Worker   }
116*795d594fSAndroid Build Coastguard Worker 
PatchEntrypointCall(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)117*795d594fSAndroid Build Coastguard Worker   void PatchEntrypointCall(std::vector<uint8_t>* code,
118*795d594fSAndroid Build Coastguard Worker                            const LinkerPatch& patch,
119*795d594fSAndroid Build Coastguard Worker                            uint32_t patch_offset) {
120*795d594fSAndroid Build Coastguard Worker     patch_offset += adjustment_;
121*795d594fSAndroid Build Coastguard Worker     relative_patcher_->PatchEntrypointCall(code, patch, patch_offset);
122*795d594fSAndroid Build Coastguard Worker   }
123*795d594fSAndroid Build Coastguard Worker 
PatchBakerReadBarrierBranch(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)124*795d594fSAndroid Build Coastguard Worker   void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
125*795d594fSAndroid Build Coastguard Worker                                    const LinkerPatch& patch,
126*795d594fSAndroid Build Coastguard Worker                                    uint32_t patch_offset) {
127*795d594fSAndroid Build Coastguard Worker     patch_offset += adjustment_;
128*795d594fSAndroid Build Coastguard Worker     relative_patcher_->PatchBakerReadBarrierBranch(code, patch, patch_offset);
129*795d594fSAndroid Build Coastguard Worker   }
130*795d594fSAndroid Build Coastguard Worker 
GenerateThunkDebugInfo(size_t executable_offset)131*795d594fSAndroid Build Coastguard Worker   std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(size_t executable_offset) {
132*795d594fSAndroid Build Coastguard Worker     executable_offset += adjustment_;
133*795d594fSAndroid Build Coastguard Worker     return relative_patcher_->GenerateThunkDebugInfo(executable_offset);
134*795d594fSAndroid Build Coastguard Worker   }
135*795d594fSAndroid Build Coastguard Worker 
136*795d594fSAndroid Build Coastguard Worker   // Wrappers around RelativePatcher for statistics retrieval.
137*795d594fSAndroid Build Coastguard Worker   uint32_t CodeAlignmentSize() const;
138*795d594fSAndroid Build Coastguard Worker   uint32_t RelativeCallThunksSize() const;
139*795d594fSAndroid Build Coastguard Worker   uint32_t MiscThunksSize() const;
140*795d594fSAndroid Build Coastguard Worker 
141*795d594fSAndroid Build Coastguard Worker  private:
142*795d594fSAndroid Build Coastguard Worker   class ThunkProvider : public RelativePatcherThunkProvider {
143*795d594fSAndroid Build Coastguard Worker    public:
ThunkProvider(CompiledMethodStorage * storage)144*795d594fSAndroid Build Coastguard Worker     explicit ThunkProvider(CompiledMethodStorage* storage)
145*795d594fSAndroid Build Coastguard Worker         : storage_(storage) {}
146*795d594fSAndroid Build Coastguard Worker 
147*795d594fSAndroid Build Coastguard Worker     void GetThunkCode(const LinkerPatch& patch,
148*795d594fSAndroid Build Coastguard Worker                       /*out*/ ArrayRef<const uint8_t>* code,
149*795d594fSAndroid Build Coastguard Worker                       /*out*/ std::string* debug_name) override;
150*795d594fSAndroid Build Coastguard Worker 
151*795d594fSAndroid Build Coastguard Worker    private:
152*795d594fSAndroid Build Coastguard Worker     CompiledMethodStorage* storage_;
153*795d594fSAndroid Build Coastguard Worker   };
154*795d594fSAndroid Build Coastguard Worker 
155*795d594fSAndroid Build Coastguard Worker   // Map method reference to assigned offset.
156*795d594fSAndroid Build Coastguard Worker   // Wrap the map in a class implementing RelativePatcherTargetProvider.
157*795d594fSAndroid Build Coastguard Worker   class MethodOffsetMap : public RelativePatcherTargetProvider {
158*795d594fSAndroid Build Coastguard Worker    public:
159*795d594fSAndroid Build Coastguard Worker     std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) override;
160*795d594fSAndroid Build Coastguard Worker     SafeMap<MethodReference, uint32_t> map;
161*795d594fSAndroid Build Coastguard Worker   };
162*795d594fSAndroid Build Coastguard Worker 
163*795d594fSAndroid Build Coastguard Worker   ThunkProvider thunk_provider_;
164*795d594fSAndroid Build Coastguard Worker   MethodOffsetMap method_offset_map_;
165*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<RelativePatcher> relative_patcher_;
166*795d594fSAndroid Build Coastguard Worker   uint32_t adjustment_;
167*795d594fSAndroid Build Coastguard Worker   InstructionSet instruction_set_;
168*795d594fSAndroid Build Coastguard Worker 
169*795d594fSAndroid Build Coastguard Worker   uint32_t start_size_code_alignment_;
170*795d594fSAndroid Build Coastguard Worker   uint32_t start_size_relative_call_thunks_;
171*795d594fSAndroid Build Coastguard Worker   uint32_t start_size_misc_thunks_;
172*795d594fSAndroid Build Coastguard Worker 
173*795d594fSAndroid Build Coastguard Worker   friend class MultiOatRelativePatcherTest;
174*795d594fSAndroid Build Coastguard Worker 
175*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(MultiOatRelativePatcher);
176*795d594fSAndroid Build Coastguard Worker };
177*795d594fSAndroid Build Coastguard Worker 
178*795d594fSAndroid Build Coastguard Worker }  // namespace linker
179*795d594fSAndroid Build Coastguard Worker }  // namespace art
180*795d594fSAndroid Build Coastguard Worker 
181*795d594fSAndroid Build Coastguard Worker #endif  // ART_DEX2OAT_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_
182