1 /*
2  * Copyright (C) 2017 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_LINKER_PATCH_H_
18 #define ART_COMPILER_LINKER_LINKER_PATCH_H_
19 
20 #include <iosfwd>
21 #include <stdint.h>
22 
23 #include <android-base/logging.h>
24 
25 #include "base/bit_utils.h"
26 #include "base/macros.h"
27 #include "dex/method_reference.h"
28 #include "dex/proto_reference.h"
29 #include "dex/string_reference.h"
30 #include "dex/type_reference.h"
31 
32 namespace art HIDDEN {
33 
34 class DexFile;
35 
36 namespace linker {
37 
38 class LinkerPatch {
39  public:
40   // Note: We explicitly specify the underlying type of the enum because GCC
41   // would otherwise select a bigger underlying type and then complain that
42   //     'art::LinkerPatch::patch_type_' is too small to hold all
43   //     values of 'enum class art::LinkerPatch::Type'
44   // which is ridiculous given we have only a handful of values here. If we
45   // choose to squeeze the Type into fewer than 8 bits, we'll have to declare
46   // patch_type_ as an uintN_t and do explicit static_cast<>s.
47   //
48   // Note: Actual patching is instruction_set-dependent.
49   enum class Type : uint8_t {
50     kIntrinsicReference,      // Boot image reference for an intrinsic, see IntrinsicObjects.
51     kBootImageRelRo,
52     kMethodRelative,
53     kMethodBssEntry,
54     kJniEntrypointRelative,
55     kCallRelative,
56     kTypeRelative,
57     kTypeAppImageRelRo,
58     kTypeBssEntry,
59     kPublicTypeBssEntry,
60     kPackageTypeBssEntry,
61     kStringRelative,
62     kStringBssEntry,
63     kMethodTypeBssEntry,
64     kCallEntrypoint,
65     kBakerReadBarrierBranch,
66   };
67 
IntrinsicReferencePatch(size_t literal_offset,uint32_t pc_insn_offset,uint32_t intrinsic_data)68   static LinkerPatch IntrinsicReferencePatch(size_t literal_offset,
69                                              uint32_t pc_insn_offset,
70                                              uint32_t intrinsic_data) {
71     LinkerPatch patch(literal_offset, Type::kIntrinsicReference, /* target_dex_file= */ nullptr);
72     patch.intrinsic_data_ = intrinsic_data;
73     patch.pc_insn_offset_ = pc_insn_offset;
74     return patch;
75   }
76 
BootImageRelRoPatch(size_t literal_offset,uint32_t pc_insn_offset,uint32_t boot_image_offset)77   static LinkerPatch BootImageRelRoPatch(size_t literal_offset,
78                                          uint32_t pc_insn_offset,
79                                          uint32_t boot_image_offset) {
80     LinkerPatch patch(literal_offset, Type::kBootImageRelRo, /* target_dex_file= */ nullptr);
81     patch.boot_image_offset_ = boot_image_offset;
82     patch.pc_insn_offset_ = pc_insn_offset;
83     return patch;
84   }
85 
RelativeMethodPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_method_idx)86   static LinkerPatch RelativeMethodPatch(size_t literal_offset,
87                                          const DexFile* target_dex_file,
88                                          uint32_t pc_insn_offset,
89                                          uint32_t target_method_idx) {
90     LinkerPatch patch(literal_offset, Type::kMethodRelative, target_dex_file);
91     patch.method_idx_ = target_method_idx;
92     patch.pc_insn_offset_ = pc_insn_offset;
93     return patch;
94   }
95 
MethodBssEntryPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_method_idx)96   static LinkerPatch MethodBssEntryPatch(size_t literal_offset,
97                                          const DexFile* target_dex_file,
98                                          uint32_t pc_insn_offset,
99                                          uint32_t target_method_idx) {
100     LinkerPatch patch(literal_offset, Type::kMethodBssEntry, target_dex_file);
101     patch.method_idx_ = target_method_idx;
102     patch.pc_insn_offset_ = pc_insn_offset;
103     return patch;
104   }
105 
RelativeJniEntrypointPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_method_idx)106   static LinkerPatch RelativeJniEntrypointPatch(size_t literal_offset,
107                                                 const DexFile* target_dex_file,
108                                                 uint32_t pc_insn_offset,
109                                                 uint32_t target_method_idx) {
110     LinkerPatch patch(literal_offset, Type::kJniEntrypointRelative, target_dex_file);
111     patch.method_idx_ = target_method_idx;
112     patch.pc_insn_offset_ = pc_insn_offset;
113     return patch;
114   }
115 
RelativeCodePatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t target_method_idx)116   static LinkerPatch RelativeCodePatch(size_t literal_offset,
117                                        const DexFile* target_dex_file,
118                                        uint32_t target_method_idx) {
119     LinkerPatch patch(literal_offset, Type::kCallRelative, target_dex_file);
120     patch.method_idx_ = target_method_idx;
121     return patch;
122   }
123 
RelativeTypePatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_type_idx)124   static LinkerPatch RelativeTypePatch(size_t literal_offset,
125                                        const DexFile* target_dex_file,
126                                        uint32_t pc_insn_offset,
127                                        uint32_t target_type_idx) {
128     LinkerPatch patch(literal_offset, Type::kTypeRelative, target_dex_file);
129     patch.type_idx_ = target_type_idx;
130     patch.pc_insn_offset_ = pc_insn_offset;
131     return patch;
132   }
133 
TypeAppImageRelRoPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_type_idx)134   static LinkerPatch TypeAppImageRelRoPatch(size_t literal_offset,
135                                             const DexFile* target_dex_file,
136                                             uint32_t pc_insn_offset,
137                                             uint32_t target_type_idx) {
138     LinkerPatch patch(literal_offset, Type::kTypeAppImageRelRo, target_dex_file);
139     patch.type_idx_ = target_type_idx;
140     patch.pc_insn_offset_ = pc_insn_offset;
141     return patch;
142   }
143 
TypeBssEntryPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_type_idx)144   static LinkerPatch TypeBssEntryPatch(size_t literal_offset,
145                                        const DexFile* target_dex_file,
146                                        uint32_t pc_insn_offset,
147                                        uint32_t target_type_idx) {
148     LinkerPatch patch(literal_offset, Type::kTypeBssEntry, target_dex_file);
149     patch.type_idx_ = target_type_idx;
150     patch.pc_insn_offset_ = pc_insn_offset;
151     return patch;
152   }
153 
PublicTypeBssEntryPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_type_idx)154   static LinkerPatch PublicTypeBssEntryPatch(size_t literal_offset,
155                                              const DexFile* target_dex_file,
156                                              uint32_t pc_insn_offset,
157                                              uint32_t target_type_idx) {
158     LinkerPatch patch(literal_offset, Type::kPublicTypeBssEntry, target_dex_file);
159     patch.type_idx_ = target_type_idx;
160     patch.pc_insn_offset_ = pc_insn_offset;
161     return patch;
162   }
163 
PackageTypeBssEntryPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_type_idx)164   static LinkerPatch PackageTypeBssEntryPatch(size_t literal_offset,
165                                               const DexFile* target_dex_file,
166                                               uint32_t pc_insn_offset,
167                                               uint32_t target_type_idx) {
168     LinkerPatch patch(literal_offset, Type::kPackageTypeBssEntry, target_dex_file);
169     patch.type_idx_ = target_type_idx;
170     patch.pc_insn_offset_ = pc_insn_offset;
171     return patch;
172   }
173 
RelativeStringPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_string_idx)174   static LinkerPatch RelativeStringPatch(size_t literal_offset,
175                                          const DexFile* target_dex_file,
176                                          uint32_t pc_insn_offset,
177                                          uint32_t target_string_idx) {
178     LinkerPatch patch(literal_offset, Type::kStringRelative, target_dex_file);
179     patch.string_idx_ = target_string_idx;
180     patch.pc_insn_offset_ = pc_insn_offset;
181     return patch;
182   }
183 
StringBssEntryPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_string_idx)184   static LinkerPatch StringBssEntryPatch(size_t literal_offset,
185                                          const DexFile* target_dex_file,
186                                          uint32_t pc_insn_offset,
187                                          uint32_t target_string_idx) {
188     LinkerPatch patch(literal_offset, Type::kStringBssEntry, target_dex_file);
189     patch.string_idx_ = target_string_idx;
190     patch.pc_insn_offset_ = pc_insn_offset;
191     return patch;
192   }
193 
MethodTypeBssEntryPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_proto_idx)194   static LinkerPatch MethodTypeBssEntryPatch(size_t literal_offset,
195                                              const DexFile* target_dex_file,
196                                              uint32_t pc_insn_offset,
197                                              uint32_t target_proto_idx) {
198     LinkerPatch patch(literal_offset, Type::kMethodTypeBssEntry, target_dex_file);
199     patch.proto_idx_ = target_proto_idx;
200     patch.pc_insn_offset_ = pc_insn_offset;
201     return patch;
202   }
203 
CallEntrypointPatch(size_t literal_offset,uint32_t entrypoint_offset)204   static LinkerPatch CallEntrypointPatch(size_t literal_offset,
205                                          uint32_t entrypoint_offset) {
206     LinkerPatch patch(literal_offset,
207                       Type::kCallEntrypoint,
208                       /* target_dex_file= */ nullptr);
209     patch.entrypoint_offset_ = entrypoint_offset;
210     return patch;
211   }
212 
213   static LinkerPatch BakerReadBarrierBranchPatch(size_t literal_offset,
214                                                  uint32_t custom_value1 = 0u,
215                                                  uint32_t custom_value2 = 0u) {
216     LinkerPatch patch(literal_offset,
217                       Type::kBakerReadBarrierBranch,
218                       /* target_dex_file= */ nullptr);
219     patch.baker_custom_value1_ = custom_value1;
220     patch.baker_custom_value2_ = custom_value2;
221     return patch;
222   }
223 
224   LinkerPatch(const LinkerPatch& other) = default;
225   LinkerPatch& operator=(const LinkerPatch& other) = default;
226 
LiteralOffset()227   size_t LiteralOffset() const {
228     return literal_offset_;
229   }
230 
GetType()231   Type GetType() const {
232     return patch_type_;
233   }
234 
IntrinsicData()235   uint32_t IntrinsicData() const {
236     DCHECK(patch_type_ == Type::kIntrinsicReference);
237     return intrinsic_data_;
238   }
239 
BootImageOffset()240   uint32_t BootImageOffset() const {
241     DCHECK(patch_type_ == Type::kBootImageRelRo);
242     return boot_image_offset_;
243   }
244 
TargetMethod()245   MethodReference TargetMethod() const {
246     DCHECK(patch_type_ == Type::kMethodRelative ||
247            patch_type_ == Type::kMethodBssEntry ||
248            patch_type_ == Type::kJniEntrypointRelative ||
249            patch_type_ == Type::kCallRelative);
250     return MethodReference(target_dex_file_, method_idx_);
251   }
252 
TargetType()253   TypeReference TargetType() const {
254     DCHECK(patch_type_ == Type::kTypeRelative ||
255            patch_type_ == Type::kTypeAppImageRelRo ||
256            patch_type_ == Type::kTypeBssEntry ||
257            patch_type_ == Type::kPublicTypeBssEntry ||
258            patch_type_ == Type::kPackageTypeBssEntry);
259     return TypeReference(target_dex_file_, dex::TypeIndex(type_idx_));
260   }
261 
TargetString()262   StringReference TargetString() const {
263     DCHECK(patch_type_ == Type::kStringRelative ||
264            patch_type_ == Type::kStringBssEntry);
265     return StringReference(target_dex_file_, dex::StringIndex(string_idx_));
266   }
267 
TargetProto()268   ProtoReference TargetProto() const {
269     DCHECK(patch_type_ == Type::kMethodTypeBssEntry);
270     return ProtoReference(target_dex_file_, dex::ProtoIndex(proto_idx_));
271   }
272 
PcInsnOffset()273   uint32_t PcInsnOffset() const {
274     DCHECK(patch_type_ == Type::kIntrinsicReference ||
275            patch_type_ == Type::kBootImageRelRo ||
276            patch_type_ == Type::kMethodRelative ||
277            patch_type_ == Type::kMethodBssEntry ||
278            patch_type_ == Type::kJniEntrypointRelative ||
279            patch_type_ == Type::kTypeRelative ||
280            patch_type_ == Type::kTypeAppImageRelRo ||
281            patch_type_ == Type::kTypeBssEntry ||
282            patch_type_ == Type::kPublicTypeBssEntry ||
283            patch_type_ == Type::kPackageTypeBssEntry ||
284            patch_type_ == Type::kStringRelative ||
285            patch_type_ == Type::kStringBssEntry);
286     return pc_insn_offset_;
287   }
288 
EntrypointOffset()289   uint32_t EntrypointOffset() const {
290     DCHECK(patch_type_ == Type::kCallEntrypoint);
291     return entrypoint_offset_;
292   }
293 
GetBakerCustomValue1()294   uint32_t GetBakerCustomValue1() const {
295     DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
296     return baker_custom_value1_;
297   }
298 
GetBakerCustomValue2()299   uint32_t GetBakerCustomValue2() const {
300     DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
301     return baker_custom_value2_;
302   }
303 
304  private:
LinkerPatch(size_t literal_offset,Type patch_type,const DexFile * target_dex_file)305   LinkerPatch(size_t literal_offset, Type patch_type, const DexFile* target_dex_file)
306       : target_dex_file_(target_dex_file),
307         literal_offset_(literal_offset),
308         patch_type_(patch_type) {
309     cmp1_ = 0u;
310     cmp2_ = 0u;
311     // The compiler rejects methods that are too big, so the compiled code
312     // of a single method really shouln't be anywhere close to 16MiB.
313     DCHECK(IsUint<24>(literal_offset));
314   }
315 
316   const DexFile* target_dex_file_;
317   // TODO: Clean up naming. Some patched locations are literals but others are not.
318   uint32_t literal_offset_ : 24;  // Method code size up to 16MiB.
319   Type patch_type_ : 8;
320   union {
321     uint32_t cmp1_;               // Used for relational operators.
322     uint32_t boot_image_offset_;  // Data to write to the boot image .data.img.rel.ro entry.
323     uint32_t method_idx_;         // Method index for Call/Method patches.
324     uint32_t type_idx_;           // Type index for Type patches.
325     uint32_t string_idx_;         // String index for String patches.
326     uint32_t proto_idx_;          // Proto index for MethodType patches.
327     uint32_t intrinsic_data_;     // Data for IntrinsicObjects.
328     uint32_t entrypoint_offset_;  // Entrypoint offset in the Thread object.
329     uint32_t baker_custom_value1_;
330     static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators");
331     static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators");
332     static_assert(sizeof(string_idx_) == sizeof(cmp1_), "needed by relational operators");
333     static_assert(sizeof(proto_idx_) == sizeof(cmp1_), "needed by relational operators");
334     static_assert(sizeof(intrinsic_data_) == sizeof(cmp1_), "needed by relational operators");
335     static_assert(sizeof(baker_custom_value1_) == sizeof(cmp1_), "needed by relational operators");
336   };
337   union {
338     // Note: To avoid uninitialized padding on 64-bit systems, we use `size_t` for `cmp2_`.
339     // This allows a hashing function to treat an array of linker patches as raw memory.
340     size_t cmp2_;             // Used for relational operators.
341     // Literal offset of the insn loading PC (same as literal_offset if it's the same insn,
342     // may be different if the PC-relative addressing needs multiple insns).
343     uint32_t pc_insn_offset_;
344     uint32_t baker_custom_value2_;
345     static_assert(sizeof(pc_insn_offset_) <= sizeof(cmp2_), "needed by relational operators");
346     static_assert(sizeof(baker_custom_value2_) <= sizeof(cmp2_), "needed by relational operators");
347   };
348 
349   friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs);
350   friend bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs);
351 };
352 EXPORT std::ostream& operator<<(std::ostream& os, LinkerPatch::Type type);
353 
354 inline bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs) {
355   return lhs.literal_offset_ == rhs.literal_offset_ &&
356       lhs.patch_type_ == rhs.patch_type_ &&
357       lhs.target_dex_file_ == rhs.target_dex_file_ &&
358       lhs.cmp1_ == rhs.cmp1_ &&
359       lhs.cmp2_ == rhs.cmp2_;
360 }
361 
362 inline bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs) {
363   return (lhs.literal_offset_ != rhs.literal_offset_) ? lhs.literal_offset_ < rhs.literal_offset_
364       : (lhs.patch_type_ != rhs.patch_type_) ? lhs.patch_type_ < rhs.patch_type_
365       : (lhs.target_dex_file_ != rhs.target_dex_file_) ? lhs.target_dex_file_ < rhs.target_dex_file_
366       : (lhs.cmp1_ != rhs.cmp1_) ? lhs.cmp1_ < rhs.cmp1_
367       : lhs.cmp2_ < rhs.cmp2_;
368 }
369 
370 }  // namespace linker
371 }  // namespace art
372 
373 #endif  // ART_COMPILER_LINKER_LINKER_PATCH_H_
374