Skip to content

Commit

Permalink
rework autosegs to use global constructors instead of scanning segmen…
Browse files Browse the repository at this point in the history
…ts, removing all platform-dependent code
  • Loading branch information
RicardoLuis0 committed Jan 5, 2025
1 parent 6f927d6 commit 32c1783
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 276 deletions.
34 changes: 7 additions & 27 deletions src/common/console/c_cvars.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ inline FBaseCVar *cvar_forceset (const char *var_name, const uint8_t *value) { r

constexpr UCVarValue::UCVarValue(FIntCVarRef& v) : Pointer(&v) { }

struct FCVarDecl
struct FCVarDecl : FAutoSegEntry<FCVarDecl>
{
void * refAddr;
ECVarType type;
Expand All @@ -679,6 +679,9 @@ struct FCVarDecl
UCVarValue defaultval;
const char *description;
void* callbackp; // actually a function pointer with unspecified arguments. C++ does not like that much...

FCVarDecl(void * r, ECVarType t, unsigned int f, const char * n, UCVarValue v, const char * d, void * c)
: FAutoSegEntry(AutoSegs::CVarDecl, this), refAddr(r), type(t), flags(f), name(n), defaultval(v), description(d), callbackp(c) {}
};


Expand All @@ -688,60 +691,37 @@ void C_RestoreCVars (void);

void C_ForgetCVars (void);


#if defined(_MSC_VER)
#pragma section(SECTION_VREG,read)

#define MSVC_VSEG __declspec(allocate(SECTION_VREG))
#define GCC_VSEG
#else
#define MSVC_VSEG
#define GCC_VSEG __attribute__((section(SECTION_VREG))) __attribute__((used))
#endif

#define CUSTOM_CVAR(type,name,def,flags) \
static void cvarfunc_##name(F##type##CVar &); \
F##type##CVarRef name; \
static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue<CVAR_##type>(def), nullptr, reinterpret_cast<void*>(cvarfunc_##name) }; \
extern FCVarDecl const *const cvardeclref_##name; \
MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name; \
static void cvarfunc_##name(F##type##CVar &self)


#define CUSTOM_CVAR_NAMED(type,name,cname,def,flags) \
static void cvarfunc_##name(F##type##CVar &); \
F##type##CVarRef name; \
static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #cname, CVarValue<CVAR_##type>(def), nullptr, reinterpret_cast<void*>(cvarfunc_##name) }; \
extern FCVarDecl const *const cvardeclref_##name; \
MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name; \
static void cvarfunc_##name(F##type##CVar &self)

#define CVAR(type,name,def,flags) \
F##type##CVarRef name; \
static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue<CVAR_##type>(def), nullptr, nullptr}; \
extern FCVarDecl const *const cvardeclref_##name; \
MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name;
static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue<CVAR_##type>(def), nullptr, nullptr};

#define EXTERN_CVAR(type,name) extern F##type##CVarRef name;

#define CUSTOM_CVARD(type,name,def,flags,descr) \
static void cvarfunc_##name(F##type##CVar &); \
F##type##CVarRef name; \
static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue<CVAR_##type>(def), descr, reinterpret_cast<void*>(cvarfunc_##name) }; \
extern FCVarDecl const *const cvardeclref_##name; \
MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name; \
static void cvarfunc_##name(F##type##CVar &self)

#define CVARD(type,name,def,flags, descr) \
F##type##CVarRef name; \
static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue<CVAR_##type>(def), descr, nullptr}; \
extern FCVarDecl const *const cvardeclref_##name; \
MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name;
static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue<CVAR_##type>(def), descr, nullptr};

#define CVARD_NAMED(type,name,varname,def,flags, descr) \
F##type##CVarRef name; \
static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #varname, CVarValue<CVAR_##type>(def), descr, nullptr}; \
extern FCVarDecl const *const cvardeclref_##name; \
MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name;
static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #varname, CVarValue<CVAR_##type>(def), descr, nullptr};

#endif //__C_CVARS_H__
104 changes: 6 additions & 98 deletions src/common/objects/autosegs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,103 +42,11 @@
** compile with something other than Visual C++ or GCC.
*/

#include <cassert>
#include "autosegs.h"

#ifdef _WIN32
#include <windows.h>
#include <dbghelp.h>
#elif defined __MACH__
#include <mach-o/getsect.h>
#include <mach-o/ldsyms.h>
#endif


#if defined _WIN32 || defined __MACH__

#define AUTOSEG_VARIABLE(name, autoseg) namespace AutoSegs{ FAutoSeg name{ AUTOSEG_STR(autoseg) }; }

#else // Linux and others with ELF executables

#define AUTOSEG_START(name) __start_##name
#define AUTOSEG_STOP(name) __stop_##name
#define AUTOSEG_VARIABLE(name, autoseg) \
void* name##DummyPointer __attribute__((section(AUTOSEG_STR(autoseg)))) __attribute__((used)); \
extern void* AUTOSEG_START(autoseg); \
extern void* AUTOSEG_STOP(autoseg); \
namespace AutoSegs { FAutoSeg name{ &AUTOSEG_START(autoseg), &AUTOSEG_STOP(autoseg) }; }

#endif

AUTOSEG_VARIABLE(ActionFunctons, AUTOSEG_AREG)
AUTOSEG_VARIABLE(TypeInfos, AUTOSEG_CREG)
AUTOSEG_VARIABLE(ClassFields, AUTOSEG_FREG)
AUTOSEG_VARIABLE(Properties, AUTOSEG_GREG)
AUTOSEG_VARIABLE(MapInfoOptions, AUTOSEG_YREG)
AUTOSEG_VARIABLE(CVarDecl, AUTOSEG_VREG)

#undef AUTOSEG_VARIABLE
#undef AUTOSEG_STOP
#undef AUTOSEG_START


void FAutoSeg::Initialize()
{
#ifdef _WIN32

const HMODULE selfModule = GetModuleHandle(nullptr);
const SIZE_T baseAddress = reinterpret_cast<SIZE_T>(selfModule);

const PIMAGE_NT_HEADERS header = ImageNtHeader(selfModule);
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(header);

for (WORD i = 0; i < header->FileHeader.NumberOfSections; ++i, ++section)
{
if (strncmp(reinterpret_cast<char *>(section->Name), name, IMAGE_SIZEOF_SHORT_NAME) == 0)
{
begin = reinterpret_cast<void **>(baseAddress + section->VirtualAddress);
end = reinterpret_cast<void **>(baseAddress + section->VirtualAddress + section->SizeOfRawData);
break;
}
}

#elif defined __MACH__

unsigned long size;

if (uint8_t *const section = getsectiondata(&_mh_execute_header, AUTOSEG_MACH_SEGMENT, name, &size))
{
begin = reinterpret_cast<void **>(section);
end = reinterpret_cast<void **>(section + size);
}

#else // Linux and others with ELF executables

assert(false);

#endif
}


#if defined(_MSC_VER)

// We want visual styles support under XP
#if defined _M_IX86

#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")

#elif defined _M_IA64

#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")

#elif defined _M_X64

#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")

#else

#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

#endif

#endif
FAutoSeg<AFuncDesc> AutoSegs::ActionFunctons;
FAutoSeg<FieldDesc> AutoSegs::ClassFields;
FAutoSeg<ClassReg> AutoSegs::TypeInfos;
FAutoSeg<FPropertyInfo> AutoSegs::Properties;
FAutoSeg<FMapOptInfo> AutoSegs::MapInfoOptions;
FAutoSeg<FCVarDecl> AutoSegs::CVarDecl;
111 changes: 40 additions & 71 deletions src/common/objects/autosegs.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@
#define NO_SANITIZE_M
#endif

#include <tarray.h>

template<typename T>
class FAutoSeg
{
const char *name;
void **begin;
void **end;
{ // register things automatically without segment hackery

template <typename T>
template <typename T2>
struct ArgumentType;

template <typename Ret, typename Func, typename Arg>
Expand Down Expand Up @@ -90,94 +90,63 @@ class FAutoSeg
template <typename Func, typename Ret>
static constexpr bool HasReturnTypeV = HasReturnType<Func, Ret>::Value;

void Initialize();

public:
explicit FAutoSeg(const char *name)
: name(name)
, begin(nullptr)
, end(nullptr)
union
{
Initialize();
}
TArray<T*> fields; // skip constructor for fields, globals are zero-initialized, so this is fine
FArray dummy;
};

FAutoSeg(void** begin, void** end)
: name(nullptr)
, begin(begin)
, end(end)
{
}
FAutoSeg(){}
~FAutoSeg(){fields.~TArray();}

template <typename Func>
void NO_SANITIZE_M ForEach(Func func, std::enable_if_t<HasReturnTypeV<Func, void>> * = nullptr)
void ForEach(Func func, std::enable_if_t<HasReturnTypeV<Func, void>> * = nullptr)
{
using CallableType = decltype(&Func::operator());
using ArgType = typename ArgumentType<CallableType>::Type;

for (void **it = begin; it < end; ++it)
for (T * elem : fields)
{
if (intptr_t(it) > 0xffff && *it && intptr_t(*it) > 0xffff)
{
func(reinterpret_cast<ArgType>(*it));
}
func(elem);
}
}

template <typename Func>
void NO_SANITIZE_M ForEach(Func func, std::enable_if_t<HasReturnTypeV<Func, bool>> * = nullptr)
void ForEach(Func func, std::enable_if_t<HasReturnTypeV<Func, bool>> * = nullptr)
{
using CallableType = decltype(&Func::operator());
using ArgType = typename ArgumentType<CallableType>::Type;

for (void **it = begin; it < end; ++it)
for (T * elem : fields)
{
if (intptr_t(it) > 0xffff && *it && intptr_t(*it) > 0xffff)
if (!func(elem))
{
if (!func(reinterpret_cast<ArgType>(*it)))
{
return;
};
return;
}
}
}
};

template<typename T>
struct FAutoSegEntry
{
FAutoSegEntry(FAutoSeg<T> &seg, T* value)
{
seg.fields.push_back(value);
}
};

struct AFuncDesc;
struct FieldDesc;
struct ClassReg;
struct FPropertyInfo;
struct FMapOptInfo;
struct FCVarDecl;

namespace AutoSegs
{
extern FAutoSeg ActionFunctons;
extern FAutoSeg TypeInfos;
extern FAutoSeg ClassFields;
extern FAutoSeg Properties;
extern FAutoSeg MapInfoOptions;
extern FAutoSeg CVarDecl;
extern FAutoSeg<AFuncDesc> ActionFunctons;
extern FAutoSeg<FieldDesc> ClassFields;
extern FAutoSeg<ClassReg> TypeInfos;
extern FAutoSeg<FPropertyInfo> Properties;
extern FAutoSeg<FMapOptInfo> MapInfoOptions;
extern FAutoSeg<FCVarDecl> CVarDecl;
}

#define AUTOSEG_AREG areg
#define AUTOSEG_CREG creg
#define AUTOSEG_FREG freg
#define AUTOSEG_GREG greg
#define AUTOSEG_YREG yreg
#define AUTOSEG_VREG vreg

#define AUTOSEG_STR(string) AUTOSEG_STR2(string)
#define AUTOSEG_STR2(string) #string

#ifdef __MACH__
#define AUTOSEG_MACH_SEGMENT "__DATA"
#define AUTOSEG_MACH_SECTION(section) AUTOSEG_MACH_SEGMENT "," AUTOSEG_STR(section)
#define SECTION_AREG AUTOSEG_MACH_SECTION(AUTOSEG_AREG)
#define SECTION_CREG AUTOSEG_MACH_SECTION(AUTOSEG_CREG)
#define SECTION_FREG AUTOSEG_MACH_SECTION(AUTOSEG_FREG)
#define SECTION_GREG AUTOSEG_MACH_SECTION(AUTOSEG_GREG)
#define SECTION_YREG AUTOSEG_MACH_SECTION(AUTOSEG_YREG)
#define SECTION_VREG AUTOSEG_MACH_SECTION(AUTOSEG_VREG)
#else
#define SECTION_AREG AUTOSEG_STR(AUTOSEG_AREG)
#define SECTION_CREG AUTOSEG_STR(AUTOSEG_CREG)
#define SECTION_FREG AUTOSEG_STR(AUTOSEG_FREG)
#define SECTION_GREG AUTOSEG_STR(AUTOSEG_GREG)
#define SECTION_YREG AUTOSEG_STR(AUTOSEG_YREG)
#define SECTION_VREG AUTOSEG_STR(AUTOSEG_VREG)
#endif

#endif
1 change: 0 additions & 1 deletion src/common/objects/dobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ ClassReg DObject::RegistrationInfo =
nullptr,
sizeof(DObject), // SizeOf
};
_DECLARE_TI(DObject)

