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