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 kCallRelative, 51 kTypeRelative, 52 kTypeBssEntry, 53 kStringRelative, 54 kStringBssEntry, 55 kCallEntrypoint, 56 kBakerReadBarrierBranch, 57 }; 58 IntrinsicReferencePatch(size_t literal_offset,uint32_t pc_insn_offset,uint32_t intrinsic_data)59 static LinkerPatch IntrinsicReferencePatch(size_t literal_offset, 60 uint32_t pc_insn_offset, 61 uint32_t intrinsic_data) { 62 LinkerPatch patch(literal_offset, Type::kIntrinsicReference, /* target_dex_file= */ nullptr); 63 patch.intrinsic_data_ = intrinsic_data; 64 patch.pc_insn_offset_ = pc_insn_offset; 65 return patch; 66 } 67 DataBimgRelRoPatch(size_t literal_offset,uint32_t pc_insn_offset,uint32_t boot_image_offset)68 static LinkerPatch DataBimgRelRoPatch(size_t literal_offset, 69 uint32_t pc_insn_offset, 70 uint32_t boot_image_offset) { 71 LinkerPatch patch(literal_offset, Type::kDataBimgRelRo, /* target_dex_file= */ nullptr); 72 patch.boot_image_offset_ = boot_image_offset; 73 patch.pc_insn_offset_ = pc_insn_offset; 74 return patch; 75 } 76 RelativeMethodPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_method_idx)77 static LinkerPatch RelativeMethodPatch(size_t literal_offset, 78 const DexFile* target_dex_file, 79 uint32_t pc_insn_offset, 80 uint32_t target_method_idx) { 81 LinkerPatch patch(literal_offset, Type::kMethodRelative, target_dex_file); 82 patch.method_idx_ = target_method_idx; 83 patch.pc_insn_offset_ = pc_insn_offset; 84 return patch; 85 } 86 MethodBssEntryPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_method_idx)87 static LinkerPatch MethodBssEntryPatch(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::kMethodBssEntry, target_dex_file); 92 patch.method_idx_ = target_method_idx; 93 patch.pc_insn_offset_ = pc_insn_offset; 94 return patch; 95 } 96 RelativeCodePatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t target_method_idx)97 static LinkerPatch RelativeCodePatch(size_t literal_offset, 98 const DexFile* target_dex_file, 99 uint32_t target_method_idx) { 100 LinkerPatch patch(literal_offset, Type::kCallRelative, target_dex_file); 101 patch.method_idx_ = target_method_idx; 102 return patch; 103 } 104 RelativeTypePatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_type_idx)105 static LinkerPatch RelativeTypePatch(size_t literal_offset, 106 const DexFile* target_dex_file, 107 uint32_t pc_insn_offset, 108 uint32_t target_type_idx) { 109 LinkerPatch patch(literal_offset, Type::kTypeRelative, target_dex_file); 110 patch.type_idx_ = target_type_idx; 111 patch.pc_insn_offset_ = pc_insn_offset; 112 return patch; 113 } 114 TypeBssEntryPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_type_idx)115 static LinkerPatch TypeBssEntryPatch(size_t literal_offset, 116 const DexFile* target_dex_file, 117 uint32_t pc_insn_offset, 118 uint32_t target_type_idx) { 119 LinkerPatch patch(literal_offset, Type::kTypeBssEntry, target_dex_file); 120 patch.type_idx_ = target_type_idx; 121 patch.pc_insn_offset_ = pc_insn_offset; 122 return patch; 123 } 124 RelativeStringPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_string_idx)125 static LinkerPatch RelativeStringPatch(size_t literal_offset, 126 const DexFile* target_dex_file, 127 uint32_t pc_insn_offset, 128 uint32_t target_string_idx) { 129 LinkerPatch patch(literal_offset, Type::kStringRelative, target_dex_file); 130 patch.string_idx_ = target_string_idx; 131 patch.pc_insn_offset_ = pc_insn_offset; 132 return patch; 133 } 134 StringBssEntryPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t target_string_idx)135 static LinkerPatch StringBssEntryPatch(size_t literal_offset, 136 const DexFile* target_dex_file, 137 uint32_t pc_insn_offset, 138 uint32_t target_string_idx) { 139 LinkerPatch patch(literal_offset, Type::kStringBssEntry, target_dex_file); 140 patch.string_idx_ = target_string_idx; 141 patch.pc_insn_offset_ = pc_insn_offset; 142 return patch; 143 } 144 CallEntrypointPatch(size_t literal_offset,uint32_t entrypoint_offset)145 static LinkerPatch CallEntrypointPatch(size_t literal_offset, 146 uint32_t entrypoint_offset) { 147 LinkerPatch patch(literal_offset, 148 Type::kCallEntrypoint, 149 /* target_dex_file= */ nullptr); 150 patch.entrypoint_offset_ = entrypoint_offset; 151 return patch; 152 } 153 154 static LinkerPatch BakerReadBarrierBranchPatch(size_t literal_offset, 155 uint32_t custom_value1 = 0u, 156 uint32_t custom_value2 = 0u) { 157 LinkerPatch patch(literal_offset, 158 Type::kBakerReadBarrierBranch, 159 /* target_dex_file= */ nullptr); 160 patch.baker_custom_value1_ = custom_value1; 161 patch.baker_custom_value2_ = custom_value2; 162 return patch; 163 } 164 165 LinkerPatch(const LinkerPatch& other) = default; 166 LinkerPatch& operator=(const LinkerPatch& other) = default; 167 LiteralOffset()168 size_t LiteralOffset() const { 169 return literal_offset_; 170 } 171 GetType()172 Type GetType() const { 173 return patch_type_; 174 } 175 IntrinsicData()176 uint32_t IntrinsicData() const { 177 DCHECK(patch_type_ == Type::kIntrinsicReference); 178 return intrinsic_data_; 179 } 180 BootImageOffset()181 uint32_t BootImageOffset() const { 182 DCHECK(patch_type_ == Type::kDataBimgRelRo); 183 return boot_image_offset_; 184 } 185 TargetMethod()186 MethodReference TargetMethod() const { 187 DCHECK(patch_type_ == Type::kMethodRelative || 188 patch_type_ == Type::kMethodBssEntry || 189 patch_type_ == Type::kCallRelative); 190 return MethodReference(target_dex_file_, method_idx_); 191 } 192 TargetTypeDexFile()193 const DexFile* TargetTypeDexFile() const { 194 DCHECK(patch_type_ == Type::kTypeRelative || 195 patch_type_ == Type::kTypeBssEntry); 196 return target_dex_file_; 197 } 198 TargetTypeIndex()199 dex::TypeIndex TargetTypeIndex() const { 200 DCHECK(patch_type_ == Type::kTypeRelative || 201 patch_type_ == Type::kTypeBssEntry); 202 return dex::TypeIndex(type_idx_); 203 } 204 TargetStringDexFile()205 const DexFile* TargetStringDexFile() const { 206 DCHECK(patch_type_ == Type::kStringRelative || 207 patch_type_ == Type::kStringBssEntry); 208 return target_dex_file_; 209 } 210 TargetStringIndex()211 dex::StringIndex TargetStringIndex() const { 212 DCHECK(patch_type_ == Type::kStringRelative || 213 patch_type_ == Type::kStringBssEntry); 214 return dex::StringIndex(string_idx_); 215 } 216 PcInsnOffset()217 uint32_t PcInsnOffset() const { 218 DCHECK(patch_type_ == Type::kIntrinsicReference || 219 patch_type_ == Type::kDataBimgRelRo || 220 patch_type_ == Type::kMethodRelative || 221 patch_type_ == Type::kMethodBssEntry || 222 patch_type_ == Type::kTypeRelative || 223 patch_type_ == Type::kTypeBssEntry || 224 patch_type_ == Type::kStringRelative || 225 patch_type_ == Type::kStringBssEntry); 226 return pc_insn_offset_; 227 } 228 EntrypointOffset()229 uint32_t EntrypointOffset() const { 230 DCHECK(patch_type_ == Type::kCallEntrypoint); 231 return entrypoint_offset_; 232 } 233 GetBakerCustomValue1()234 uint32_t GetBakerCustomValue1() const { 235 DCHECK(patch_type_ == Type::kBakerReadBarrierBranch); 236 return baker_custom_value1_; 237 } 238 GetBakerCustomValue2()239 uint32_t GetBakerCustomValue2() const { 240 DCHECK(patch_type_ == Type::kBakerReadBarrierBranch); 241 return baker_custom_value2_; 242 } 243 244 private: LinkerPatch(size_t literal_offset,Type patch_type,const DexFile * target_dex_file)245 LinkerPatch(size_t literal_offset, Type patch_type, const DexFile* target_dex_file) 246 : target_dex_file_(target_dex_file), 247 literal_offset_(literal_offset), 248 patch_type_(patch_type) { 249 cmp1_ = 0u; 250 cmp2_ = 0u; 251 // The compiler rejects methods that are too big, so the compiled code 252 // of a single method really shouln't be anywhere close to 16MiB. 253 DCHECK(IsUint<24>(literal_offset)); 254 } 255 256 const DexFile* target_dex_file_; 257 // TODO: Clean up naming. Some patched locations are literals but others are not. 258 uint32_t literal_offset_ : 24; // Method code size up to 16MiB. 259 Type patch_type_ : 8; 260 union { 261 uint32_t cmp1_; // Used for relational operators. 262 uint32_t boot_image_offset_; // Data to write to the .data.bimg.rel.ro entry. 263 uint32_t method_idx_; // Method index for Call/Method patches. 264 uint32_t type_idx_; // Type index for Type patches. 265 uint32_t string_idx_; // String index for String patches. 266 uint32_t intrinsic_data_; // Data for IntrinsicObjects. 267 uint32_t entrypoint_offset_; // Entrypoint offset in the Thread object. 268 uint32_t baker_custom_value1_; 269 static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators"); 270 static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators"); 271 static_assert(sizeof(string_idx_) == sizeof(cmp1_), "needed by relational operators"); 272 static_assert(sizeof(intrinsic_data_) == sizeof(cmp1_), "needed by relational operators"); 273 static_assert(sizeof(baker_custom_value1_) == sizeof(cmp1_), "needed by relational operators"); 274 }; 275 union { 276 // Note: To avoid uninitialized padding on 64-bit systems, we use `size_t` for `cmp2_`. 277 // This allows a hashing function to treat an array of linker patches as raw memory. 278 size_t cmp2_; // Used for relational operators. 279 // Literal offset of the insn loading PC (same as literal_offset if it's the same insn, 280 // may be different if the PC-relative addressing needs multiple insns). 281 uint32_t pc_insn_offset_; 282 uint32_t baker_custom_value2_; 283 static_assert(sizeof(pc_insn_offset_) <= sizeof(cmp2_), "needed by relational operators"); 284 static_assert(sizeof(baker_custom_value2_) <= sizeof(cmp2_), "needed by relational operators"); 285 }; 286 287 friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs); 288 friend bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs); 289 }; 290 std::ostream& operator<<(std::ostream& os, LinkerPatch::Type type); 291 292 inline bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs) { 293 return lhs.literal_offset_ == rhs.literal_offset_ && 294 lhs.patch_type_ == rhs.patch_type_ && 295 lhs.target_dex_file_ == rhs.target_dex_file_ && 296 lhs.cmp1_ == rhs.cmp1_ && 297 lhs.cmp2_ == rhs.cmp2_; 298 } 299 300 inline bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs) { 301 return (lhs.literal_offset_ != rhs.literal_offset_) ? lhs.literal_offset_ < rhs.literal_offset_ 302 : (lhs.patch_type_ != rhs.patch_type_) ? lhs.patch_type_ < rhs.patch_type_ 303 : (lhs.target_dex_file_ != rhs.target_dex_file_) ? lhs.target_dex_file_ < rhs.target_dex_file_ 304 : (lhs.cmp1_ != rhs.cmp1_) ? lhs.cmp1_ < rhs.cmp1_ 305 : lhs.cmp2_ < rhs.cmp2_; 306 } 307 308 } // namespace linker 309 } // namespace art 310 311 #endif // ART_COMPILER_LINKER_LINKER_PATCH_H_ 312