diff options
-rw-r--r-- | .clang-format | 77 | ||||
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | EASTL-compat/kcrt.cpp | 208 | ||||
-rw-r--r-- | EASTL/source/assert.cpp | 6 | ||||
-rw-r--r-- | EASTL/source/thread_support.cpp | 6 | ||||
-rw-r--r-- | Makefile | 51 | ||||
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | ddk-template-cplusplus-EASTL.cpp | 125 | ||||
-rw-r--r-- | ddk-template-cplusplus.cpp | 44 | ||||
-rw-r--r-- | ddk-template.c | 5 |
10 files changed, 507 insertions, 35 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..aeb942a --- /dev/null +++ b/.clang-format @@ -0,0 +1,77 @@ +Language: Cpp +BasedOnStyle : LLVM +Standard : Cpp03 +# BasedOnStyle: LLVM +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: true +ConstructorInitializerIndentWidth: 4 +AlignEscapedNewlinesLeft: false +AlignTrailingComments: true +AllowShortBlocksOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: false +AlwaysBreakTemplateDeclarations: true +AlwaysBreakBeforeMultilineStrings: true +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +DerivePointerAlignment: false +ExperimentalAutoDetectBinPacking: false +IndentCaseLabels: true +IndentWrappedFunctionNames: false +IndentFunctionDeclarationAfterType: false +MaxEmptyLinesToKeep: 1 +KeepEmptyLinesAtTheStartOfBlocks: true +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false + +PenaltyExcessCharacter : 500 +PenaltyReturnTypeOnItsOwnLine : 120 +PenaltyBreakBeforeFirstCallParameter : 100 +PenaltyBreakString : 20 +PenaltyBreakComment : 10 +PenaltyBreakFirstLessLess : 0 + +SpacesBeforeTrailingComments: 1 +Cpp11BracedListStyle: true +IndentWidth: 4 +TabWidth: 4 +UseTab: Never +BreakBeforeBraces: Allman +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpacesInAngles : false +SpaceInEmptyParentheses : false +SpacesInCStyleCastParentheses : false +SpaceAfterCStyleCast : false +SpacesInContainerLiterals : true +SpaceBeforeAssignmentOperators : true +ContinuationIndentWidth : 4 +SpaceBeforeParens : ControlStatements +DisableFormat : false +AccessModifierOffset : -4 +PointerAlignment : Middle +AlignAfterOpenBracket : Align +AllowAllParametersOfDeclarationOnNextLine : true +BinPackArguments : false +BinPackParameters : false +AlignOperands : true +AlignConsecutiveAssignments : false +AllowShortFunctionsOnASingleLine : None +BreakBeforeBinaryOperators : None +AlwaysBreakAfterReturnType : None +SortIncludes : false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..04fea95 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.deps-built +/EASTL-build +/x86_64-w64-mingw32 +*.o +*.opp diff --git a/EASTL-compat/kcrt.cpp b/EASTL-compat/kcrt.cpp new file mode 100644 index 0000000..7a8fc52 --- /dev/null +++ b/EASTL-compat/kcrt.cpp @@ -0,0 +1,208 @@ +/* + * Shameless copy pasta from: https://github.com/sidyhe/dxx + */ + +#include <cstdio> +#include <cstdlib> + +#include <ntddk.h> + +#define KCRT_POOL_DEFAULT_TAG 0xDEADBEEF + +typedef struct _MALLOC_HEADER +{ + ULONG32 Tags; + ULONG32 _Resv0; + ULONG_PTR Size; +} MALLOC_HEADER, *PMALLOC_HEADER; +C_ASSERT(sizeof(MALLOC_HEADER) % sizeof(void *) == 0); + +// dynamic memory mgmt + +PMALLOC_HEADER GET_MALLOC_HEADER(PVOID ptr) +{ + return (MALLOC_HEADER *)((PUCHAR)ptr - sizeof(MALLOC_HEADER)); +} + +PVOID GET_MALLOC_ADDRESS(PMALLOC_HEADER header) +{ + return (PVOID)((PUCHAR)header + sizeof(MALLOC_HEADER)); +} + +ULONG_PTR GET_MALLOC_SIZE(PVOID ptr) +{ + PMALLOC_HEADER header = GET_MALLOC_HEADER(ptr); + + if (header->Tags != KCRT_POOL_DEFAULT_TAG) + KeBugCheckEx(BAD_POOL_HEADER, 0, 0, 0, 0); + + return header->Size; +} + +// c runtime + +void __cdecl free(void * ptr) +{ + if (ptr) + { + MALLOC_HEADER * mhdr = GET_MALLOC_HEADER(ptr); + + if (mhdr->Tags != KCRT_POOL_DEFAULT_TAG) + KeBugCheckEx(BAD_POOL_HEADER, 0, 0, 0, 0); + + ExFreePool(mhdr); + } +} + +void * __cdecl malloc(size_t size) +{ + PMALLOC_HEADER mhdr = NULL; + const size_t new_size = size + sizeof(MALLOC_HEADER); + + mhdr = (PMALLOC_HEADER)ExAllocatePoolWithTag(NonPagedPool, new_size, KCRT_POOL_DEFAULT_TAG); + if (mhdr) + { + RtlZeroMemory(mhdr, new_size); + + mhdr->Tags = KCRT_POOL_DEFAULT_TAG; + mhdr->Size = size; + return GET_MALLOC_ADDRESS(mhdr); + } + + return NULL; +} + +void * __cdecl realloc(void * ptr, size_t new_size) +{ + if (!ptr) + { + return malloc(new_size); + } + else if (new_size == 0) + { + free(ptr); + return NULL; + } + else + { + size_t old_size = GET_MALLOC_SIZE(ptr); + + if (new_size <= old_size) + { + return ptr; + } + else + { + void * new_ptr = malloc(new_size); + + if (new_ptr) + { + memcpy(new_ptr, ptr, old_size); + free(ptr); + return new_ptr; + } + } + } + + 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) +{ +} + +// stolen from musl: https://elixir.bootlin.com/musl/v1.1.9/source/src/math/ceilf.c +#define FORCE_EVAL(x) \ + do \ + { \ + if (sizeof(x) == sizeof(float)) \ + { \ + volatile float __x __attribute__((unused)); \ + __x = (x); \ + } \ + else if (sizeof(x) == sizeof(double)) \ + { \ + volatile double __x __attribute__((unused)); \ + __x = (x); \ + } \ + else \ + { \ + volatile long double __x __attribute__((unused)); \ + __x = (x); \ + } \ + } while (0) + +extern "C" float ceilf(float x) +{ + union { + float f; + UINT32 i; + } u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + UINT32 m; + + if (e >= 23) + return x; + if (e >= 0) + { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i += m; + u.i &= ~m; + } + else + { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.f = -0.0; + else if (u.i << 1) + u.f = 1.0; + } + return u.f; +} diff --git a/EASTL/source/assert.cpp b/EASTL/source/assert.cpp index 7d32d5e..a4734af 100644 --- a/EASTL/source/assert.cpp +++ b/EASTL/source/assert.cpp @@ -15,7 +15,11 @@ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif - #include <Windows.h> + #ifdef __MINGW64__ + #include <windows.h> + #else + #include <Windows.h> + #endif EA_RESTORE_ALL_VC_WARNINGS(); #elif defined(EA_PLATFORM_ANDROID) #include <android/log.h> diff --git a/EASTL/source/thread_support.cpp b/EASTL/source/thread_support.cpp index 1b03629..3b8550e 100644 --- a/EASTL/source/thread_support.cpp +++ b/EASTL/source/thread_support.cpp @@ -13,7 +13,11 @@ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif - #include <Windows.h> + #ifdef __MINGW64__ + #include <windows.h> + #else + #include <Windows.h> + #endif EA_RESTORE_ALL_VC_WARNINGS(); #endif @@ -3,13 +3,26 @@ LOCAL_MINGW64_BUILD_DIR := ./x86_64-w64-mingw32 LOCAL_MINGW64_CC := $(LOCAL_MINGW64_BUILD_DIR)/bin/x86_64-w64-mingw32-gcc LOCAL_MINGW64_DDK_INCLUDE_DIR := $(LOCAL_MINGW64_BUILD_DIR)/x86_64-w64-mingw32/include/ddk +CMAKE = cmake CC = $(LOCAL_MINGW64_CC) CXX = $(dir $(CC))/x86_64-w64-mingw32-g++ DDK_INCLUDE_DIR = $(LOCAL_MINGW64_DDK_INCLUDE_DIR) -CFLAGS = -Wall -m64 -shared \ +CFLAGS := -Wall -Wextra -m64 -shared \ -I$(DDK_INCLUDE_DIR) \ -D__INTRINSIC_DEFINED_InterlockedBitTestAndSet \ -D__INTRINSIC_DEFINED_InterlockedBitTestAndReset +CXXFLAGS := -fno-exceptions -fno-rtti +EASTL_CXXFLAGS := -IEASTL/include -IEASTL/test/packages/EABase/include/Common \ + -DEASTL_THREAD_SUPPORT_AVAILABLE=0 \ + -DEASTL_EXCEPTIONS_ENABLED=0 \ + -DEASTL_ASSERT_ENABLED=0 \ + -DEA_COMPILER_NO_EXCEPTIONS=1 \ + -DEA_COMPILER_MANAGED_CPP=1 \ + -Wno-unknown-pragmas \ + -Wno-deprecated-copy \ + -Wl,--gc-sections +EASTL_STATIC_LIB := EASTL-build/libEASTL.a +EASTL_COMPAT := EASTL-compat/kcrt.opp 1_DRIVER_NAME = ddk-template 1_OBJECTS = $(1_DRIVER_NAME).o @@ -19,9 +32,13 @@ CFLAGS = -Wall -m64 -shared \ 2_OBJECTS = $(2_DRIVER_NAME).opp 2_TARGET = $(2_DRIVER_NAME).sys -all: deps-print-local-notice check-vars $(1_TARGET) $(2_TARGET) +3_DRIVER_NAME = ddk-template-cplusplus-EASTL +3_OBJECTS = $(3_DRIVER_NAME).opp +3_TARGET = $(3_DRIVER_NAME).sys -deps-print-local-notice: +all: deps-print-local-notice check-vars $(1_TARGET) $(2_TARGET) $(3_TARGET) + +deps-print-local-notice: $(CC) ifeq ($(CC),$(LOCAL_MINGW64_CC)) ifeq ($(DDK_INCLUDE_DIR),$(LOCAL_MINGW64_DDK_INCLUDE_DIR)) @echo @@ -80,15 +97,31 @@ endif deps: .deps-built +$(EASTL_STATIC_LIB): .deps-built + mkdir -p EASTL-build + cd EASTL-build && \ + $(CMAKE) ../EASTL \ + -DCMAKE_CXX_COMPILER="$(realpath $(CXX))" \ + -DCMAKE_SYSTEM_NAME="Windows" \ + -DCMAKE_CXX_FLAGS='-ffunction-sections -fdata-sections $(CXXFLAGS) $(EASTL_CXXFLAGS)' && \ + $(MAKE) VERBOSE=1 + +distclean: clean + rm -f .deps-built + rm -rf $(LOCAL_MINGW64_BUILD_DIR) + clean: rm -f $(1_OBJECTS) $(1_TARGET) rm -f $(2_OBJECTS) $(2_TARGET) + rm -f $(3_OBJECTS) $(3_TARGET) + rm -f $(EASTL_COMPAT) $(EASTL_STATIC_LIB) + $(MAKE) -C EASTL-build clean -%.o: %.c +%.o: %.c .deps-built $(CC) $(CFLAGS) -c $< -o $@ -%.opp: %.cpp - $(CXX) $(CFLAGS) -c $< -o $@ +%.opp: %.cpp .deps-built + $(CXX) $(CFLAGS) $(CXXFLAGS) $(EASTL_CXXFLAGS) -c $< -o $@ $(1_TARGET): .deps-built $(1_OBJECTS) $(CC) -std=c99 $(CFLAGS) -Wl,--subsystem,native -Wl,--image-base,0x140000000 -Wl,--dynamicbase -Wl,--nxcompat \ @@ -101,3 +134,9 @@ $(2_TARGET): .deps-built $(2_OBJECTS) -Wl,--file-alignment,0x200 -Wl,--section-alignment,0x1000 -Wl,--stack,0x100000 \ -Wl,--entry,DriverEntry@8 -nostartfiles -nostdlib -o $(2_TARGET) \ $(2_OBJECTS) -lntoskrnl -lhal + +$(3_TARGET): .deps-built $(EASTL_STATIC_LIB) $(EASTL_COMPAT) $(3_OBJECTS) + $(CXX) $(CFLAGS) $(CXXFLAGS) $(EASTL_CXXFLAGS) -Wl,--subsystem,native -Wl,--image-base,0x140000000 -Wl,--dynamicbase -Wl,--nxcompat \ + -Wl,--file-alignment,0x200 -Wl,--section-alignment,0x1000 -Wl,--stack,0x100000 \ + -Wl,--entry,DriverEntry@8 -nostartfiles -nostdlib -o $(3_TARGET) \ + $(3_OBJECTS) $(EASTL_COMPAT) $(EASTL_STATIC_LIB) -lntoskrnl -lhal @@ -1,8 +1,9 @@ -# Mingw64 [D]river [D]evelopment [K]it - Template +# Mingw64 Driver Plus Plus A demonstration on how to compile Windows kernel drivers using Mingw64. -## How? +It provides also an example with a feature complete STL including your +beloved containers. You will need an modern Mingw64-GCC toolchain. Do not use any broken toolchains like the one shipped with debian-10. @@ -10,8 +11,9 @@ Instead either use Zeranoe's build script with `make deps` or use your own. ## What? -1. ddk-template: plain and stupid ddk example -2. ddk-template-cplusplus: same, but in C++, including a very complex class +1. ddk-template: plain and stupid ddk C example +2. ddk-template-cplusplus: same, but written in C++, including a very complex class +3. ddk-template-cplusplus: C++ example w/ (EA)STL integration, everything usable except for Threads ## Build and Test @@ -32,3 +34,8 @@ Build Mingw64 only: `` make deps `` + +## Thanks! + +- [Zeranoe](https://github.com/Zeranoe/mingw-w64-build) for the Mingw64 build script +- [sidhye](https://github.com/sidhye/dxx) for some copy paste ready CRT code ;) diff --git a/ddk-template-cplusplus-EASTL.cpp b/ddk-template-cplusplus-EASTL.cpp new file mode 100644 index 0000000..e099488 --- /dev/null +++ b/ddk-template-cplusplus-EASTL.cpp @@ -0,0 +1,125 @@ +#include <ntddk.h> + +#include <cstdint> + +#include <EASTL/functional.h> +#include <EASTL/hash_map.h> +#include <EASTL/random.h> +#include <EASTL/scoped_ptr.h> +#include <EASTL/set.h> +#include <EASTL/shared_ptr.h> +#include <EASTL/sort.h> +#include <EASTL/string.h> +#include <EASTL/map.h> +#include <EASTL/unordered_map.h> +#include <EASTL/unordered_set.h> +#include <EASTL/vector.h> + +// C&P from: https://raw.githubusercontent.com/sidyhe/dxx/ed06aba3b91fe8e101d08c33c26ba73db96acef0/README.md +void stl_test() +{ + eastl::make_unique<DRIVER_OBJECT>(); + eastl::make_shared<UNICODE_STRING>(); + eastl::scoped_ptr<double> dptr(new double(3.6)); + + eastl::set<int> set_test; + set_test.insert(1); + set_test.insert(3); + set_test.insert(5); + set_test.erase(1); + + eastl::map<int, int> map_test; + map_test[0] = 1; + map_test[10] = 11; + map_test[20] = 12; + map_test.erase(11); + + eastl::vector<int> vec_test; + vec_test.push_back(2); + vec_test.push_back(3); + vec_test.push_back(1); + eastl::stable_sort(vec_test.begin(), vec_test.end(), eastl::less<int>()); + for (auto e : vec_test) + { + DbgPrint("%d\n", e); + } + + eastl::string s; + s = "This a string"; + s.append("any"); + DbgPrint("%s\n", s.c_str()); + + eastl::wstring ws; + ws = L"wide string"; + ws.clear(); + + eastl::unordered_set<float> us_test; + us_test.insert(333); + + eastl::unordered_map<double, eastl::string> um_test; + um_test.insert(eastl::make_pair(6.6, "9.9")); +} + +void more_stl_test() +{ + eastl::hash_map<int, eastl::string> hm; + + hm[0] = "test1"; + hm[10] = "test2"; + hm[20] = "test3"; + for (auto s : hm) + { + DbgPrint("%s\n", s.second.c_str()); + } + + eastl::uniform_int_distribution<std::uint32_t> uid(1, UINT32_MAX); + DbgPrint("PRNG: %u\n", uid); + + auto lambda = [] { DbgPrint("Hello lambda!\n"); }; + eastl::function<void(void)> fn = lambda; + fn(); + + auto lambda2 = [](int n) { + DbgPrint("Hello lambda2, %u!\n", n); + return n; + }; + eastl::function<int(int)> fn2 = lambda2; + fn2(1337); + + eastl::vector<std::uint32_t> fill_me; + for (auto i = UINT16_MAX; i > 0; --i) + { + fill_me.push_back(i); + } + DbgPrint("fill_me size: %zu\n", fill_me.size()); +} + +extern "C" +{ + + DRIVER_INITIALIZE DriverEntry; + DRIVER_UNLOAD DriverUnload; + + NTSTATUS DriverEntry(_In_ struct _DRIVER_OBJECT * DriverObject, _In_ PUNICODE_STRING RegistryPath) + { + (void)DriverObject; + (void)RegistryPath; + + DbgPrint("%s\n", "Hello ring0!"); + + /* support for service stopping */ + DriverObject->DriverUnload = DriverUnload; + + stl_test(); + more_stl_test(); + + return STATUS_SUCCESS; + } + + VOID DriverUnload(_In_ struct _DRIVER_OBJECT * DriverObject) + { + (void)DriverObject; + + DbgPrint("%s\n", "Bye ring0!"); + } +} diff --git a/ddk-template-cplusplus.cpp b/ddk-template-cplusplus.cpp index 3ab6257..f4e3ce4 100644 --- a/ddk-template-cplusplus.cpp +++ b/ddk-template-cplusplus.cpp @@ -1,11 +1,11 @@ #include <ntddk.h> -#include <vector> - class TestSmth { public: - TestSmth() {} + TestSmth() + { + } void doSmth(void) { DbgPrint("%s\n", "Hello Class!"); @@ -21,30 +21,28 @@ static void test_cplusplus(void) extern "C" { -DRIVER_INITIALIZE DriverEntry; -DRIVER_UNLOAD DriverUnload; + DRIVER_INITIALIZE DriverEntry; + DRIVER_UNLOAD DriverUnload; -NTSTATUS DriverEntry( - _In_ struct _DRIVER_OBJECT *DriverObject, - _In_ PUNICODE_STRING RegistryPath -) -{ - DbgPrint("%s\n", "Hello ring0!"); + NTSTATUS DriverEntry(_In_ struct _DRIVER_OBJECT * DriverObject, _In_ PUNICODE_STRING RegistryPath) + { + (void)DriverObject; + (void)RegistryPath; - /* support for service stopping */ - DriverObject->DriverUnload = DriverUnload; + DbgPrint("%s\n", "Hello ring0!"); - test_cplusplus(); + /* support for service stopping */ + DriverObject->DriverUnload = DriverUnload; - return STATUS_SUCCESS; -} + test_cplusplus(); -VOID -DriverUnload( - _In_ struct _DRIVER_OBJECT *DriverObject -) -{ - DbgPrint("%s\n", "Bye ring0!"); -} + return STATUS_SUCCESS; + } + VOID DriverUnload(_In_ struct _DRIVER_OBJECT * DriverObject) + { + (void)DriverObject; + + DbgPrint("%s\n", "Bye ring0!"); + } } diff --git a/ddk-template.c b/ddk-template.c index 9374b1f..9667b18 100644 --- a/ddk-template.c +++ b/ddk-template.c @@ -8,6 +8,9 @@ NTSTATUS DriverEntry( _In_ PUNICODE_STRING RegistryPath ) { + (void)DriverObject; + (void)RegistryPath; + DbgPrint("%s\n", "Hello ring0!"); /* support for service stopping */ @@ -21,5 +24,7 @@ DriverUnload( _In_ struct _DRIVER_OBJECT *DriverObject ) { + (void)DriverObject; + DbgPrint("%s\n", "Bye ring0!"); } |