CommonLibSSE NG
Relocation.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "REL/ID.h"
4 #include "REL/Module.h"
5 
6 #include "SKSE/Trampoline.h"
7 
8 #define REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_nopropQual, a_propQual, ...) \
9  template < \
10  class R, \
11  class Cls, \
12  class... Args> \
13  struct member_function_pod_type<R (Cls::*)(Args...) __VA_ARGS__ a_nopropQual a_propQual> \
14  { \
15  using type = R(__VA_ARGS__ Cls*, Args...) a_propQual; \
16  }; \
17  \
18  template < \
19  class R, \
20  class Cls, \
21  class... Args> \
22  struct member_function_pod_type<R (Cls::*)(Args..., ...) __VA_ARGS__ a_nopropQual a_propQual> \
23  { \
24  using type = R(__VA_ARGS__ Cls*, Args..., ...) a_propQual; \
25  };
26 
27 #define REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(a_qualifer, ...) \
28  REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_qualifer, , ##__VA_ARGS__) \
29  REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_qualifer, noexcept, ##__VA_ARGS__)
30 
31 #define REL_MAKE_MEMBER_FUNCTION_POD_TYPE(...) \
32  REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(, __VA_ARGS__) \
33  REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(&, ##__VA_ARGS__) \
34  REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(&&, ##__VA_ARGS__)
35 
36 #define REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL(a_nopropQual, a_propQual, ...) \
37  template < \
38  class R, \
39  class Cls, \
40  class... Args> \
41  struct member_function_non_pod_type<R (Cls::*)(Args...) __VA_ARGS__ a_nopropQual a_propQual> \
42  { \
43  using type = R&(__VA_ARGS__ Cls*, void*, Args...)a_propQual; \
44  }; \
45  \
46  template < \
47  class R, \
48  class Cls, \
49  class... Args> \
50  struct member_function_non_pod_type<R (Cls::*)(Args..., ...) __VA_ARGS__ a_nopropQual a_propQual> \
51  { \
52  using type = R&(__VA_ARGS__ Cls*, void*, Args..., ...)a_propQual; \
53  };
54 
55 #define REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(a_qualifer, ...) \
56  REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL(a_qualifer, , ##__VA_ARGS__) \
57  REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL(a_qualifer, noexcept, ##__VA_ARGS__)
58 
59 #define REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE(...) \
60  REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(, __VA_ARGS__) \
61  REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(&, ##__VA_ARGS__) \
62  REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(&&, ##__VA_ARGS__)
63 
64 namespace REL
65 {
66  namespace detail
67  {
68  template<class>
70 
74  REL_MAKE_MEMBER_FUNCTION_POD_TYPE(const volatile);
75 
76  template<class F>
78 
79  template<class>
81 
86 
87  template<class F>
89 
90  // https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
91 
92  template<class T>
94  std::disjunction<
95  std::bool_constant<sizeof(T) == 1>,
96  std::bool_constant<sizeof(T) == 2>,
97  std::bool_constant<sizeof(T) == 4>,
98  std::bool_constant<sizeof(T) == 8>>
99  {};
100 
101  template<class T>
103  std::conjunction<
104  std::is_trivially_constructible<T>,
105  std::is_trivially_destructible<T>,
106  std::is_trivially_copy_assignable<T>,
107  std::negation<
108  std::is_polymorphic<T>>>
109  {};
110 
111  template<class T>
112  struct meets_member_req : std::is_standard_layout<T> {};
113 
114  template<class T, class = void>
115  struct is_x64_pod : std::true_type {};
116 
117  template<class T>
118  struct is_x64_pod<
119  T,
120  std::enable_if_t<
121  std::is_union_v<T>>> :
122  std::false_type {};
123 
124  template<class T>
125  struct is_x64_pod<
126  T,
127  std::enable_if_t<
128  std::is_class_v<T>>> :
129  std::conjunction<
130  meets_length_req<T>,
131  meets_function_req<T>,
132  meets_member_req<T>> {};
133 
134  template<class T>
135  inline constexpr bool is_x64_pod_v = is_x64_pod<T>::value;
136 
137  template<
138  class F,
139  class First,
140  class... Rest>
141  decltype(auto) invoke_member_function_non_pod(F&& a_func, First&& a_first, Rest&& ... a_rest) //
142  noexcept(std::is_nothrow_invocable_v<F, First, Rest...>) {
143  using result_t = std::invoke_result_t<F, First, Rest...>;
144  std::aligned_storage_t<sizeof(result_t), alignof(result_t)> result;
145 
146  using func_t = member_function_non_pod_type_t<F>;
147  auto func = stl::unrestricted_cast<func_t*>(std::forward<F>(a_func));
148 
149  return func(std::forward<First>(a_first), std::addressof(result), std::forward<Rest>(a_rest)...);
150  }
151  }
152 
153  inline constexpr std::uint8_t NOP = 0x90;
154  inline constexpr std::uint8_t NOP2[] = { 0x66, 0x90 };
155  inline constexpr std::uint8_t NOP3[] = { 0x0F, 0x1F, 0x00 };
156  inline constexpr std::uint8_t NOP4[] = { 0x0F, 0x1F, 0x40, 0x00 };
157  inline constexpr std::uint8_t NOP5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 };
158  inline constexpr std::uint8_t NOP6[] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 };
159  inline constexpr std::uint8_t NOP7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
160  inline constexpr std::uint8_t NOP8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
161  inline constexpr std::uint8_t NOP9[] = { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
162 
163  inline constexpr std::uint8_t JMP8 = 0xEB;
164  inline constexpr std::uint8_t JMP32 = 0xE9;
165  inline constexpr std::uint8_t RET = 0xC3;
166  inline constexpr std::uint8_t INT3 = 0xCC;
167 
168  template<class F, class... Args>
169  std::invoke_result_t<F, Args...> invoke(F&& a_func, Args&&... a_args)
170  noexcept(std::is_nothrow_invocable_v<F, Args...>)
171  requires(std::invocable<F, Args...>)
172  {
173  if constexpr (std::is_member_function_pointer_v<std::decay_t<F>>) {
174  if constexpr (detail::is_x64_pod_v<std::invoke_result_t<F, Args...>>) { // member functions == free functions in x64
176  auto func = stl::unrestricted_cast<func_t *>(std::forward<F>(a_func));
177  return func(std::forward<Args>(a_args)...);
178  } else { // shift args to insert result
179  return detail::invoke_member_function_non_pod(std::forward<F>(a_func), std::forward<Args>(a_args)...);
180  }
181  } else {
182  return std::forward<F>(a_func)(std::forward<Args>(a_args)...);
183  }
184  }
185 
186  void safe_write(std::uintptr_t a_dst, const void* a_src, std::size_t a_count);
187 
188  template<std::integral T>
189  void safe_write(std::uintptr_t a_dst, const T& a_data)
190  {
191  safe_write(a_dst, std::addressof(a_data), sizeof(T));
192  }
193 
194  template<class T>
195  void safe_write(std::uintptr_t a_dst, std::span<T> a_data)
196  {
197  safe_write(a_dst, a_data.data(), a_data.size_bytes());
198  }
199 
200  void safe_fill(std::uintptr_t a_dst, std::uint8_t a_value, std::size_t a_count);
201 
202  template <class T = std::uintptr_t>
204  {
205  public:
206  using value_type =
207  std::conditional_t<
208  std::is_member_pointer_v<T> || std::is_function_v<std::remove_pointer_t<T>>,
209  std::decay_t<T>,
210  T>;
211 
212  constexpr Relocation() noexcept = default;
213 
214  explicit constexpr Relocation(std::uintptr_t a_address) noexcept:
215  _impl{a_address}
216  {}
217 
218  explicit Relocation(Offset a_offset) :
219  _impl{a_offset.address()}
220  {}
221 
222  explicit Relocation(VariantOffset a_offset) :
223  _impl{a_offset.address()}
224  {}
225 
226  explicit Relocation(ID a_id) :
227  _impl{a_id.address()}
228  {}
229 
230  explicit Relocation(ID a_id, std::ptrdiff_t a_offset) :
231  _impl{a_id.address() + a_offset}
232  {}
233 
234  explicit Relocation(ID a_id, Offset a_offset) :
235  _impl{a_id.address() + a_offset.offset()}
236  {}
237 
238  explicit Relocation(ID a_id, VariantOffset a_offset) :
239  _impl{a_id.address() + a_offset.offset()}
240  {}
241 
242  explicit Relocation(RelocationID a_id) :
243  _impl{a_id.address()}
244  {}
245 
246  explicit Relocation(RelocationID a_id, std::ptrdiff_t a_offset) :
247  _impl{a_id.address() + a_offset}
248  {}
249 
250  explicit Relocation(RelocationID a_id, Offset a_offset) :
251  _impl{a_id.address() + a_offset.offset()}
252  {}
253 
254  explicit Relocation(RelocationID a_id, VariantOffset a_offset) :
255  _impl{a_id.address() + a_offset.offset()}
256  {}
257 
258  explicit Relocation(VariantID a_id) :
259  _impl{a_id.address()}
260  {}
261 
262  explicit Relocation(VariantID a_id, std::ptrdiff_t a_offset) :
263  _impl{a_id.address() + a_offset}
264  {}
265 
266  explicit Relocation(VariantID a_id, Offset a_offset) :
267  _impl{a_id.address() + a_offset.offset()}
268  {}
269 
270  explicit Relocation(VariantID a_id, VariantOffset a_offset) :
271  _impl{a_id.address() + a_offset.offset()}
272  {}
273 
274  constexpr Relocation &operator=(std::uintptr_t a_address) noexcept
275  {
276  _impl = a_address;
277  return *this;
278  }
279 
281  {
282  _impl = a_offset.address();
283  return *this;
284  }
285 
287  {
288  _impl = a_offset.address();
289  return *this;
290  }
291 
293  {
294  _impl = a_id.address();
295  return *this;
296  }
297 
299  {
300  _impl = a_id.address();
301  return *this;
302  }
303 
305  {
306  _impl = a_id.address();
307  return *this;
308  }
309 
310  template<class U = value_type>
311  [[nodiscard]] decltype(auto) operator*() const noexcept
312  requires(std::is_pointer_v<U>)
313  {
314  return *get();
315  }
316 
317  template<class U = value_type>
318  [[nodiscard]] auto operator->() const noexcept
319  requires(std::is_pointer_v<U>)
320  {
321  return get();
322  }
323 
324  template<class... Args>
325  std::invoke_result_t<const value_type &, Args...> operator()(Args &&... a_args) const
326  noexcept(std::is_nothrow_invocable_v<const value_type &, Args...>)
327  requires(std::invocable<const value_type &, Args...>)
328  {
329  return REL::invoke(get(), std::forward<Args>(a_args)...);
330  }
331 
332  [[nodiscard]] constexpr std::uintptr_t address() const noexcept { return _impl; }
333 
334  [[nodiscard]] std::size_t offset() const { return _impl - base(); }
335 
336  [[nodiscard]] value_type get() const
337  noexcept(std::is_nothrow_copy_constructible_v<value_type>)
338  {
339  assert(_impl != 0);
340  return stl::unrestricted_cast<value_type>(_impl);
341  }
342 
343  template <std::integral U>
344  void write(const U& a_data)
345  requires(std::same_as<value_type, std::uintptr_t>)
346  {
347  safe_write(address(), std::addressof(a_data), sizeof(T));
348  }
349 
350  template <class U>
351  void write(const std::span<U> a_data)
352  requires(std::same_as<value_type, std::uintptr_t>)
353  {
354  safe_write(address(), a_data.data(), a_data.size_bytes());
355  }
356 
357  template <std::size_t N>
358  std::uintptr_t write_branch(const std::uintptr_t a_dst)
359  requires(std::same_as<value_type, std::uintptr_t>)
360  {
361  return SKSE::GetTrampoline().write_branch<N>(address(), a_dst);
362  }
363 
364  template <std::size_t N, class F>
365  std::uintptr_t write_branch(const F a_dst)
366  requires(std::same_as<value_type, std::uintptr_t>)
367  {
368  return SKSE::GetTrampoline().write_branch<N>(address(), stl::unrestricted_cast<std::uintptr_t>(a_dst));
369  }
370 
371  template <std::size_t N>
372  std::uintptr_t write_call(const std::uintptr_t a_dst)
373  requires(std::same_as<value_type, std::uintptr_t>)
374  {
375  return SKSE::GetTrampoline().write_call<N>(address(), a_dst);
376  }
377 
378  template <std::size_t N, class F>
379  std::uintptr_t write_call(const F a_dst)
380  requires(std::same_as<value_type, std::uintptr_t>)
381  {
382  return SKSE::GetTrampoline().write_call<N>(address(), stl::unrestricted_cast<std::uintptr_t>(a_dst));
383  }
384 
385  void write_fill(const std::uint8_t a_value, const std::size_t a_count)
386  requires(std::same_as<value_type, std::uintptr_t>)
387  {
388  safe_fill(address(), a_value, a_count);
389  }
390 
391  template <class U = value_type>
392  std::uintptr_t write_vfunc(const std::size_t a_idx, const std::uintptr_t a_newFunc)
393  requires(std::same_as<U, std::uintptr_t>)
394  {
395  const auto addr = address() + (sizeof(void *) * a_idx);
396  const auto result = *reinterpret_cast<std::uintptr_t *>(addr);
397  safe_write(addr, a_newFunc);
398  return result;
399  }
400 
401  template<class F>
402  std::uintptr_t write_vfunc(std::size_t a_idx, F a_newFunc)
403  requires(std::same_as<value_type, std::uintptr_t>)
404  {
405  return write_vfunc(a_idx, stl::unrestricted_cast<std::uintptr_t>(a_newFunc));
406  }
407 
408  private:
409  // clang-format off
410  [[nodiscard]] static std::uintptr_t base() { return Module::get().base(); }
411  // clang-format on
412 
413  std::uintptr_t _impl{0};
414  };
415 
431  template<class T>
432  [[nodiscard]] SKYRIM_ADDR T Relocate(
433  [[maybe_unused]] T&& a_seAndVR,
434  [[maybe_unused]] T&& a_ae) noexcept
435  {
436 #ifndef ENABLE_SKYRIM_AE
437  return a_seAndVR;
438 #elif !defined(ENABLE_SKYRIM_SE) && !defined(ENABLE_SKYRIM_VR)
439  return a_ae;
440 #else
441  return Module::IsAE() ? a_ae : a_seAndVR;
442 #endif
443  }
444 
462  template<class T>
463  [[nodiscard]] SKYRIM_REL T Relocate(
464  [[maybe_unused]] T a_se,
465  [[maybe_unused]] T a_ae,
466  [[maybe_unused]] T a_vr) noexcept
467  {
468 #if !defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_VR)
469  return a_se;
470 #elif !defined(ENABLE_SKYRIM_SE) && !defined(ENABLE_SKYRIM_VR)
471  return a_ae;
472 #elif !defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_SE)
473  return a_vr;
474 #else
475  switch (Module::get().GetRuntime()) {
476  case Module::Runtime::AE:
477  return a_ae;
478  case Module::Runtime::VR:
479  return a_vr;
480  default:
481  return a_se;
482  }
483 #endif
484  }
485 
486  namespace detail
487  {
488  template<class T>
490 
491  template<class Ret, class This>
492  struct RelocateVirtualHelper<Ret(This*)>
493  {
494  using this_type = This;
495  using return_type = Ret;
496  using function_type = Ret(This*);
497  };
498 
499  template<class Ret, class This, class... Args>
500  struct RelocateVirtualHelper<Ret(This*, Args...)>
501  {
502  using this_type = This;
503  using return_type = Ret;
504  using function_type = Ret(This *, Args...);
505  };
506 
507  template<class Ret, class This>
508  struct RelocateVirtualHelper<Ret(This::*)()>
509  {
510  using this_type = This;
511  using return_type = Ret;
512  using function_type = Ret(This *);
513  };
514 
515  template<class Ret, class This, class... Args>
516  struct RelocateVirtualHelper<Ret(This::*)(Args...)>
517  {
518  using this_type = This;
519  using return_type = Ret;
520  using function_type = Ret(This *, Args...);
521  };
522 
523  template<class Ret, class This>
524  struct RelocateVirtualHelper<Ret(This::*)() const>
525  {
526  using this_type = const This;
527  using return_type = Ret;
528  using function_type = Ret(const This *);
529  };
530 
531  template<class Ret, class This, class... Args>
532  struct RelocateVirtualHelper<Ret(This::*)(Args...) const>
533  {
534  using this_type = const This;
535  using return_type = Ret;
536  using function_type = Ret(const This*, Args...);
537  };
538  }
539 
560  template<class Fn, class... Args>
562  [[maybe_unused]] std::ptrdiff_t a_seAndAEVtableOffset,
563  [[maybe_unused]] std::ptrdiff_t a_vrVtableOffset,
564  [[maybe_unused]] std::ptrdiff_t a_seAndAEVtableIndex,
565  [[maybe_unused]] std::ptrdiff_t a_vrVtableIndex,
566  typename detail::RelocateVirtualHelper<Fn>::this_type* a_self, Args &&... a_args)
567  {
568  return (*reinterpret_cast<typename detail::RelocateVirtualHelper<Fn>::function_type**>(
569  *reinterpret_cast<const uintptr_t *>(reinterpret_cast<uintptr_t>(a_self) +
570  #ifndef ENABLE_SKYRIM_VR
571  a_seAndAEVtableOffset) +
572  a_seAndAEVtableIndex
573  #elif !defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_SE)
574  a_vrVtableOffset) +
575  a_vrVtableIndex
576  #else
577  (Module::IsVR() ? a_vrVtableOffset : a_seAndAEVtableOffset)) +
578  (Module::IsVR() ? a_vrVtableIndex : a_seAndAEVtableIndex)
579  #endif
580  * sizeof(uintptr_t)))(a_self, std::forward<Args>(a_args)...);
581  }
582 
606  template<class Fn, class... Args>
608  std::ptrdiff_t a_seAndAEVtableIndex,
609  std::ptrdiff_t a_vrVtableIndex,
610  typename detail::RelocateVirtualHelper<Fn>::this_type* a_self, Args&&... a_args)
611  {
612  return RelocateVirtual<Fn, Args...>(0, 0, a_seAndAEVtableIndex, a_vrVtableIndex, a_self, std::forward<Args>(a_args)...);
613  }
614 
632  template<class T, class This>
633  [[nodiscard]] inline T& RelocateMember(This* a_self, std::ptrdiff_t a_seAndAE, std::ptrdiff_t a_vr)
634  {
635  return *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(a_self) + Relocate(a_seAndAE, a_seAndAE, a_vr));
636  }
637 
638  template<class T, class This>
639  [[nodiscard]] inline T& RelocateMember(This* a_self, std::ptrdiff_t offset)
640  {
641  return *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(a_self) + offset);
642  }
643 
644  template<class T, class This>
645  [[nodiscard]] inline T& RelocateMemberIf(bool condition, This* a_self, std::ptrdiff_t a, std::ptrdiff_t b)
646  {
647  return *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(a_self) + (condition ? a : b));
648  }
649 
650  template<class T, class This>
651  [[nodiscard]] inline T& RelocateMemberIfNewer(Version v, This* a_self, std::ptrdiff_t older, std::ptrdiff_t newer)
652  {
653  return *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(a_self) +
654  (REL::Module::get().version().compare(v) == std::strong_ordering::less ? older : newer));
655  }
656 }
657 
658 #undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE
659 #undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER
660 #undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL
661 
662 #undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE
663 #undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER
664 #undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL
#define SKYRIM_ADDR
Definition: Common.h:18
#define SKYRIM_REL
Definition: Common.h:38
Definition: ID.h:430
std::uintptr_t address() const
Definition: ID.h:444
static SKYRIM_REL_VR bool IsVR() noexcept
Definition: Module.h:254
static Module & get()
Definition: Module.h:82
Version version() const noexcept
Definition: Module.h:207
std::uintptr_t base() const noexcept
Definition: Module.h:201
static SKYRIM_REL bool IsAE() noexcept
Definition: Module.h:238
Definition: Offset.h:8
std::uintptr_t address() const
Definition: Offset.h:22
Definition: ID.h:457
std::uintptr_t address() const
Definition: ID.h:492
Definition: Relocation.h:204
void write(const std::span< U > a_data) requires(std
Definition: Relocation.h:351
constexpr std::uintptr_t address() const noexcept
Definition: Relocation.h:332
std::uintptr_t write_branch(const F a_dst) requires(std
Definition: Relocation.h:365
auto operator->() const noexcept requires(std
Definition: Relocation.h:318
std::uintptr_t write_call(const F a_dst) requires(std
Definition: Relocation.h:379
std::conditional_t< std::is_member_pointer_v< T >||std::is_function_v< std::remove_pointer_t< T > >, std::decay_t< T >, T > value_type
Definition: Relocation.h:210
Relocation(ID a_id, Offset a_offset)
Definition: Relocation.h:234
constexpr Relocation & operator=(std::uintptr_t a_address) noexcept
Definition: Relocation.h:274
Relocation(VariantID a_id, VariantOffset a_offset)
Definition: Relocation.h:270
std::uintptr_t write_vfunc(const std::size_t a_idx, const std::uintptr_t a_newFunc) requires(std
Definition: Relocation.h:392
Relocation & operator=(RelocationID a_id)
Definition: Relocation.h:298
std::uintptr_t write_branch(const std::uintptr_t a_dst) requires(std
Definition: Relocation.h:358
std::uintptr_t write_call(const std::uintptr_t a_dst) requires(std
Definition: Relocation.h:372
value_type get() const noexcept(std::is_nothrow_copy_constructible_v< value_type >)
Definition: Relocation.h:336
Relocation(Offset a_offset)
Definition: Relocation.h:218
Relocation(RelocationID a_id, Offset a_offset)
Definition: Relocation.h:250
Relocation(ID a_id, std::ptrdiff_t a_offset)
Definition: Relocation.h:230
Relocation(VariantID a_id, Offset a_offset)
Definition: Relocation.h:266
Relocation(VariantID a_id)
Definition: Relocation.h:258
Relocation(RelocationID a_id, std::ptrdiff_t a_offset)
Definition: Relocation.h:246
std::uintptr_t write_vfunc(std::size_t a_idx, F a_newFunc) requires(std
Definition: Relocation.h:402
Relocation(VariantID a_id, std::ptrdiff_t a_offset)
Definition: Relocation.h:262
Relocation & operator=(Offset a_offset)
Definition: Relocation.h:280
void write_fill(const std::uint8_t a_value, const std::size_t a_count) requires(std
Definition: Relocation.h:385
std::invoke_result_t< const value_type &, Args... > operator()(Args &&... a_args) const noexcept(std::is_nothrow_invocable_v< const value_type &, Args... >) requires(std
Definition: Relocation.h:325
constexpr Relocation() noexcept=default
void write(const U &a_data) requires(std
Definition: Relocation.h:344
Relocation(ID a_id, VariantOffset a_offset)
Definition: Relocation.h:238
Relocation & operator=(VariantOffset a_offset)
Definition: Relocation.h:286
Relocation(VariantOffset a_offset)
Definition: Relocation.h:222
Relocation(ID a_id)
Definition: Relocation.h:226
Relocation & operator=(VariantID a_id)
Definition: Relocation.h:304
Relocation(RelocationID a_id)
Definition: Relocation.h:242
Relocation(RelocationID a_id, VariantOffset a_offset)
Definition: Relocation.h:254
Relocation & operator=(ID a_id)
Definition: Relocation.h:292
std::size_t offset() const
Definition: Relocation.h:334
Definition: ID.h:543
std::uintptr_t address() const
Definition: ID.h:563
Definition: Offset.h:33
std::uintptr_t address() const
Definition: Offset.h:53
Definition: Version.h:6
constexpr std::strong_ordering compare(const Version &a_rhs) const noexcept
Definition: Version.h:59
std::uintptr_t write_call(std::uintptr_t a_src, std::uintptr_t a_dst)
Definition: Trampoline.h:107
std::uintptr_t write_branch(std::uintptr_t a_src, std::uintptr_t a_dst)
Definition: Trampoline.h:82
typename member_function_non_pod_type< F >::type member_function_non_pod_type_t
Definition: Relocation.h:88
decltype(auto) invoke_member_function_non_pod(F &&a_func, First &&a_first, Rest &&... a_rest) noexcept(std::is_nothrow_invocable_v< F, First, Rest... >)
Definition: Relocation.h:141
typename member_function_pod_type< F >::type member_function_pod_type_t
Definition: Relocation.h:77
constexpr bool is_x64_pod_v
Definition: Relocation.h:135
REL_MAKE_MEMBER_FUNCTION_POD_TYPE()
REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE()
Definition: ID.h:6
constexpr std::uint8_t NOP6[]
Definition: Relocation.h:158
constexpr std::uint8_t JMP8
Definition: Relocation.h:163
constexpr std::uint8_t NOP
Definition: Relocation.h:153
constexpr std::uint8_t NOP4[]
Definition: Relocation.h:156
T & RelocateMember(This *a_self, std::ptrdiff_t a_seAndAE, std::ptrdiff_t a_vr)
Definition: Relocation.h:633
constexpr std::uint8_t INT3
Definition: Relocation.h:166
detail::RelocateVirtualHelper< Fn >::return_type RelocateVirtual([[maybe_unused]] std::ptrdiff_t a_seAndAEVtableOffset, [[maybe_unused]] std::ptrdiff_t a_vrVtableOffset, [[maybe_unused]] std::ptrdiff_t a_seAndAEVtableIndex, [[maybe_unused]] std::ptrdiff_t a_vrVtableIndex, typename detail::RelocateVirtualHelper< Fn >::this_type *a_self, Args &&... a_args)
Definition: Relocation.h:561
constexpr std::uint8_t NOP8[]
Definition: Relocation.h:160
constexpr std::uint8_t NOP2[]
Definition: Relocation.h:154
T & RelocateMemberIfNewer(Version v, This *a_self, std::ptrdiff_t older, std::ptrdiff_t newer)
Definition: Relocation.h:651
SKYRIM_ADDR T Relocate([[maybe_unused]] T &&a_seAndVR, [[maybe_unused]] T &&a_ae) noexcept
Definition: Relocation.h:432
void safe_fill(std::uintptr_t a_dst, std::uint8_t a_value, std::size_t a_count)
T & RelocateMemberIf(bool condition, This *a_self, std::ptrdiff_t a, std::ptrdiff_t b)
Definition: Relocation.h:645
void safe_write(std::uintptr_t a_dst, const void *a_src, std::size_t a_count)
constexpr std::uint8_t NOP5[]
Definition: Relocation.h:157
constexpr std::uint8_t NOP3[]
Definition: Relocation.h:155
constexpr std::uint8_t NOP9[]
Definition: Relocation.h:161
std::invoke_result_t< F, Args... > invoke(F &&a_func, Args &&... a_args) noexcept(std::is_nothrow_invocable_v< F, Args... >) requires(std
Definition: Relocation.h:169
constexpr std::uint8_t RET
Definition: Relocation.h:165
constexpr std::uint8_t JMP32
Definition: Relocation.h:164
constexpr std::uint8_t NOP7[]
Definition: Relocation.h:159
requires(is_builtin_convertible_v< T >) struct GetRawType< T >
Definition: PackUnpack.h:30
Trampoline & GetTrampoline()
Definition: ActorValueList.h:28
Ret(This *, Args...) function_type
Definition: Relocation.h:504
Ret return_type
Definition: Relocation.h:495
This this_type
Definition: Relocation.h:494
Ret(This *) function_type
Definition: Relocation.h:496
Ret(const This *, Args...) function_type
Definition: Relocation.h:536
Ret(This *, Args...) function_type
Definition: Relocation.h:520
const This this_type
Definition: Relocation.h:526
Ret(const This *) function_type
Definition: Relocation.h:528
Ret return_type
Definition: Relocation.h:511
Ret(This *) function_type
Definition: Relocation.h:512
This this_type
Definition: Relocation.h:510
Definition: Relocation.h:489
Definition: Relocation.h:115
Definition: Relocation.h:109
Definition: Relocation.h:99
Definition: Relocation.h:112
Definition: Relocation.h:69