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