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