Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rework autosegs to use global constructors instead of scanning segments, removing all platform-dependent code #2887

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
108 changes: 35 additions & 73 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,56 @@ 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)
{
Initialize();
}

FAutoSeg(void** begin, void** end)
: name(nullptr)
, begin(begin)
, end(end)
{
}
TArray<T*> fields {TArray<T*>::NoInit}; // skip constructor for fields, globals are zero-initialized, so this is fine

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