// This bit is needed in the playsim - but give it a less crappy name.
DEFINE_FIELD_BIT(DObject,ObjectFlags, bDestroyed, OF_EuthanizeMe)
Expand Down
13 changes: 4 additions & 9 deletions src/common/objects/dobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class PClassActor;
#define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object

// Enumerations for the meta classes created by ClassReg::RegisterClass()
struct ClassReg
struct ClassReg : FAutoSegEntry<ClassReg>
{
PClass *MyClass;
const char *Name;
Expand All @@ -103,6 +103,9 @@ struct ClassReg
void(*InitNatives)();
unsigned int SizeOf;

ClassReg(PClass *mc, const char * nm, ClassReg * pt, ClassReg *vm, const size_t * ps, void (*cn)(void *), void(*in)(), unsigned int so)
: FAutoSegEntry(AutoSegs::TypeInfos, this), MyClass(mc), Name(nm), ParentType(pt), _VMExport(vm), Pointers(ps), ConstructNative(cn), InitNatives(in), SizeOf(so) {}

PClass *RegisterClass();
void SetupClass(PClass *cls);
};
Expand Down Expand Up @@ -134,13 +137,6 @@ public: \
#define HAS_OBJECT_POINTERS \
static const size_t PointerOffsets[];

#if defined(_MSC_VER)
# pragma section(SECTION_CREG,read)
# define _DECLARE_TI(cls) __declspec(allocate(SECTION_CREG)) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo;
#else
# define _DECLARE_TI(cls) ClassReg * const cls::RegistrationInfoPtr __attribute__((section(SECTION_CREG))) = &cls::RegistrationInfo;
#endif

#define _IMP_PCLASS(cls, ptrs, create) \
ClassReg cls::RegistrationInfo = {\
nullptr, \
Expand All @@ -151,7 +147,6 @@ public: \
create, \
nullptr, \
sizeof(cls) }; \
_DECLARE_TI(cls) \
PClass *cls::StaticType() const { return RegistrationInfo.MyClass; }

#define IMPLEMENT_CLASS(cls, isabstract, ptrs) \
Expand Down
Loading

0 comments on commit 32c1783

Please sign in to comment.