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