diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2021-07-28 16:53:41 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2021-07-28 18:27:51 +0200 |
commit | 6c602fd542b7f97e3a23ef27c3839656906c98de (patch) | |
tree | 31ca34bd5ed53a52ae3181878b9ebbe9c92b15f8 | |
parent | 3a3cbeecc113daf992de838a39569f6c81876dbe (diff) |
Fixed ctor/dtor issue allowing use of static qualifiers for non primitives.
* split CRT in a C and C++ part
* use "fake" entry point to init CRT and set a DriverUnload routine for de-init
* added -Wl,--exclude-all-symbols to DRIVER_LDFLAGS
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | CRT/DriverThread.cpp (renamed from DriverThread.cpp) | 0 | ||||
-rw-r--r-- | CRT/DriverThread.hpp (renamed from DriverThread.hpp) | 0 | ||||
-rw-r--r-- | CRT/kcrt.c (renamed from EASTL-compat/kcrt.cpp) | 156 | ||||
-rw-r--r-- | CRT/kcrt.cpp | 51 | ||||
-rw-r--r-- | CRT/ucrt.cpp (renamed from EASTL-compat/ucrt.cpp) | 0 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | Makefile.deps | 7 | ||||
-rw-r--r-- | Makefile.inc | 43 | ||||
-rw-r--r-- | README.md | 24 | ||||
-rw-r--r-- | ddk-template-cplusplus-EASTL.cpp | 3 | ||||
-rw-r--r-- | ddk-template-cplusplus.cpp | 28 | ||||
-rw-r--r-- | ddk-template.c | 3 |
12 files changed, 235 insertions, 86 deletions
diff --git a/DriverThread.cpp b/CRT/DriverThread.cpp index efc4023..efc4023 100644 --- a/DriverThread.cpp +++ b/CRT/DriverThread.cpp diff --git a/DriverThread.hpp b/CRT/DriverThread.hpp index d00db1b..d00db1b 100644 --- a/DriverThread.hpp +++ b/CRT/DriverThread.hpp diff --git a/EASTL-compat/kcrt.cpp b/CRT/kcrt.c index 885dadb..ccff181 100644 --- a/EASTL-compat/kcrt.cpp +++ b/CRT/kcrt.c @@ -1,14 +1,30 @@ /* * Shameless copy pasta from: https://github.com/sidyhe/dxx + * and: https://github.com/liupengs/Mini-CRT + * and some minor modifications. */ -#include <cstdio> -#include <cstdlib> - #include <ntddk.h> #define KCRT_POOL_DEFAULT_TAG 0xDEADBEEF +extern void (*__CTOR_LIST__)(); +extern void (*__DTOR_LIST__)(); +extern NTSTATUS __cdecl DriverEntry(_In_ struct _DRIVER_OBJECT * DriverObject, _In_ PUNICODE_STRING RegistryPath); +extern void __cdecl DriverUnload(_In_ struct _DRIVER_OBJECT * DriverObject); + +DRIVER_INITIALIZE __cdecl _CRT_DriverEntry; +DRIVER_UNLOAD __cdecl _CRT_DriverUnload; + +typedef void (*__cdecl init_and_deinit_fn)(void); +typedef void (*__cdecl atexit_func_t)(void); + +typedef struct _func_node +{ + atexit_func_t func; + struct _func_node * next; +} func_node; + typedef struct _MALLOC_HEADER { ULONG32 Tags; @@ -17,6 +33,8 @@ typedef struct _MALLOC_HEADER } MALLOC_HEADER, *PMALLOC_HEADER; C_ASSERT(sizeof(MALLOC_HEADER) % sizeof(void *) == 0); +static func_node * atexit_list = NULL; + // dynamic memory mgmt PMALLOC_HEADER GET_MALLOC_HEADER(PVOID ptr) @@ -41,6 +59,28 @@ ULONG_PTR GET_MALLOC_SIZE(PVOID ptr) // c runtime +static int register_atexit(atexit_func_t func) +{ + func_node * node; + if (!func) + return -1; + + node = (func_node *)malloc(sizeof(func_node)); + + if (node == 0) + return -1; + + node->func = func; + node->next = atexit_list; + atexit_list = node; + return 0; +} + +int __cdecl atexit(atexit_func_t func) +{ + return register_atexit(func); +} + void __cdecl free(void * ptr) { if (ptr) @@ -107,56 +147,13 @@ void * __cdecl realloc(void * ptr, size_t new_size) return NULL; } -// new & delete - -void * __cdecl operator new(std::size_t size) -{ - return malloc(size); -} - -void * __cdecl operator new[](size_t size) -{ - return malloc(size); -} - -void __cdecl operator delete(void * ptr) -{ - free(ptr); -} - -void __cdecl operator delete(void * ptr, size_t) -{ - free(ptr); -} - -void __cdecl operator delete[](void * ptr, long long unsigned int) -{ - free(ptr); -} - -void __cdecl operator delete[](void * ptr) -{ - free(ptr); -} - -// EASTL - -void * operator new[](size_t size, const char *, int, unsigned, const char *, int) -{ - return malloc(size); -} -void * operator new[](size_t size, size_t, size_t, const char *, int, unsigned, const char *, int) -{ - return malloc(size); -} - -extern "C" void __cxa_pure_virtual(void) +void __cdecl __cxa_pure_virtual(void) { // definitly not perfect, but we get at least a notification while (1) { DbgPrint("Pure virtual function call..\n"); - LARGE_INTEGER li = { .QuadPart = -10000000 }; + LARGE_INTEGER li = {.QuadPart = -10000000}; KeDelayExecutionThread(KernelMode, TRUE, &li); } } @@ -182,7 +179,7 @@ extern "C" void __cxa_pure_virtual(void) } \ } while (0) -extern "C" float ceilf(float x) +float __cdecl ceilf(float x) { union { float f; @@ -213,3 +210,64 @@ extern "C" float ceilf(float x) } return u.f; } + +// functions called in DRIVER_INITIALIZE and DRIVER_UNLOAD + +static void __cdecl __ctors(void) +{ + unsigned long long int const * const * const l = (unsigned long long int const * const * const)&__CTOR_LIST__; + unsigned long long int i = (unsigned long long int)*l; + init_and_deinit_fn const * p; + + if (i == (unsigned long long int)-1) + { + for (i = 1; l[i] != NULL; i++) + ; + i--; + } + + p = (init_and_deinit_fn *)&l[i]; + + while (i--) + { + (**p--)(); + } +} + +static void __cdecl __dtors(void) +{ + func_node * p = atexit_list; + for (; p != NULL; p = p->next) + { + p->func(); + free(p); + } + atexit_list = NULL; +} + +void __cdecl KCRT_OnDriverEntry(void) +{ + __ctors(); +} + +void __cdecl KCRT_OnDriverUnload(void) +{ + __dtors(); +} + +void __cdecl _CRT_DriverUnload(_In_ struct _DRIVER_OBJECT * DriverObject) +{ + DriverUnload(DriverObject); + + KCRT_OnDriverUnload(); +} + +NTSTATUS __cdecl _CRT_DriverEntry(_In_ struct _DRIVER_OBJECT * DriverObject, _In_ PUNICODE_STRING RegistryPath) +{ + KCRT_OnDriverEntry(); + + /* support for service stopping and CRT de-init */ + DriverObject->DriverUnload = _CRT_DriverUnload; + + return DriverEntry(DriverObject, RegistryPath); +} diff --git a/CRT/kcrt.cpp b/CRT/kcrt.cpp new file mode 100644 index 0000000..32681ab --- /dev/null +++ b/CRT/kcrt.cpp @@ -0,0 +1,51 @@ +/* + * Shameless copy pasta from: https://github.com/sidyhe/dxx + * and: https://github.com/liupengs/Mini-CRT + * and some minor modifications. + */ + +#include <cstdio> +#include <cstdlib> + +// new & delete + +void * __cdecl operator new(std::size_t size) +{ + return malloc(size); +} + +void * __cdecl operator new[](size_t size) +{ + return malloc(size); +} + +void __cdecl operator delete(void * ptr) +{ + free(ptr); +} + +void __cdecl operator delete(void * ptr, size_t) +{ + free(ptr); +} + +void __cdecl operator delete[](void * ptr, long long unsigned int) +{ + free(ptr); +} + +void __cdecl operator delete[](void * ptr) +{ + free(ptr); +} + +// EASTL + +void * operator new[](size_t size, const char *, int, unsigned, const char *, int) +{ + return malloc(size); +} +void * operator new[](size_t size, size_t, size_t, const char *, int, unsigned, const char *, int) +{ + return malloc(size); +} diff --git a/EASTL-compat/ucrt.cpp b/CRT/ucrt.cpp index 19ea583..19ea583 100644 --- a/EASTL-compat/ucrt.cpp +++ b/CRT/ucrt.cpp @@ -51,9 +51,9 @@ distclean: clean clean: $(MAKE) -C $(DPP_ROOT) -f Makefile.deps clean - rm -f $(1_OBJECTS) $(1_TARGET) - rm -f $(2_OBJECTS) $(2_TARGET) - rm -f $(3_OBJECTS) $(3_TARGET) + rm -f $(1_OBJECTS) $(1_TARGET) $(1_TARGET).map + rm -f $(2_OBJECTS) $(2_TARGET) $(2_TARGET).map + rm -f $(3_OBJECTS) $(3_TARGET) $(3_TARGET).map .PHONY: all install distclean clean .DEFAULT_GOAL := all diff --git a/Makefile.deps b/Makefile.deps index 9f883f8..ca3d22d 100644 --- a/Makefile.deps +++ b/Makefile.deps @@ -46,8 +46,9 @@ deps-build: \ $(LOCAL_MINGW64_CC) \ $(EASTL_STATIC_LIB) \ $(DRIVER_ADDITIONAL_OBJS) \ - $(DRIVER_EASTL_COMPAT) \ - $(USER_EASTL_COMPAT) \ + $(DRIVER_CRT) \ + $(DRIVER_CRTPLUSPLUS) \ + $(USER_CRT) \ $(SIGNTOOL_PREFIX) deps: deps-print-local-notice deps-build @@ -73,7 +74,7 @@ distclean: clean git submodule deinit --all clean: - rm -f $(DRIVER_EASTL_COMPAT) $(USER_EASTL_COMPAT) $(EASTL_STATIC_LIB) + rm -f $(DRIVER_CRT) $(DRIVER_CRTPLUSPLUS) $(USER_CRT) $(EASTL_STATIC_LIB) rm -f $(DRIVER_ADDITIONAL_OBJS) rm -rf EASTL-build diff --git a/Makefile.inc b/Makefile.inc index 153e84c..3535464 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -18,12 +18,16 @@ CMAKE = cmake CC = $(LOCAL_MINGW64_CC) CXX = $(dir $(CC))x86_64-w64-mingw32-g++ DDK_INCLUDE_DIR = $(dir $(CC))../x86_64-w64-mingw32/include/ddk -CFLAGS := -Wall -Wextra -m64 -fPIC -fvisibility=hidden \ +CFLAGS := -Wall -Wextra -Wno-sign-compare \ + -m64 -fPIC -fvisibility=hidden \ -ffunction-sections -fdata-sections -fno-builtin -ffreestanding \ - -I$(DPP_ROOT) -I$(DDK_INCLUDE_DIR) \ + -I$(DPP_ROOT)/CRT -I$(DDK_INCLUDE_DIR) \ -D__INTRINSIC_DEFINED_InterlockedBitTestAndSet \ -D__INTRINSIC_DEFINED_InterlockedBitTestAndReset -CXXFLAGS := -fno-exceptions -fno-rtti +ifneq ($(WERROR),) +CFLAGS += -Werror +endif +CXXFLAGS := -fno-exceptions -fno-rtti -fuse-cxa-atexit EASTL_CXXFLAGS := -I$(DPP_ROOT)/EASTL/include -I$(DPP_ROOT)/EASTL/test/packages/EABase/include/Common \ -DEASTL_THREAD_SUPPORT_AVAILABLE=0 \ -DEASTL_EXCEPTIONS_ENABLED=0 \ @@ -39,24 +43,27 @@ DRIVER_LDFLAGS := -shared \ -Wl,--file-alignment,0x200 \ -Wl,--section-alignment,0x1000 \ -Wl,--stack,0x100000 \ - -Wl,--entry,DriverEntry \ -Wl,--gc-sections \ + -Wl,--exclude-all-symbols \ + -Wl,--entry,_CRT_DriverEntry \ -nostartfiles -nodefaultlibs -nostdlib DRIVER_LIBS := -lntoskrnl -lhal -USER_LDFLAGS := -Wl,--dynamicbase -Wl,--nxcompat \ - -Wl,--gc-sections +USER_LDFLAGS := -Wl,--dynamicbase -Wl,--nxcompat -Wl,--gc-sections -DRIVER_ADDITIONAL_DEPS := $(DPP_ROOT)/DriverThread.cpp $(DPP_ROOT)/DriverThread.hpp -DRIVER_ADDITIONAL_OBJS := $(DPP_ROOT)/DriverThread.opp +DRIVER_ADDITIONAL_DEPS := $(DPP_ROOT)/CRT/DriverThread.cpp $(DPP_ROOT)/CRT/DriverThread.hpp +DRIVER_ADDITIONAL_OBJS := $(DPP_ROOT)/CRT/DriverThread.opp EASTL_DEPS := $(wildcard $(DPP_ROOT)/EASTL/source/*.cpp) $(wildcard $(DPP_ROOT)/EASTL/include/EASTL/*.h) EASTL_STATIC_LIB := $(DPP_ROOT)/EASTL-build/libEASTL.a -DRIVER_EASTL_COMPAT_DEPS := $(DPP_ROOT)/EASTL-compat/kcrt.cpp -DRIVER_EASTL_COMPAT := $(DPP_ROOT)/EASTL-compat/kcrt.opp +DRIVER_CRT_DEPS := $(DPP_ROOT)/CRT/kcrt.c +DRIVER_CRT := $(DPP_ROOT)/CRT/kcrt.o + +DRIVER_CRTPLUSPLUS_DEPS := $(DPP_ROOT)/CRT/kcrt.cpp $(DPP_ROOT)/CRT/kcrt.c +DRIVER_CRTPLUSPLUS := $(DPP_ROOT)/CRT/kcrt.opp $(DPP_ROOT)/CRT/kcrt.o -USER_EASTL_COMPAT_DEPS := $(DPP_ROOT)/EASTL-compat/ucrt.cpp -USER_EASTL_COMPAT := $(DPP_ROOT)/EASTL-compat/ucrt.opp +USER_CRT_DEPS := $(DPP_ROOT)/CRT/ucrt.cpp +USER_CRT := $(DPP_ROOT)/CRT/ucrt.opp is_set = \ $(if $1,, \ @@ -72,8 +79,9 @@ define CHECK_REQUIRED_PATHS $(call path_exists,$(DDK_INCLUDE_DIR)) $(call path_exists,$(DRIVER_ADDITIONAL_OBJS)) $(call path_exists,$(EASTL_STATIC_LIB)) - $(call path_exists,$(DRIVER_EASTL_COMPAT)) - $(call path_exists,$(USER_EASTL_COMPAT)) + $(call path_exists,$(DRIVER_CRT)) + $(call path_exists,$(DRIVER_CRTPLUSPLUS)) + $(call path_exists,$(USER_CRT)) endef define BUILD_C_OBJECT @@ -99,8 +107,10 @@ define LINK_C_KERNEL_TARGET $(Q)$(CC) \ $(CFLAGS) \ $(DRIVER_LDFLAGS) \ + -Wl,-Map='$(2).map' \ -o '$(2)' \ $(1) \ + $(DRIVER_CRT) \ $(DRIVER_LIBS) @echo 'LD $(2)' endef @@ -126,10 +136,11 @@ define LINK_CPP_KERNEL_TARGET $(CXXFLAGS) \ $(EASTL_CXXFLAGS) \ $(DRIVER_LDFLAGS) \ + -Wl,-Map='$(2).map' \ -o '$(2)' \ $(1) \ $(DRIVER_ADDITIONAL_OBJS) \ - $(DRIVER_EASTL_COMPAT) \ + $(DRIVER_CRTPLUSPLUS) \ $(EASTL_STATIC_LIB) \ $(DRIVER_LIBS) @echo 'LD $(2)' @@ -146,7 +157,7 @@ define LINK_CPP_USER_TARGET $(USER_LDFLAGS) \ -o '$(2)' \ $(1) \ - $(USER_EASTL_COMPAT) \ + $(USER_CRT) \ $(EASTL_STATIC_LIB) @echo 'LD $(2)' endef @@ -67,19 +67,31 @@ install: $(DRIVER_TARGET) $(call INSTALL_EXEC_SIGN,$(DRIVER_TARGET)) ``` -## Known issues +## The CRT and CRT++ -Defining classes (by value, not pointer) with a static qualifier won't work because something seems broken with the static initialization of (non-primitive) globals. -Meaning code `static MyClass test;` fails whereas `static MyClass * test = new MyClass();` will sill work. +This project uses a very very rudimentary CRT for C and C++ projects. +Please keep in mind that depending on what you want to do the CRT may lack features you are familiar with. +Usually copy&pasting them from various online sources should be sufficient. -The issue is related to `__static_initialization_and_destruction` as it does not call the appropriate ctor's and dtor's (pushing dtor's via `atexit()`). -The latter one may be related to `-Wl,--subsystem,native` as in kernel space there is usually no need for calling `atexit()`. -I've tried adding C++ initializers manually, but they did not survive linker optimizations. There may be custom linker script required to fix it. +Remember: The CRT and CRT++ **sets a driver unload function** meaning that code .e.g.: + +```C +NTSTATUS MyDriverEntry(_In_ struct _DRIVER_OBJECT * DriverObject, _In_ PUNICODE_STRING RegistryPath) +{ + DriverObject->DriverUnload = MyDriverUnload; +} +``` + +shouldn't be used. Instead the function `DriverUnload` will be called. +So make sure that the symbol `DriverUnload` exists and has the usual ddk function signature: +`void DriverUnload(_In_ struct _DRIVER_OBJECT * DriverObject)`. +This is required to make ctors/dtors work without calling additional functions in `DriverEntry` / `DriverUnload`. ## Thanks! - [Zeranoe](https://github.com/Zeranoe/mingw-w64-build) for the Mingw64 build script - [sidyhe](https://github.com/sidyhe/dxx) for some copy paste ready CRT code ;) +- [liupengs](https://github.com/liupengs/Mini-CRT) helped me to fix the ctor/dtor issue and last but not least: diff --git a/ddk-template-cplusplus-EASTL.cpp b/ddk-template-cplusplus-EASTL.cpp index e099488..d3cb0e3 100644 --- a/ddk-template-cplusplus-EASTL.cpp +++ b/ddk-template-cplusplus-EASTL.cpp @@ -107,9 +107,6 @@ extern "C" DbgPrint("%s\n", "Hello ring0!"); - /* support for service stopping */ - DriverObject->DriverUnload = DriverUnload; - stl_test(); more_stl_test(); diff --git a/ddk-template-cplusplus.cpp b/ddk-template-cplusplus.cpp index 380603a..f9167ec 100644 --- a/ddk-template-cplusplus.cpp +++ b/ddk-template-cplusplus.cpp @@ -35,6 +35,29 @@ public: } }; +class DerivedWithCDtor : public Derived +{ +public: + explicit DerivedWithCDtor(unsigned int value) + { + some_value = value; + DbgPrint("%s\n", "DerivedWithCDtor-Ctor."); + } + ~DerivedWithCDtor() + { + DbgPrint("%s\n", "DerivedWithCDtor-Dtor."); + } + void doSmth(void) + { + DbgPrint("SomeValue: %X\n", some_value); + } + +private: + unsigned int some_value = 0; +}; + +static DerivedWithCDtor some_static(0xDEADC0DE); + struct threadContext { DriverThread::Semaphore sem; @@ -70,6 +93,8 @@ static void test_cplusplus(void) ctx.dth.WaitForTermination(); ctx.dth.WaitForTermination(); DbgPrint("MainThread EOF\n"); + + some_static.doSmth(); } extern "C" @@ -86,9 +111,6 @@ extern "C" DbgPrint("%s\n", "Hello ring0!"); cdtor_test = new TestSmth(); - /* support for service stopping */ - DriverObject->DriverUnload = DriverUnload; - test_cplusplus(); return STATUS_SUCCESS; diff --git a/ddk-template.c b/ddk-template.c index 9667b18..2d7becd 100644 --- a/ddk-template.c +++ b/ddk-template.c @@ -13,9 +13,6 @@ NTSTATUS DriverEntry( DbgPrint("%s\n", "Hello ring0!"); - /* support for service stopping */ - DriverObject->DriverUnload = DriverUnload; - return STATUS_SUCCESS; } |