Patching-x86-shared.h (3808B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_x86_shared_Patching_x86_shared_h 8 #define jit_x86_shared_Patching_x86_shared_h 9 10 namespace js { 11 namespace jit { 12 13 namespace X86Encoding { 14 15 inline void* GetPointer(const void* where) { 16 void* res; 17 memcpy(&res, (const char*)where - sizeof(void*), sizeof(void*)); 18 return res; 19 } 20 21 inline void SetPointer(void* where, const void* value) { 22 memcpy((char*)where - sizeof(void*), &value, sizeof(void*)); 23 } 24 25 inline int32_t GetInt32(const void* where) { 26 int32_t res; 27 memcpy(&res, (const char*)where - sizeof(int32_t), sizeof(int32_t)); 28 return res; 29 } 30 31 inline void SetInt32(void* where, int32_t value, uint32_t trailing = 0) { 32 memcpy((char*)where - trailing - sizeof(int32_t), &value, sizeof(int32_t)); 33 } 34 35 inline void SetRel32(void* from, void* to, uint32_t trailing = 0) { 36 intptr_t offset = 37 reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from); 38 MOZ_ASSERT(offset == static_cast<int32_t>(offset), 39 "offset is too great for a 32-bit relocation"); 40 if (offset != static_cast<int32_t>(offset)) { 41 MOZ_CRASH("offset is too great for a 32-bit relocation"); 42 } 43 44 SetInt32(from, offset, trailing); 45 } 46 47 inline void* GetRel32Target(void* where) { 48 int32_t rel = GetInt32(where); 49 return (char*)where + rel; 50 } 51 52 // JmpSrc represents a positive offset within a code buffer, or an uninitialized 53 // value. Lots of code depends on uninitialized JmpSrc holding the value -1, on 54 // -1 being a legal value of JmpSrc, and on being able to initialize a JmpSrc 55 // with the value -1. 56 // 57 // The value of the `offset` is always positive and <= MaxCodeBytesPerProcess, 58 // see ProcessExecutableMemory.h. The latter quantity in turn must fit in an 59 // i32. But we further require that the value is not precisely INT32_MAX, so as 60 // to allow the JmpSrc value -1 to mean "uninitialized" without ambiguity. 61 // 62 // The quantity `trailing` denotes the number of bytes of data that follow the 63 // patch field in the instruction. The offset points to the end of the 64 // instruction as per normal. The information about trailing bytes is needed 65 // separately from the offset to correctly patch instructions that have 66 // immediates trailing the patch field (eg CMPSS and CMPSD). Currently the only 67 // allowed values for `trailing` are 0 and 1. 68 69 static_assert(MaxCodeBytesPerProcess < size_t(INT32_MAX), "Invariant"); 70 71 class JmpSrc { 72 public: 73 JmpSrc() : offset_(INT32_MAX), trailing_(0) {} 74 explicit JmpSrc(int32_t offset) : offset_(offset), trailing_(0) { 75 // offset -1 is stored as INT32_MAX 76 MOZ_ASSERT(offset == -1 || (offset >= 0 && offset < INT32_MAX)); 77 } 78 JmpSrc(int32_t offset, uint32_t trailing) 79 : offset_(offset), trailing_(trailing) { 80 // Disallow offset -1 in this situation, it does not apply. 81 MOZ_ASSERT(offset >= 0 && offset < INT32_MAX); 82 MOZ_ASSERT(trailing <= 1); 83 } 84 int32_t offset() const { 85 return offset_ == INT32_MAX ? -1 : int32_t(offset_); 86 } 87 uint32_t trailing() const { return trailing_; } 88 89 private: 90 uint32_t offset_ : 31; 91 uint32_t trailing_ : 1; 92 }; 93 94 class JmpDst { 95 public: 96 explicit JmpDst(int32_t offset) : offset_(offset) {} 97 int32_t offset() const { return offset_; } 98 99 private: 100 int32_t offset_; 101 }; 102 103 inline bool CanRelinkJump(void* from, void* to) { 104 intptr_t offset = static_cast<char*>(to) - static_cast<char*>(from); 105 return (offset == static_cast<int32_t>(offset)); 106 } 107 108 } // namespace X86Encoding 109 110 } // namespace jit 111 } // namespace js 112 113 #endif /* jit_x86_shared_Patching_x86_shared_h */