diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index fc4d264e8..6f363883d 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -935,6 +935,7 @@ set (PCH_SOURCES common/engine/serializer.cpp common/engine/m_joy.cpp common/engine/m_random.cpp + common/objects/autosegs.cpp common/objects/dobject.cpp common/objects/dobjgc.cpp common/objects/dobjtype.cpp @@ -1031,7 +1032,6 @@ use_precompiled_header(".") add_executable( ${PROJECT_NAME} WIN32 MACOSX_BUNDLE ${HEADER_FILES} ${NOT_COMPILED_SOURCE_FILES} - __autostart.cpp ${SYSTEM_SOURCES} ${FASTMATH_SOURCES} ${PCH_SOURCES} @@ -1057,7 +1057,6 @@ add_executable( ${PROJECT_NAME} WIN32 MACOSX_BUNDLE common/thirdparty/math/tan.c common/thirdparty/math/tanh.c common/thirdparty/math/fastsin.cpp - zzautozend.cpp ) #set_source_files_properties( ${FASTMATH_SOURCES} PROPERTIES COMPILE_FLAGS ${DEM_FASTMATH_FLAG} ) diff --git a/source/__autostart.cpp b/source/common/objects/autosegs.cpp similarity index 62% rename from source/__autostart.cpp rename to source/common/objects/autosegs.cpp index d33fc6126..4840d1319 100644 --- a/source/__autostart.cpp +++ b/source/common/objects/autosegs.cpp @@ -44,32 +44,79 @@ #include "autosegs.h" +#ifdef _WIN32 +#include +#include +#elif defined __MACH__ +#include +#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) + +#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(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(section->Name), name, IMAGE_SIZEOF_SHORT_NAME) == 0) + { + begin = reinterpret_cast(baseAddress + section->VirtualAddress); + end = reinterpret_cast(baseAddress + section->VirtualAddress + section->SizeOfRawData); + break; + } + } + +#elif defined __MACH__ + + if (const struct section_64 *const section = getsectbyname(AUTOSEG_MACH_SEGMENT, name)) + { + begin = reinterpret_cast(section->addr); + end = reinterpret_cast(section->addr + section->size); + } + +#else // Linux and others with ELF executables + + assert(false); + +#endif +} + + #if defined(_MSC_VER) -// The various reg sections are used to group pointers spread across multiple -// source files into cohesive arrays in the final executable. We don't -// actually care about these sections themselves and merge them all into -// a single section during the final link. (.rdata is the standard section -// for initialized read-only data.) - -#pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.freg=.rdata") -#pragma comment(linker, "/merge:.greg=.rdata /merge:.yreg=.rdata") - -#pragma section(".areg$a",read) -__declspec(allocate(".areg$a")) void *const ARegHead = 0; - -#pragma section(".creg$a",read) -__declspec(allocate(".creg$a")) void *const CRegHead = 0; - -#pragma section(".freg$a",read) -__declspec(allocate(".freg$a")) void *const FRegHead = 0; - -#pragma section(".greg$a",read) -__declspec(allocate(".greg$a")) void *const GRegHead = 0; - -#pragma section(".yreg$a",read) -__declspec(allocate(".yreg$a")) void *const YRegHead = 0; - // We want visual styles support under XP #if defined _M_IX86 @@ -89,23 +136,4 @@ __declspec(allocate(".yreg$a")) void *const YRegHead = 0; #endif -#elif defined(__GNUC__) - -#include "basics.h" - -// I don't know of an easy way to merge sections together with the GNU linker, -// so GCC users will see all of these sections appear in the final executable. -// (There are linker scripts, but that apparently involves extracting the -// default script from ld and then modifying it.) - -void *const ARegHead __attribute__((section(SECTION_AREG))) = 0; -void *const CRegHead __attribute__((section(SECTION_CREG))) = 0; -void *const FRegHead __attribute__((section(SECTION_FREG))) = 0; -void *const GRegHead __attribute__((section(SECTION_GREG))) = 0; -void *const YRegHead __attribute__((section(SECTION_YREG))) = 0; - -#else - -#error Please fix autostart.cpp for your compiler - #endif diff --git a/source/common/objects/autosegs.h b/source/common/objects/autosegs.h index 9cba04ad2..df996d2f0 100644 --- a/source/common/objects/autosegs.h +++ b/source/common/objects/autosegs.h @@ -35,6 +35,8 @@ #ifndef AUTOSEGS_H #define AUTOSEGS_H +#include + #if defined(__clang__) #if defined(__has_feature) && __has_feature(address_sanitizer) #define NO_SANITIZE __attribute__((no_sanitize("address"))) @@ -45,69 +47,126 @@ #define NO_SANITIZE #endif -#define REGMARKER(x) (x) -typedef void * const REGINFO; -typedef void * NCREGINFO; - -// List of Action functons -extern REGINFO ARegHead; -extern REGINFO ARegTail; - -// List of TypeInfos -extern REGINFO CRegHead; -extern REGINFO CRegTail; - -// List of class fields -extern REGINFO FRegHead; -extern REGINFO FRegTail; - -// List of properties -extern REGINFO GRegHead; -extern REGINFO GRegTail; - -// List of MAPINFO map options -extern REGINFO YRegHead; -extern REGINFO YRegTail; - -class FAutoSegIterator +class FAutoSeg { - public: - FAutoSegIterator(REGINFO &head, REGINFO &tail) - { - // Weirdness. Mingw's linker puts these together backwards. - if (&head <= &tail) - { - Head = &head; - Tail = &tail; - } - else - { - Head = &tail; - Tail = &head; - } - Probe = Head; - } - NCREGINFO operator*() const NO_SANITIZE - { - return *Probe; - } - FAutoSegIterator &operator++() NO_SANITIZE - { - do - { - ++Probe; - } while (*Probe == 0 && Probe < Tail); - return *this; - } - void Reset() - { - Probe = Head; - } + const char *name; + void **begin; + void **end; - protected: - REGINFO *Probe; - REGINFO *Head; - REGINFO *Tail; + template + struct ArgumentType; + + template + struct ArgumentType + { + using Type = Arg; + }; + + template + using ArgumentTypeT = typename ArgumentType::Type; + + template + struct ReturnType + { + using Type = std::invoke_result_t>; + }; + + template + using ReturnTypeT = typename ReturnType::Type; + + template + struct HasReturnType + { + static constexpr bool Value = std::is_same_v, Ret>; + }; + + template + static constexpr bool HasReturnTypeV = HasReturnType::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) + { + } + + template + void ForEach(Func func, std::enable_if_t> * = nullptr) + { + using CallableType = decltype(&Func::operator()); + using ArgType = typename ArgumentType::Type; + + for (void **it = begin; it < end; ++it) + { + if (*it) + { + func(reinterpret_cast(*it)); + } + } + } + + template + void ForEach(Func func, std::enable_if_t> * = nullptr) + { + using CallableType = decltype(&Func::operator()); + using ArgType = typename ArgumentType::Type; + + for (void **it = begin; it < end; ++it) + { + if (*it) + { + if (!func(reinterpret_cast(*it))) + { + return; + }; + } + } + } }; +namespace AutoSegs +{ + extern FAutoSeg ActionFunctons; + extern FAutoSeg TypeInfos; + extern FAutoSeg ClassFields; + extern FAutoSeg Properties; + extern FAutoSeg MapInfoOptions; +} + +#define AUTOSEG_AREG areg +#define AUTOSEG_CREG creg +#define AUTOSEG_FREG freg +#define AUTOSEG_GREG greg +#define AUTOSEG_YREG yreg + +#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) +#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) +#endif + #endif diff --git a/source/common/objects/dobject.h b/source/common/objects/dobject.h index a866a4ca5..ce591b6d6 100644 --- a/source/common/objects/dobject.h +++ b/source/common/objects/dobject.h @@ -41,6 +41,7 @@ #include "name.h" #include "palentry.h" #include "textureid.h" +#include "autosegs.h" class PClass; class PType; @@ -134,8 +135,8 @@ public: \ static const size_t PointerOffsets[]; #if defined(_MSC_VER) -# pragma section(".creg$u",read) -# define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo; +# 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 diff --git a/source/common/objects/dobjtype.cpp b/source/common/objects/dobjtype.cpp index 08c0a5692..03a1cc980 100644 --- a/source/common/objects/dobjtype.cpp +++ b/source/common/objects/dobjtype.cpp @@ -206,13 +206,10 @@ void PClass::StaticInit () { Namespaces.GlobalNamespace = Namespaces.NewNamespace(0); - FAutoSegIterator probe(CRegHead, CRegTail); - - while (*++probe != nullptr) + AutoSegs::TypeInfos.ForEach([](ClassReg* typeInfo) { - ((ClassReg *)*probe)->RegisterClass (); - } - probe.Reset(); + typeInfo->RegisterClass(); + }); // Keep built-in classes in consistant order. I did this before, though // I'm not sure if this is really necessary to maintain any sort of sync. @@ -268,14 +265,10 @@ void PClass::StaticShutdown () AllClasses.Clear(); ClassMap.Clear(); - FAutoSegIterator probe(CRegHead, CRegTail); - - while (*++probe != nullptr) + AutoSegs::TypeInfos.ForEach([](ClassReg* typeInfo) { - auto cr = ((ClassReg *)*probe); - cr->MyClass = nullptr; - } - + typeInfo->MyClass = nullptr; + }); } //========================================================================== @@ -953,4 +946,4 @@ void PClass::InitializeDefaults() } } } -} \ No newline at end of file +} diff --git a/source/common/scripting/core/imports.cpp b/source/common/scripting/core/imports.cpp index b1b478b74..6db68bc46 100644 --- a/source/common/scripting/core/imports.cpp +++ b/source/common/scripting/core/imports.cpp @@ -194,17 +194,14 @@ void InitImports() AFTable.Clear(); if (AFTable.Size() == 0) { - FAutoSegIterator probe(ARegHead, ARegTail); - - while (*++probe != NULL) + AutoSegs::ActionFunctons.ForEach([](AFuncDesc *afunc) { - AFuncDesc *afunc = (AFuncDesc *)*probe; assert(afunc->VMPointer != NULL); *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->FuncName); (*(afunc->VMPointer))->PrintableName.Format("%s.%s [Native]", afunc->ClassName+1, afunc->FuncName); (*(afunc->VMPointer))->DirectNativeCall = afunc->DirectNative; AFTable.Push(*afunc); - } + }); AFTable.ShrinkToFit(); qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } @@ -212,13 +209,10 @@ void InitImports() FieldTable.Clear(); if (FieldTable.Size() == 0) { - FAutoSegIterator probe(FRegHead, FRegTail); - - while (*++probe != NULL) + AutoSegs::ClassFields.ForEach([](FieldDesc *afield) { - FieldDesc *afield = (FieldDesc *)*probe; FieldTable.Push(*afield); - } + }); FieldTable.ShrinkToFit(); qsort(&FieldTable[0], FieldTable.Size(), sizeof(FieldTable[0]), fieldcmp); } diff --git a/source/common/scripting/vm/vm.h b/source/common/scripting/vm/vm.h index 0eeec06b4..d0a34a975 100644 --- a/source/common/scripting/vm/vm.h +++ b/source/common/scripting/vm/vm.h @@ -620,11 +620,11 @@ struct AFuncDesc }; #if defined(_MSC_VER) -#pragma section(".areg$u",read) -#pragma section(".freg$u",read) +#pragma section(SECTION_AREG,read) +#pragma section(SECTION_FREG,read) -#define MSVC_ASEG __declspec(allocate(".areg$u")) -#define MSVC_FSEG __declspec(allocate(".freg$u")) +#define MSVC_ASEG __declspec(allocate(SECTION_AREG)) +#define MSVC_FSEG __declspec(allocate(SECTION_FREG)) #define GCC_ASEG #define GCC_FSEG #else diff --git a/source/common/utility/basics.h b/source/common/utility/basics.h index 2f2ff7f43..34450469a 100644 --- a/source/common/utility/basics.h +++ b/source/common/utility/basics.h @@ -93,24 +93,6 @@ inline double RAD2DEG(double deg) return deg * (180. / M_PI); } -// Auto-registration sections for GCC. -// Apparently, you cannot do string concatenation inside section attributes. -#ifdef __MACH__ -#define SECTION_AREG "__DATA,areg" -#define SECTION_CREG "__DATA,creg" -#define SECTION_FREG "__DATA,freg" -#define SECTION_GREG "__DATA,greg" -#define SECTION_MREG "__DATA,mreg" -#define SECTION_YREG "__DATA,yreg" -#else -#define SECTION_AREG "areg" -#define SECTION_CREG "creg" -#define SECTION_FREG "freg" -#define SECTION_GREG "greg" -#define SECTION_MREG "mreg" -#define SECTION_YREG "yreg" -#endif - // This is needed in common code, despite being Doom specific. enum EStateUseFlags { diff --git a/source/zzautozend.cpp b/source/zzautozend.cpp deleted file mode 100644 index c5a48b62f..000000000 --- a/source/zzautozend.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -** autozend.cpp -** This file contains the tails of lists stored in special data segments -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -** See autostart.cpp for an explanation of why I do things like this. -*/ - -#include "autosegs.h" - -#if defined(_MSC_VER) - -#pragma section(".areg$z",read) -__declspec(allocate(".areg$z")) void *const ARegTail = 0; - -#pragma section(".creg$z",read) -__declspec(allocate(".creg$z")) void *const CRegTail = 0; - -#pragma section(".freg$z",read) -__declspec(allocate(".freg$z")) void *const FRegTail = 0; - -#pragma section(".greg$z",read) -__declspec(allocate(".greg$z")) void *const GRegTail = 0; - -#pragma section(".yreg$z",read) -__declspec(allocate(".yreg$z")) void *const YRegTail = 0; - - -#elif defined(__GNUC__) - -#include "basics.h" - -void *const ARegTail __attribute__((section(SECTION_AREG))) = 0; -void *const CRegTail __attribute__((section(SECTION_CREG))) = 0; -void *const FRegTail __attribute__((section(SECTION_FREG))) = 0; -void *const GRegTail __attribute__((section(SECTION_GREG))) = 0; -void *const YRegTail __attribute__((section(SECTION_YREG))) = 0; - -#else - -#error Please fix autozend.cpp for your compiler - -#endif