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