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