GCC mod section fix

This commit is contained in:
Luke Street
2026-07-28 19:26:53 -06:00
parent 95608438c1
commit f0e6b88cfd
2 changed files with 51 additions and 0 deletions
+9
View File
@@ -139,6 +139,14 @@ struct NamedHook<Name, R(A...)> : HookImpl<detail::NameTag<Name>, R, A...> {};
* leading underscore) or the demangled qualified display name; overloaded display names are
* ambiguous and need the mangled form.
*/
#if defined(__GNUC__) && !defined(__clang__) && defined(__ELF__)
#define DEFINE_HOOK(target, alias) \
MOD_META_RECORD static constinit auto mod_meta_hook_##alias = \
::mods::detail::make_local_hook_record<(target), ::mods::FixedString{#target}>(); \
struct alias : ::mods::Hook<(target)> { \
static void* resolved_target() { return mod_meta_hook_##alias.resolved; } \
}
#else
#define DEFINE_HOOK(target, alias) \
[[maybe_unused]] static const void* const mod_meta_hook_##alias = \
&::mods::detail::HookRecordFor<(target), ::mods::FixedString{#target}>::Holder::record; \
@@ -148,6 +156,7 @@ struct NamedHook<Name, R(A...)> : HookImpl<detail::NameTag<Name>, R, A...> {};
::mods::FixedString{#target}>::Holder::record.resolved; \
} \
}
#endif
#define DEFINE_HOOK_SYMBOL(name, sig, alias) \
MOD_META_RECORD static constinit auto mod_meta_hook_##alias = \
+42
View File
@@ -241,6 +241,48 @@ consteval auto make_hook_mem_names() {
return r;
}
#if defined(__GNUC__) && !defined(__clang__) && defined(__ELF__)
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41091 prevents inline static template members from
* sharing an explicit ELF section with ordinary variables. GCC can instead constant-evaluate a
* file-local record at each DEFINE_HOOK. */
template <auto Target>
void materialize_hook_mem(unsigned char* outPmf) {
const auto target = Target;
std::memcpy(outPmf, &target, sizeof(target));
}
template <auto Target, FixedString Disp>
consteval auto make_local_hook_record() {
using F = decltype(Target);
if constexpr (std::is_member_function_pointer_v<F>) {
constexpr auto names = make_hook_mem_names<Target, Disp>();
static_assert(sizeof(F) <= MOD_META_HOOK_MEM_EXT_CAPACITY,
"unsupported pointer-to-member representation");
if constexpr (sizeof(F) > MOD_META_HOOK_MEM_CAPACITY) {
HookMemExtRecord<names.len> record = {
{sizeof(HookMemExtRecord<names.len>), MOD_META_HOOK_MEM_EXT, 0}, sizeof(F),
materialize_hook_mem<Target>, nullptr, {}};
for (size_t i = 0; i < names.len; ++i) {
record.names[i] = names.chars[i];
}
return record;
} else {
HookMemRecord<F, names.len> record = {
{sizeof(HookMemRecord<F, names.len>), MOD_META_HOOK_MEM, 0}, 0, {Target}, nullptr,
{}};
for (size_t i = 0; i < names.len; ++i) {
record.names[i] = names.chars[i];
}
return record;
}
} else {
static_assert(std::is_pointer_v<F> && std::is_function_v<std::remove_pointer_t<F>>,
"hook target must be a function or member function");
return HookFnRecord<F>{{sizeof(HookFnRecord<F>), MOD_META_HOOK_FN, 0}, 0, Target, nullptr};
}
}
#endif
/*
* MSVC constant-evaluates a compact pointer-to-member only when every other operand in the
* initializer is a literal: no consteval calls, constexpr-object copies, or default member