From c174ed117759d97d278f3d469547c0838b7284cb Mon Sep 17 00:00:00 2001 From: Youhei Sakurai Date: Tue, 13 Sep 2016 00:50:13 +0900 Subject: [PATCH 01/35] Remove stdint.h for VC++9.0 (VS2008) --- MemoryModule.c | 1 - 1 file changed, 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index d8d3f3a..200e60f 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #ifdef DEBUG_OUTPUT #include From 164b21ac07c38e92da65b7163d501afb73e5377a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 21:38:19 +0200 Subject: [PATCH 02/35] Move AppVeyor test code to script. --- appveyor.yml | 21 +++++---------------- scripts/run-appveyor.bat | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 scripts/run-appveyor.bat diff --git a/appveyor.yml b/appveyor.yml index 8fb52dd..c64b8b9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,20 +31,9 @@ platform: configuration: - Debug -build: - verbosity: normal +install: + - call scripts\run-appveyor.bat -build_script: - - ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" } - - cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -H. -Bbuild - - cmake --build build --config %CONFIGURATION% - -before_test: - - copy /y build\example\DllLoader\%CONFIGURATION%\DllLoader.exe build\example\DllLoader\ - - copy /y build\example\DllLoader\%CONFIGURATION%\DllLoaderLoader.exe build\example\DllLoader\ - - copy /y build\example\SampleDLL\%CONFIGURATION%\SampleDLL.dll build\example\SampleDLL\ - -test_script: - - cd build\example\DllLoader - - DllLoader.exe - - DllLoaderLoader.exe +build: off +test: off +deploy: off diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat new file mode 100644 index 0000000..2b2eb13 --- /dev/null +++ b/scripts/run-appveyor.bat @@ -0,0 +1,36 @@ +@echo off +setlocal + +if /I "%PLATFORM" == "x64" ( + set CMAKE_GEN_SUFFIX= Win64 +) else ( + set CMAKE_GEN_SUFFIX= +) + +echo. +echo Preparing %CONFIGURATION% build environment for %GENERATOR%%CMAKE_GEN_SUFFIX% ... +cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -H. -Bbuild +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo Building ... +cmake --build build --config %CONFIGURATION% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo Copying generated files ... +copy /y build\example\DllLoader\%CONFIGURATION%\DllLoader.exe build\example\DllLoader\ > NUL +copy /y build\example\DllLoader\%CONFIGURATION%\DllLoaderLoader.exe build\example\DllLoader\ > NUL +copy /y build\example\SampleDLL\%CONFIGURATION%\SampleDLL.dll build\example\SampleDLL\ > NUL + +cd build\example\DllLoader + +echo. +echo Running DllLoader.exe ... +DllLoader.exe +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo Running DllLoaderLoader.exe ... +DllLoaderLoader.exe +if %errorlevel% neq 0 exit /b %errorlevel% From af2c521cf2734bb372e78625f699836b19a13202 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 21:41:34 +0200 Subject: [PATCH 03/35] Added .gitattributes file. --- .gitattributes | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a725a5d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto + +# Native line endings. +*.c text +*.cpp text +*.h text +*.rc text + +# Windows line endings. +*.bat text eol=crlf +*.eln text eol=crlf From d19c62ed8204e8a1906e5c4ae07ca86291185d13 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 22:27:02 +0200 Subject: [PATCH 04/35] Fixed detection of x64 platform. --- scripts/run-appveyor.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat index 2b2eb13..4390e3a 100644 --- a/scripts/run-appveyor.bat +++ b/scripts/run-appveyor.bat @@ -1,7 +1,7 @@ @echo off setlocal -if /I "%PLATFORM" == "x64" ( +if /I "%PLATFORM%" == "x64" ( set CMAKE_GEN_SUFFIX= Win64 ) else ( set CMAKE_GEN_SUFFIX= From 1d19f9f750b632ad3b8b85de821dfd447869100b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 22:43:01 +0200 Subject: [PATCH 05/35] Pass PLATFORM/UNICODE to cmake. --- scripts/run-appveyor.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat index 4390e3a..cb34169 100644 --- a/scripts/run-appveyor.bat +++ b/scripts/run-appveyor.bat @@ -9,7 +9,7 @@ if /I "%PLATFORM%" == "x64" ( echo. echo Preparing %CONFIGURATION% build environment for %GENERATOR%%CMAKE_GEN_SUFFIX% ... -cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -H. -Bbuild +cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DPLATFORM=%PLATFORM% -DUNICODE=%UNICODE% -H. -Bbuild if %errorlevel% neq 0 exit /b %errorlevel% echo. From b26476ff8d932a2794131cf45ef71c4adedb5189 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 12 Sep 2016 18:05:00 +0200 Subject: [PATCH 06/35] Also run CI against Visual Studio 9. --- appveyor.yml | 4 ++++ scripts/run-appveyor.bat | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index c64b8b9..4282d88 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,10 @@ os: environment: matrix: + - GENERATOR: "Visual Studio 9 2008" + UNICODE: ON + - GENERATOR: "Visual Studio 9 2008" + UNICODE: OFF - GENERATOR: "Visual Studio 10 2010" UNICODE: ON - GENERATOR: "Visual Studio 10 2010" diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat index cb34169..0bc2943 100644 --- a/scripts/run-appveyor.bat +++ b/scripts/run-appveyor.bat @@ -3,6 +3,10 @@ setlocal if /I "%PLATFORM%" == "x64" ( set CMAKE_GEN_SUFFIX= Win64 + if /I "%GENERATOR%" == "Visual Studio 9 2008" ( + echo Skipping %CONFIGURATION% build using %GENERATOR%%CMAKE_GEN_SUFFIX% on %PLATFORM% + exit 0 + ) ) else ( set CMAKE_GEN_SUFFIX= ) From de5dbce7701c73f748f49e31152c988843759383 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 22:51:39 +0200 Subject: [PATCH 07/35] Error on some type conversion warnings. --- CMakeLists.txt | 1 + MemoryModule.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ddd49a..e2a3676 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ endif () if (NOT MSVC) add_definitions ("-Wall") else () + # Show level 4 warnings. add_definitions ("-W4") endif () diff --git a/MemoryModule.c b/MemoryModule.c index 200e60f..3a6162a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -35,6 +35,10 @@ #if _MSC_VER // Disable warning about data -> function pointer conversion #pragma warning(disable:4055) + // C4244: conversion from 'uintptr_t' to 'DWORD', possible loss of data. +#pragma warning(error: 4244) +// C4267: conversion from 'size_t' to 'int', possible loss of data. +#pragma warning(error: 4267) #endif #ifndef IMAGE_SIZEOF_BASE_RELOCATION From 03cd7c91d98963f30a95d639a1d7865be2afc20a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 23:59:33 +0200 Subject: [PATCH 08/35] Fixed alignment of values/addresses on 64bit systems. --- MemoryModule.c | 90 +++++++++++++++++++++++++++++++++++++++++++---- tests/Makefile | 12 +++++-- tests/TestSuite.c | 17 +++++++++ 3 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 tests/TestSuite.c diff --git a/MemoryModule.c b/MemoryModule.c index 3a6162a..60511d4 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -39,6 +39,8 @@ #pragma warning(error: 4244) // C4267: conversion from 'size_t' to 'int', possible loss of data. #pragma warning(error: 4267) + +#define inline __inline #endif #ifndef IMAGE_SIZEOF_BASE_RELOCATION @@ -78,8 +80,21 @@ typedef struct { } SECTIONFINALIZEDATA, *PSECTIONFINALIZEDATA; #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] -#define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1)) -#define ALIGN_VALUE_UP(value, alignment) (((value) + (alignment) - 1) & ~((alignment) - 1)) + +static inline uintptr_t +AlignValueDown(uintptr_t value, uintptr_t alignment) { + return value & ~(alignment - 1); +} + +static inline LPVOID +AlignAddressDown(LPVOID address, uintptr_t alignment) { + return (LPVOID) AlignValueDown((uintptr_t) address, alignment); +} + +static inline size_t +AlignValueUp(size_t value, size_t alignment) { + return (value + alignment - 1) & ~(alignment - 1); +} #ifdef DEBUG_OUTPUT static void @@ -246,7 +261,7 @@ FinalizeSections(PMEMORYMODULE module) #endif SECTIONFINALIZEDATA sectionData; sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); - sectionData.alignedAddress = ALIGN_DOWN(sectionData.address, module->pageSize); + sectionData.alignedAddress = AlignAddressDown(sectionData.address, module->pageSize); sectionData.size = GetRealSectionSize(module, section); sectionData.characteristics = section->Characteristics; sectionData.last = FALSE; @@ -255,7 +270,7 @@ FinalizeSections(PMEMORYMODULE module) // loop through all sections and change access flags for (i=1; iheaders->FileHeader.NumberOfSections; i++, section++) { LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); - LPVOID alignedAddress = ALIGN_DOWN(sectionAddress, module->pageSize); + LPVOID alignedAddress = AlignAddressDown(sectionAddress, module->pageSize); DWORD sectionSize = GetRealSectionSize(module, section); // Combine access flags of all sections that share a page // TODO(fancycode): We currently share flags of a trailing large section @@ -547,8 +562,8 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } GetNativeSystemInfo(&sysInfo); - alignedImageSize = ALIGN_VALUE_UP(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize); - if (alignedImageSize != ALIGN_VALUE_UP(lastSectionEnd, sysInfo.dwPageSize)) { + alignedImageSize = AlignValueUp(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize); + if (alignedImageSize != AlignValueUp(lastSectionEnd, sysInfo.dwPageSize)) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } @@ -998,3 +1013,66 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO #endif return size; } + +#ifdef TESTSUITE +#include +#include + +#ifndef PRIxPTR +#ifdef _WIN64 +#define PRIxPTR "I64x" +#else +#define PRIxPTR "x" +#endif +#endif + +static const uintptr_t AlignValueDownTests[][3] = { + {16, 16, 16}, + {17, 16, 16}, + {32, 16, 32}, + {33, 16, 32}, +#ifdef _WIN64 + {0x12345678abcd1000, 0x1000, 0x12345678abcd1000}, + {0x12345678abcd101f, 0x1000, 0x12345678abcd1000}, +#endif + {0, 0, 0}, +}; + +static const uintptr_t AlignValueUpTests[][3] = { + {16, 16, 16}, + {17, 16, 32}, + {32, 16, 32}, + {33, 16, 48}, +#ifdef _WIN64 + {0x12345678abcd1000, 0x1000, 0x12345678abcd1000}, + {0x12345678abcd101f, 0x1000, 0x12345678abcd2000}, +#endif + {0, 0, 0}, +}; + +BOOL MemoryModuleTestsuite() { + BOOL success = TRUE; + for (size_t idx = 0; AlignValueDownTests[idx][0]; ++idx) { + const uintptr_t* tests = AlignValueDownTests[idx]; + uintptr_t value = AlignValueDown(tests[0], tests[1]); + if (value != tests[2]) { + printf("AlignValueDown failed for 0x%" PRIxPTR "/0x%" PRIxPTR ": expected 0x%" PRIxPTR ", got 0x%" PRIxPTR "\n", + tests[0], tests[1], tests[2], value); + success = FALSE; + } + } + for (size_t idx = 0; AlignValueDownTests[idx][0]; ++idx) { + const uintptr_t* tests = AlignValueUpTests[idx]; + uintptr_t value = AlignValueUp(tests[0], tests[1]); + if (value != tests[2]) { + printf("AlignValueUp failed for 0x%" PRIxPTR "/0x%" PRIxPTR ": expected 0x%" PRIxPTR ", got 0x%" PRIxPTR "\n", + tests[0], tests[1], tests[2], value); + success = FALSE; + } + } + if (success) { + printf("OK\n"); + } + return success; +} +#endif diff --git a/tests/Makefile b/tests/Makefile index f167a72..9df5da5 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -16,7 +16,7 @@ RC = rc endif RM = rm -CFLAGS = -Wall -g +CFLAGS = -Wall -g -DTESTSUITE LDFLAGS = RCFLAGS = -O coff @@ -49,13 +49,20 @@ TEST_DLLS = \ test-relocate.dll \ LOADDLL_OBJ = LoadDll.o ../MemoryModule.o +TESTSUITE_OBJ = TestSuite.o ../MemoryModule.o DLL_OBJ = SampleDLL.o SampleDLL.res -all: LoadDll.exe $(TEST_DLLS) +all: prepare_testsuite LoadDll.exe TestSuite.exe $(TEST_DLLS) + +prepare_testsuite: + rm -f $(TESTSUITE_OBJ) LoadDll.exe: $(LOADDLL_OBJ) $(CC) $(LDFLAGS_EXE) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o LoadDll.exe $(LOADDLL_OBJ) +TestSuite.exe: $(TESTSUITE_OBJ) + $(CC) $(LDFLAGS_EXE) $(LDFLAGS) -o TestSuite.exe $(TESTSUITE_OBJ) + LoadDll.o: LoadDll.cpp $(CXX) $(CFLAGS) $(CFLAGS_EXE) -c $< @@ -78,4 +85,5 @@ clean: $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) test: all + ./TestSuite.exe ./runtests.sh $(PLATFORM) "$(TEST_DLLS)" diff --git a/tests/TestSuite.c b/tests/TestSuite.c new file mode 100644 index 0000000..be3e519 --- /dev/null +++ b/tests/TestSuite.c @@ -0,0 +1,17 @@ +#define WIN32_LEAN_AND_MEAN +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include + +extern BOOL MemoryModuleTestsuite(); + +int main(int argc, char* argv[]) +{ + if (!MemoryModuleTestsuite()) { + return 1; + } + + return 0; +} From 6c2c3e2feee12d97af18f43f7a5dcaad9b5e69ea Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 00:08:53 +0200 Subject: [PATCH 09/35] Fix more potential conversion issues on 64bit. --- MemoryModule.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 60511d4..52c8637 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -74,7 +74,7 @@ typedef struct { typedef struct { LPVOID address; LPVOID alignedAddress; - DWORD size; + SIZE_T size; DWORD characteristics; BOOL last; } SECTIONFINALIZEDATA, *PSECTIONFINALIZEDATA; @@ -192,7 +192,7 @@ static int ProtectionFlags[2][2][2] = { }, }; -static DWORD +static SIZE_T GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { DWORD size = section->SizeOfRawData; if (size == 0) { @@ -202,7 +202,7 @@ GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { size = module->headers->OptionalHeader.SizeOfUninitializedData; } } - return size; + return (SIZE_T) size; } static BOOL @@ -271,7 +271,7 @@ FinalizeSections(PMEMORYMODULE module) for (i=1; iheaders->FileHeader.NumberOfSections; i++, section++) { LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); LPVOID alignedAddress = AlignAddressDown(sectionAddress, module->pageSize); - DWORD sectionSize = GetRealSectionSize(module, section); + SIZE_T sectionSize = GetRealSectionSize(module, section); // Combine access flags of all sections that share a page // TODO(fancycode): We currently share flags of a trailing large section // with the page of a first small section. This should be optimized. @@ -282,7 +282,7 @@ FinalizeSections(PMEMORYMODULE module) } else { sectionData.characteristics |= section->Characteristics; } - sectionData.size = (((uintptr_t)sectionAddress) + sectionSize) - (uintptr_t) sectionData.address; + sectionData.size = (((uintptr_t)sectionAddress) + ((uintptr_t) sectionSize)) - (uintptr_t) sectionData.address; continue; } @@ -868,7 +868,11 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); if (cmp == 0) { // Handle partial match - cmp = searchKeyLen - resourceString->Length; + if (searchKeyLen > resourceString->Length) { + cmp = 1; + } else if (searchKeyLen < resourceString->Length) { + cmp = -1; + } } if (cmp < 0) { end = (middle != end ? middle : middle-1); From 097403a8addca6553355484836c4aa7941c8f1c6 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 00:14:56 +0200 Subject: [PATCH 10/35] Added wrapper to run wine/wine64. --- tests/Makefile | 2 +- tests/runtests.sh | 10 +--------- tests/runwine.sh | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 10 deletions(-) create mode 100755 tests/runwine.sh diff --git a/tests/Makefile b/tests/Makefile index 9df5da5..626611f 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -85,5 +85,5 @@ clean: $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) test: all - ./TestSuite.exe + ./runwine.sh $(PLATFORM) TestSuite.exe ./runtests.sh $(PLATFORM) "$(TEST_DLLS)" diff --git a/tests/runtests.sh b/tests/runtests.sh index 57d70c6..a2c6520 100755 --- a/tests/runtests.sh +++ b/tests/runtests.sh @@ -1,13 +1,5 @@ #!/bin/bash PLATFORM=$1 -if [ "${PLATFORM}" = "x86_64" ]; then - export WINEPREFIX=${HOME}/.wine64/ - WINE=wine64 -else - export WINEPREFIX=${HOME}/.wine/ - WINE=wine -fi -export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.6/ read -a TEST_DLLS <<< $2 @@ -15,7 +7,7 @@ for filename in "${TEST_DLLS[@]}" do : echo "Testing $filename" - ${WINE} ./LoadDll.exe $filename + ./runwine.sh "${PLATFORM}" ./LoadDll.exe $filename if [ "$?" != "0" ]; then exit 1 fi diff --git a/tests/runwine.sh b/tests/runwine.sh new file mode 100755 index 0000000..eaee1fc --- /dev/null +++ b/tests/runwine.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -eu +PLATFORM=$1 +shift + +if [ "${PLATFORM}" = "x86_64" ]; then + export WINEPREFIX=${HOME}/.wine64/ + WINE=wine64 +else + export WINEPREFIX=${HOME}/.wine/ + WINE=wine +fi +export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.6/ + +exec ${WINE} $@ From caf917707b22c66ab27528d6cfba97815f6ac162 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 00:54:28 +0200 Subject: [PATCH 11/35] Replace defines with static consts. --- MemoryModule.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 52c8637..3711f8a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -257,7 +257,7 @@ FinalizeSections(PMEMORYMODULE module) #ifdef _WIN64 uintptr_t imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); #else - #define imageOffset 0 + static const uintptr_t imageOffset = 0; #endif SECTIONFINALIZEDATA sectionData; sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); @@ -298,9 +298,6 @@ FinalizeSections(PMEMORYMODULE module) if (!FinalizeSection(module, §ionData)) { return FALSE; } -#ifndef _WIN64 -#undef imageOffset -#endif return TRUE; } @@ -838,7 +835,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( #else // Resource names are always stored using 16bit characters, need to // convert string we search for. -#define MAX_LOCAL_KEY_LENGTH 2048 + static const size_t MAX_LOCAL_KEY_LENGTH = 2048; // In most cases resource names are short, so optimize for that by // using a pre-allocated array. wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH+1]; @@ -887,7 +884,6 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { free(_searchKey); } -#undef MAX_LOCAL_KEY_LENGTH #endif } From 4074f1e6abd4c519f4181692fc8d631999178a44 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:00:39 +0200 Subject: [PATCH 12/35] Simplify conditional compiled code a bit. --- MemoryModule.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 3711f8a..9162abb 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -96,10 +96,12 @@ AlignValueUp(size_t value, size_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } -#ifdef DEBUG_OUTPUT -static void +static inline void OutputLastError(const char *msg) { +#ifndef DEBUG_OUTPUT + UNREFERENCED_PARAMETER(msg); +#else LPVOID tmp; char *tmpmsg; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, @@ -109,8 +111,8 @@ OutputLastError(const char *msg) OutputDebugString(tmpmsg); LocalFree(tmpmsg); LocalFree(tmp); -} #endif +} static BOOL CheckSize(size_t size, size_t expected) { @@ -240,9 +242,7 @@ FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { // change memory access flags if (VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect) == 0) { -#ifdef DEBUG_OUTPUT - OutputLastError("Error protecting memory page") -#endif + OutputLastError("Error protecting memory page"); return FALSE; } @@ -341,16 +341,10 @@ PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) unsigned char *dest = codeBase + relocation->VirtualAddress; unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { - DWORD *patchAddrHL; -#ifdef _WIN64 - ULONGLONG *patchAddr64; -#endif - int type, offset; - // the upper 4 bits define the type of relocation - type = *relInfo >> 12; + int type = *relInfo >> 12; // the lower 12 bits define the offset - offset = *relInfo & 0xfff; + int offset = *relInfo & 0xfff; switch (type) { @@ -360,14 +354,18 @@ PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) case IMAGE_REL_BASED_HIGHLOW: // change complete 32 bit address - patchAddrHL = (DWORD *) (dest + offset); - *patchAddrHL += (DWORD) delta; + { + DWORD *patchAddrHL = (DWORD *) (dest + offset); + *patchAddrHL += (DWORD) delta; + } break; #ifdef _WIN64 case IMAGE_REL_BASED_DIR64: - patchAddr64 = (ULONGLONG *) (dest + offset); - *patchAddr64 += (ULONGLONG) delta; + { + ULONGLONG *patchAddr64 = (ULONGLONG *) (dest + offset); + *patchAddr64 += (ULONGLONG) delta; + } break; #endif @@ -528,10 +526,11 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } #ifdef _WIN64 - if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { + static const WORD HOST_MACHINE = IMAGE_FILE_MACHINE_AMD64; #else - if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { + static const WORD HOST_MACHINE = IMAGE_FILE_MACHINE_I386; #endif + if (old_header->FileHeader.Machine != HOST_MACHINE) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } From 49a82873f7d546bb0a08131f94c1fd5982ce8d1b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:03:54 +0200 Subject: [PATCH 13/35] Use "size_t" instead of "long" for sizes. --- example/DllLoader/DllLoader.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 973f5b4..9f0bfd9 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -46,8 +46,8 @@ void LoadFromFile(void) FreeLibrary(handle); } -void* ReadLibrary(long* pSize) { - long read; +void* ReadLibrary(size_t* pSize) { + size_t read; void* result; FILE* fp; @@ -59,8 +59,8 @@ void* ReadLibrary(long* pSize) { } fseek(fp, 0, SEEK_END); - *pSize = ftell(fp); - if (*pSize < 0) + *pSize = static_cast(ftell(fp)); + if (*pSize == 0) { fclose(fp); return NULL; @@ -75,7 +75,7 @@ void* ReadLibrary(long* pSize) { fseek(fp, 0, SEEK_SET); read = fread(result, 1, *pSize, fp); fclose(fp); - if (read != static_cast(*pSize)) + if (read != *pSize) { free(result); return NULL; @@ -87,7 +87,7 @@ void* ReadLibrary(long* pSize) { void LoadFromMemory(void) { void *data; - long size; + size_t size; HMEMORYMODULE handle; addNumberProc addNumber; HMEMORYRSRC resourceInfo; @@ -195,7 +195,7 @@ void InitFreeFunc(CallList* calls, CustomFreeFunc freeFunc) { calls->current_free_call = 0; } -void TestFailingAllocation(void *data, long size) { +void TestFailingAllocation(void *data, size_t size) { CallList expected_calls; HMEMORYMODULE handle; @@ -214,7 +214,7 @@ void TestFailingAllocation(void *data, long size) { assert(expected_calls.current_free_call == 0); } -void TestCleanupAfterFailingAllocation(void *data, long size) { +void TestCleanupAfterFailingAllocation(void *data, size_t size) { CallList expected_calls; HMEMORYMODULE handle; int free_calls_after_loading; @@ -238,7 +238,7 @@ void TestCleanupAfterFailingAllocation(void *data, long size) { assert(expected_calls.current_free_call == free_calls_after_loading); } -void TestFreeAfterDefaultAlloc(void *data, long size) { +void TestFreeAfterDefaultAlloc(void *data, size_t size) { CallList expected_calls; HMEMORYMODULE handle; int free_calls_after_loading; @@ -260,7 +260,7 @@ void TestFreeAfterDefaultAlloc(void *data, long size) { void TestCustomAllocAndFree(void) { void *data; - long size; + size_t size; data = ReadLibrary(&size); if (data == NULL) From e2826eb9565e764707a906814d4c4463f1f1b63c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:15:26 +0200 Subject: [PATCH 14/35] Fix MSVC compiler error. --- MemoryModule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 9162abb..4d72a5d 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -526,9 +526,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } #ifdef _WIN64 - static const WORD HOST_MACHINE = IMAGE_FILE_MACHINE_AMD64; + static const int HOST_MACHINE = IMAGE_FILE_MACHINE_AMD64; #else - static const WORD HOST_MACHINE = IMAGE_FILE_MACHINE_I386; + static const int HOST_MACHINE = IMAGE_FILE_MACHINE_I386; #endif if (old_header->FileHeader.Machine != HOST_MACHINE) { SetLastError(ERROR_BAD_EXE_FORMAT); From d9dcc0eb8c764f15bf5f8e0578d37577abf2102d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:17:12 +0200 Subject: [PATCH 15/35] Don't use "static const ", breaks on MSVC. --- MemoryModule.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 4d72a5d..a032d52 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -48,6 +48,12 @@ #define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION)) #endif +#ifdef _WIN64 +#define HOST_MACHINE IMAGE_FILE_MACHINE_AMD64 +#else +#define HOST_MACHINE IMAGE_FILE_MACHINE_I386 +#endif + #include "MemoryModule.h" typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); @@ -525,11 +531,6 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, return NULL; } -#ifdef _WIN64 - static const int HOST_MACHINE = IMAGE_FILE_MACHINE_AMD64; -#else - static const int HOST_MACHINE = IMAGE_FILE_MACHINE_I386; -#endif if (old_header->FileHeader.Machine != HOST_MACHINE) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; From 5ce3707c7d9d6f3dfcde8b848a96986ef2e6c5dd Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:23:24 +0200 Subject: [PATCH 16/35] MSVC again - "static const" can not be used as array size. --- MemoryModule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index a032d52..7e6c1a5 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -835,7 +835,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( #else // Resource names are always stored using 16bit characters, need to // convert string we search for. - static const size_t MAX_LOCAL_KEY_LENGTH = 2048; +#define MAX_LOCAL_KEY_LENGTH 2048 // In most cases resource names are short, so optimize for that by // using a pre-allocated array. wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH+1]; @@ -884,6 +884,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { free(_searchKey); } +#undef MAX_LOCAL_KEY_LENGTH #endif } From 8d609dc2a240a70450642112ee52e7012dfbea2b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:34:42 +0200 Subject: [PATCH 17/35] Use script to run wine. --- .travis.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index e9dcb84..f9ef247 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,14 @@ sudo: false env: - - PLATFORM=x86_64 WINE=wine64 UNICODE= CMAKE= - - PLATFORM=i686 WINE=wine UNICODE= CMAKE= - - PLATFORM=x86_64 WINE=wine64 UNICODE=1 CMAKE= - - PLATFORM=i686 WINE=wine UNICODE=1 CMAKE= - - PLATFORM=x86_64 WINE=wine64 UNICODE= CMAKE=1 - - PLATFORM=i686 WINE=wine UNICODE= CMAKE=1 - - PLATFORM=x86_64 WINE=wine64 UNICODE=1 CMAKE=1 - - PLATFORM=i686 WINE=wine UNICODE=1 CMAKE=1 + - PLATFORM=x86_64 UNICODE= CMAKE= + - PLATFORM=i686 UNICODE= CMAKE= + - PLATFORM=x86_64 UNICODE=1 CMAKE= + - PLATFORM=i686 UNICODE=1 CMAKE= + - PLATFORM=x86_64 UNICODE= CMAKE=1 + - PLATFORM=i686 UNICODE= CMAKE=1 + - PLATFORM=x86_64 UNICODE=1 CMAKE=1 + - PLATFORM=i686 UNICODE=1 CMAKE=1 language: cpp @@ -37,5 +37,5 @@ script: - if [ -z "$CMAKE" ]; then make test PLATFORM=$PLATFORM UNICODE=$UNICODE; fi - if [ ! -z "$CMAKE" ]; then cmake --build .; fi - cd example/DllLoader - - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe + - ../../tests/runwine.sh $PLATFORM ./DllLoader.exe + - ../../tests/runwine.sh $PLATFORM ./DllLoaderLoader.exe From 6c4ab3589d59ca389756f4ad7aca947d3566f4cb Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 22:18:42 +0200 Subject: [PATCH 18/35] Added testcase to load image above 32bit. --- example/DllLoader/DllLoader.cpp | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 9f0bfd9..4355ea8 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -257,6 +257,55 @@ void TestFreeAfterDefaultAlloc(void *data, size_t size) { assert(expected_calls.current_free_call == free_calls_after_loading + 1); } +#ifdef _WIN64 + +LPVOID MemoryAllocHigh(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect, void* userdata) +{ + int* counter = static_cast(userdata); + if (*counter == 0) { + // Make sure the image gets loaded to an address above 32bit. + uintptr_t offset = 0x10000000000; + address = (LPVOID) ((uintptr_t) address + offset); + } + (*counter)++; + return MemoryDefaultAlloc(address, size, allocationType, protect, NULL); +} + +void TestAllocHighMemory(void *data, size_t size) { + HMEMORYMODULE handle; + int counter = 0; + addNumberProc addNumber; + HMEMORYRSRC resourceInfo; + DWORD resourceSize; + LPVOID resourceData; + TCHAR buffer[100]; + + handle = MemoryLoadLibraryEx( + data, size, MemoryAllocHigh, MemoryDefaultFree, MemoryDefaultLoadLibrary, + MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, &counter); + + assert(handle != NULL); + + addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); + _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); + + resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + + MemoryLoadString(handle, 1, buffer, sizeof(buffer)); + _tprintf(_T("String1: %s\n"), buffer); + + MemoryLoadString(handle, 20, buffer, sizeof(buffer)); + _tprintf(_T("String2: %s\n"), buffer); + + MemoryFreeLibrary(handle); +} +#endif // _WIN64 + void TestCustomAllocAndFree(void) { void *data; @@ -274,6 +323,10 @@ void TestCustomAllocAndFree(void) TestCleanupAfterFailingAllocation(data, size); _tprintf(_T("Test custom free function after MemoryLoadLibraryEx\n")); TestFreeAfterDefaultAlloc(data, size); +#ifdef _WIN64 + _tprintf(_T("Test allocating in high memory\n")); + TestAllocHighMemory(data, size); +#endif free(data); } From f5c9db8b5c7dd23deb67c1ca4bc67f3d29d2a82b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 22:36:55 +0200 Subject: [PATCH 19/35] Simplfy some casting code, updated comments about 32/64 bit. --- MemoryModule.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 7e6c1a5..13a371f 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -102,6 +102,11 @@ AlignValueUp(size_t value, size_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } +static inline void* +OffsetPointer(void* data, ptrdiff_t offset) { + return (void*) ((uintptr_t) data + offset); +} + static inline void OutputLastError(const char *msg) { @@ -153,9 +158,11 @@ CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_heade } // Always use position from file to support alignments smaller - // than page size. + // than page size (allocation above will align to page size). dest = codeBase + section->VirtualAddress; - section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; + // NOTE: On 64bit systems we truncate to 32bit here but expand + // again later when "PhysicalAddress" is used. + section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff); memset(dest, 0, section_size); } @@ -178,10 +185,12 @@ CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_heade } // Always use position from file to support alignments smaller - // than page size. + // than page size (allocation above will align to page size). dest = codeBase + section->VirtualAddress; memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); - section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; + // NOTE: On 64bit systems we truncate to 32bit here but expand + // again later when "PhysicalAddress" is used. + section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff); } return TRUE; @@ -261,7 +270,9 @@ FinalizeSections(PMEMORYMODULE module) int i; PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); #ifdef _WIN64 - uintptr_t imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); + // "PhysicalAddress" might have been truncated to 32bit above, expand to + // 64bits again. + uintptr_t imageOffset = ((uintptr_t) module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); #else static const uintptr_t imageOffset = 0; #endif @@ -345,7 +356,7 @@ PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) for (; relocation->VirtualAddress > 0; ) { DWORD i; unsigned char *dest = codeBase + relocation->VirtualAddress; - unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); + unsigned short *relInfo = (unsigned short*) OffsetPointer(relocation, IMAGE_SIZEOF_BASE_RELOCATION); for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { // the upper 4 bits define the type of relocation int type = *relInfo >> 12; @@ -382,7 +393,7 @@ PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) } // advance to next relocation block - relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); + relocation = (PIMAGE_BASE_RELOCATION) OffsetPointer(relocation, relocation->SizeOfBlock); } return TRUE; } @@ -861,7 +872,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( int cmp; PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; - resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); + resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) OffsetPointer(root, entries[middle].Name & 0x7FFFFFFF); cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); if (cmp == 0) { // Handle partial match @@ -993,7 +1004,7 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO data = (PIMAGE_RESOURCE_DIR_STRING_U) MemoryLoadResource(module, resource); id = id & 0x0f; while (id--) { - data = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) data) + (data->Length + 1) * sizeof(WCHAR)); + data = (PIMAGE_RESOURCE_DIR_STRING_U) OffsetPointer(data, (data->Length + 1) * sizeof(WCHAR)); } if (data->Length == 0) { SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); From 184113ca0964709cfe6544e2d5f2b9a11c1832ce Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 22:58:17 +0200 Subject: [PATCH 20/35] Also build and run testsuite on cmake CI tests. --- .travis.yml | 4 +++- CMakeLists.txt | 9 +++++++++ MemoryModule.c | 6 +++--- scripts/run-appveyor.bat | 10 +++++++++- tests/CMakeLists.txt | 14 ++++++++++++++ tests/TestSuite.c | 2 ++ 6 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 tests/CMakeLists.txt diff --git a/.travis.yml b/.travis.yml index f9ef247..3c45d20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ addons: - wine before_script: - - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -D UNICODE=$UNICODE -H. -B.; fi + - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -DUNICODE=$UNICODE -DTESTSUITE=ON -H. -B.; fi script: - if [ -z "$CMAKE" ]; then make PLATFORM=$PLATFORM UNICODE=$UNICODE; fi @@ -39,3 +39,5 @@ script: - cd example/DllLoader - ../../tests/runwine.sh $PLATFORM ./DllLoader.exe - ../../tests/runwine.sh $PLATFORM ./DllLoaderLoader.exe + - cd ../../tests + - ./runwine.sh $PLATFORM ./TestSuite.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index e2a3676..e3ba63c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,11 +40,20 @@ else () message (STATUS "Compile without UNICODE support") endif () +option(TESTSUITE "Compile with TESTSUITE support" OFF) +if (TESTSUITE) + message (STATUS "Compile with TESTSUITE support") + add_definitions ("-DTESTSUITE") +else () + message (STATUS "Compile without TESTSUITE support") +endif () + add_library (MemoryModule STATIC MemoryModule.c MemoryModule.h) if (NOT MSVC) set_target_properties ("MemoryModule" PROPERTIES PREFIX "") endif () add_subdirectory (example) +add_subdirectory (tests) enable_language (RC) diff --git a/MemoryModule.c b/MemoryModule.c index 13a371f..cf38388 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -1028,7 +1028,6 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO #ifdef TESTSUITE #include -#include #ifndef PRIxPTR #ifdef _WIN64 @@ -1064,7 +1063,8 @@ static const uintptr_t AlignValueUpTests[][3] = { BOOL MemoryModuleTestsuite() { BOOL success = TRUE; - for (size_t idx = 0; AlignValueDownTests[idx][0]; ++idx) { + size_t idx; + for (idx = 0; AlignValueDownTests[idx][0]; ++idx) { const uintptr_t* tests = AlignValueDownTests[idx]; uintptr_t value = AlignValueDown(tests[0], tests[1]); if (value != tests[2]) { @@ -1073,7 +1073,7 @@ BOOL MemoryModuleTestsuite() { success = FALSE; } } - for (size_t idx = 0; AlignValueDownTests[idx][0]; ++idx) { + for (idx = 0; AlignValueDownTests[idx][0]; ++idx) { const uintptr_t* tests = AlignValueUpTests[idx]; uintptr_t value = AlignValueUp(tests[0], tests[1]); if (value != tests[2]) { diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat index 0bc2943..6662d99 100644 --- a/scripts/run-appveyor.bat +++ b/scripts/run-appveyor.bat @@ -13,7 +13,7 @@ if /I "%PLATFORM%" == "x64" ( echo. echo Preparing %CONFIGURATION% build environment for %GENERATOR%%CMAKE_GEN_SUFFIX% ... -cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DPLATFORM=%PLATFORM% -DUNICODE=%UNICODE% -H. -Bbuild +cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DPLATFORM=%PLATFORM% -DUNICODE=%UNICODE% -DTESTSUITE=ON -H. -Bbuild if %errorlevel% neq 0 exit /b %errorlevel% echo. @@ -26,6 +26,7 @@ echo Copying generated files ... copy /y build\example\DllLoader\%CONFIGURATION%\DllLoader.exe build\example\DllLoader\ > NUL copy /y build\example\DllLoader\%CONFIGURATION%\DllLoaderLoader.exe build\example\DllLoader\ > NUL copy /y build\example\SampleDLL\%CONFIGURATION%\SampleDLL.dll build\example\SampleDLL\ > NUL +copy /y build\tests\%CONFIGURATION%\TestSuite.exe build\tests\ > NUL cd build\example\DllLoader @@ -38,3 +39,10 @@ echo. echo Running DllLoaderLoader.exe ... DllLoaderLoader.exe if %errorlevel% neq 0 exit /b %errorlevel% + +cd ..\..\tests + +echo. +echo Running TestSuite.exe ... +TestSuite.exe +if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..8b1007f --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,14 @@ +set (sources_testsuite + TestSuite.c +) + +if (NOT MSVC) + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-static") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-static") +endif () + +add_executable (TestSuite ${sources_testsuite}) +target_link_libraries ("TestSuite" "MemoryModule") +if (NOT MSVC) + set_target_properties ("TestSuite" PROPERTIES SUFFIX ".exe") +endif () diff --git a/tests/TestSuite.c b/tests/TestSuite.c index be3e519..f4bd325 100644 --- a/tests/TestSuite.c +++ b/tests/TestSuite.c @@ -9,6 +9,8 @@ extern BOOL MemoryModuleTestsuite(); int main(int argc, char* argv[]) { + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); if (!MemoryModuleTestsuite()) { return 1; } From 2bbbc205d6758d47df81c2bd40ef252413b669ba Mon Sep 17 00:00:00 2001 From: Friedrich von Never Date: Sat, 15 Jul 2017 18:56:54 +0700 Subject: [PATCH 21/35] readme: fix the doc file name --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index aa9f497..4e9d82d 100644 --- a/readme.md +++ b/readme.md @@ -16,5 +16,5 @@ file gets deleted. `MemoryModule` is a library that can be used to load a DLL completely from memory - without storing on the disk first. -See `doc/readme.txt` for more informations about the format of a DLL file and +See `doc/readme.rst` for more informations about the format of a DLL file and a tutorial how they can be loaded directly. From 0884dccfa70ccbb857e44e250fb772931e479580 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 2 Nov 2017 20:15:22 +0100 Subject: [PATCH 22/35] Update mingw -dev package for Trusty. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3c45d20..737c970 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,8 @@ addons: - binutils-mingw-w64-i686 - binutils-mingw-w64-x86-64 - cmake - - mingw-w64-dev + - mingw-w64-i686-dev + - mingw-w64-x86-64-dev - g++-mingw-w64-i686 - g++-mingw-w64-x86-64 - gcc-mingw-w64-i686 From 98b95eca4cc467fedded96386bcadaba3addf18e Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 2 Nov 2017 21:02:26 +0100 Subject: [PATCH 23/35] Implement binary search for looking up exports by name. Code based on #74 which contained code from py2exe. --- MemoryModule.c | 73 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index cf38388..59a5844 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -22,6 +22,12 @@ * Portions created by Joachim Bauch are Copyright (C) 2004-2015 * Joachim Bauch. All Rights Reserved. * + * + * THeller: Added binary search in MemoryGetProcAddress function + * (#define USE_BINARY_SEARCH to enable it). This gives a very large + * speedup for libraries that exports lots of functions. + * + * These portions are Copyright (C) 2013 Thomas Heller. */ #include @@ -56,6 +62,11 @@ #include "MemoryModule.h" +struct ExportNameEntry { + LPCSTR name; + WORD idx; +}; + typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); typedef int (WINAPI *ExeEntryProc)(void); @@ -72,6 +83,7 @@ typedef struct { CustomLoadLibraryFunc loadLibrary; CustomGetProcAddressFunc getProcAddress; CustomFreeLibraryFunc freeLibrary; + struct ExportNameEntry *nameExportsTable; void *userdata; ExeEntryProc exeEntry; DWORD pageSize; @@ -688,12 +700,27 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, return NULL; } -FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) +static int _compare(const void *a, const void *b) +{ + const struct ExportNameEntry *p1 = (const struct ExportNameEntry*) a; + const struct ExportNameEntry *p2 = (const struct ExportNameEntry*) b; + return _stricmp(p1->name, p2->name); +} + +static int _find(const void *a, const void *b) +{ + LPCSTR *name = (LPCSTR *) a; + const struct ExportNameEntry *p = (const struct ExportNameEntry*) b; + return _stricmp(*name, p->name); +} + +FARPROC MemoryGetProcAddress(HMEMORYMODULE mod, LPCSTR name) { - unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; + PMEMORYMODULE module = (PMEMORYMODULE)mod; + unsigned char *codeBase = module->codeBase; DWORD idx = 0; PIMAGE_EXPORT_DIRECTORY exports; - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) { // no export table found SetLastError(ERROR_PROC_NOT_FOUND); @@ -715,25 +742,44 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) } idx = LOWORD(name) - exports->Base; + } else if (!exports->NumberOfNames) { + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; } else { - // search function name in list of exported names - DWORD i; - DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames); - WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); - BOOL found = FALSE; - for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { - if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { - idx = *ordinal; - found = TRUE; - break; + const struct ExportNameEntry *found; + + // Lazily build name table and sort it by names + if (!module->nameExportsTable) { + DWORD i; + DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames); + WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); + struct ExportNameEntry *entry = (struct ExportNameEntry*) malloc(exports->NumberOfNames * sizeof(struct ExportNameEntry)); + module->nameExportsTable = entry; + if (!entry) { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; } + for (i=0; iNumberOfNames; i++, nameRef++, ordinal++, entry++) { + entry->name = (const char *) (codeBase + (*nameRef)); + entry->idx = *ordinal; + } + qsort(module->nameExportsTable, + exports->NumberOfNames, + sizeof(struct ExportNameEntry), _compare); } + // search function name in list of exported names with binary search + found = (const struct ExportNameEntry*) bsearch(&name, + module->nameExportsTable, + exports->NumberOfNames, + sizeof(struct ExportNameEntry), _find); if (!found) { // exported symbol not found SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } + + idx = found->idx; } if (idx > exports->NumberOfFunctions) { @@ -759,6 +805,7 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); } + free(module->nameExportsTable); if (module->modules != NULL) { // free previously opened libraries int i; From ac78ea10e7ba666ae24b753a1564c8c93ccff4bd Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 2 Nov 2017 21:37:14 +0100 Subject: [PATCH 24/35] Add test that loads a dll with lots of exports. --- .gitignore | 3 ++ tests/LoadDll.cpp | 75 +++++++++++++++++++++++++++++++++++++-- tests/Makefile | 7 ++++ tests/generate-exports.sh | 52 +++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100755 tests/generate-exports.sh diff --git a/.gitignore b/.gitignore index 6c07d24..508c3dc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ *.exe tests/*.dll tests/*.res + +tests/SampleExports.cpp +tests/SampleExports.h diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 07a2538..8cb215b 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -11,6 +11,7 @@ #include "../MemoryModule.h" +typedef int (*addProc)(int); typedef int (*addNumberProc)(int, int); // Thanks to Tim Cooper (from http://stackoverflow.com/a/8584708) @@ -127,6 +128,11 @@ BOOL LoadFromMemory(char *filename) } addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); + if (!addNumber) { + _tprintf(_T("MemoryGetProcAddress(\"addNumber\") returned NULL\n")); + result = FALSE; + goto exit; + } _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); // the DLL only exports one function, try to load by ordinal value @@ -218,6 +224,65 @@ BOOL LoadFromMemory(char *filename) return result; } +BOOL LoadExportsFromMemory(char *filename) +{ + FILE *fp; + unsigned char *data=NULL; + long size; + size_t read; + HMEMORYMODULE handle = NULL; + int i; + BOOL result = TRUE; + + fp = fopen(filename, "rb"); + if (fp == NULL) + { + printf("Can't open DLL file \"%s\".", filename); + result = FALSE; + goto exit; + } + + fseek(fp, 0, SEEK_END); + size = ftell(fp); + assert(size > 0); + data = (unsigned char *)malloc(size); + assert(data != NULL); + fseek(fp, 0, SEEK_SET); + read = fread(data, 1, size, fp); + assert(read == static_cast(size)); + fclose(fp); + + handle = MemoryLoadLibrary(data, size); + if (handle == NULL) + { + _tprintf(_T("Can't load library from memory.\n")); + result = FALSE; + goto exit; + } + + for (i = 1; i <= 100; i++) { + char name[100]; + sprintf(name, "add%d", i); + addProc addNumber = (addProc)MemoryGetProcAddress(handle, name); + if (!addNumber) { + _tprintf(_T("MemoryGetProcAddress(\"%s\") returned NULL\n"), name); + result = FALSE; + goto exit; + } + int result = addNumber(1); + if (result != 1 + i) { + _tprintf(_T("(\"%s\") returned %d, expected %d\n"), name, result, 1 + i); + result = FALSE; + goto exit; + } + _tprintf(_T("%s: %d\n"), name, result); + } +exit: + MemoryFreeLibrary(handle); + free(data); + return result; +} + int main(int argc, char* argv[]) { if (argc < 2) { @@ -225,8 +290,14 @@ int main(int argc, char* argv[]) return 1; } - if (!LoadFromMemory(argv[1])) { - return 2; + if (!strstr((const char *) argv[1], "exports")) { + if (!LoadFromMemory(argv[1])) { + return 2; + } + } else { + if (!LoadExportsFromMemory(argv[1])) { + return 2; + } } return 0; diff --git a/tests/Makefile b/tests/Makefile index 626611f..014cc80 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -47,6 +47,7 @@ TEST_DLLS = \ test-align-800.dll \ test-align-900.dll \ test-relocate.dll \ + test-exports.dll LOADDLL_OBJ = LoadDll.o ../MemoryModule.o TESTSUITE_OBJ = TestSuite.o ../MemoryModule.o @@ -72,6 +73,12 @@ test-align-%.dll: $(DLL_OBJ) test-relocate.dll: $(DLL_OBJ) $(CXX) $(LDFLAGS_DLL) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o $@ $(DLL_OBJ) +test-exports.dll: SampleExports.o + $(CXX) $(LDFLAGS_DLL) $(LDFLAGS) -o $@ SampleExports.o + +SampleExports.cpp: generate-exports.sh + ./generate-exports.sh + %.o: %.cpp $(CXX) $(CFLAGS) $(CFLAGS_DLL) -c $< diff --git a/tests/generate-exports.sh b/tests/generate-exports.sh new file mode 100755 index 0000000..974b2a6 --- /dev/null +++ b/tests/generate-exports.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +## +## Generate header file. +## + +cat > SampleExports.h << EOF +extern "C" { + +#ifdef SAMPLEDLL_EXPORTS +#define SAMPLEDLL_API __declspec(dllexport) +#else +#define SAMPLEDLL_API __declspec(dllimport) +#endif + +EOF + +for i in `seq 1 100`; +do +cat >> SampleExports.h << EOF +SAMPLEDLL_API int add$i(int a); +EOF +done + +cat >> SampleExports.h << EOF +} +EOF + + +## +## Generate source file. +## + +cat > SampleExports.cpp << EOF +#include "SampleExports.h" + +extern "C" { +EOF + +for i in `seq 1 100 | sort -R`; +do +cat >> SampleExports.cpp << EOF +SAMPLEDLL_API int add$i(int a) +{ + return a + $i; +} +EOF +done + +cat >> SampleExports.cpp << EOF +} +EOF From 9e295953a8b056036525c4274fb1ddf91dbb85c7 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 20:31:28 +0100 Subject: [PATCH 25/35] Prevent memory of library from spanning over 4GB bounaries. Based on code from #67 / #79, fixes #63. --- MemoryModule.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 59a5844..05646e1 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -70,6 +70,13 @@ struct ExportNameEntry { typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); typedef int (WINAPI *ExeEntryProc)(void); +#ifdef _WIN64 +typedef struct POINTER_LIST { + struct POINTER_LIST *next; + void *address; +} POINTER_LIST; +#endif + typedef struct { PIMAGE_NT_HEADERS headers; unsigned char *codeBase; @@ -87,6 +94,9 @@ typedef struct { void *userdata; ExeEntryProc exeEntry; DWORD pageSize; +#ifdef _WIN64 + POINTER_LIST *blockedMemory; +#endif } MEMORYMODULE, *PMEMORYMODULE; typedef struct { @@ -137,6 +147,21 @@ OutputLastError(const char *msg) #endif } +#ifdef _WIN64 +static void +FreePointerList(POINTER_LIST *head, CustomFreeFunc freeMemory, void *userdata) +{ + POINTER_LIST *node = head; + while (node) { + POINTER_LIST *next; + freeMemory(node->address, 0, MEM_RELEASE, userdata); + next = node->next; + free(node); + node = next; + } +} +#endif + static BOOL CheckSize(size_t size, size_t expected) { if (size < expected) { @@ -535,6 +560,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, size_t optionalSectionSize; size_t lastSectionEnd = 0; size_t alignedImageSize; +#ifdef _WIN64 + POINTER_LIST *blockedMemory = NULL; +#endif if (!CheckSize(size, sizeof(IMAGE_DOS_HEADER))) { return NULL; @@ -610,9 +638,40 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } } +#ifdef _WIN64 + // Memory block may not span 4 GB boundaries. + while ((((uintptr_t) code) >> 32) < (((uintptr_t) (code + alignedImageSize)) >> 32)) { + POINTER_LIST *node = (POINTER_LIST*) malloc(sizeof(POINTER_LIST)); + if (!node) { + freeMemory(code, 0, MEM_RELEASE, userdata); + FreePointerList(blockedMemory, freeMemory, userdata); + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + + node->next = blockedMemory; + node->address = code; + blockedMemory = node; + + code = (unsigned char *)allocMemory(NULL, + alignedImageSize, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE, + userdata); + if (code == NULL) { + FreePointerList(blockedMemory, freeMemory, userdata); + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + } +#endif + result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); if (result == NULL) { freeMemory(code, 0, MEM_RELEASE, userdata); +#ifdef _WIN64 + FreePointerList(blockedMemory, freeMemory, userdata); +#endif SetLastError(ERROR_OUTOFMEMORY); return NULL; } @@ -626,6 +685,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, result->freeLibrary = freeLibrary; result->userdata = userdata; result->pageSize = sysInfo.dwPageSize; +#ifdef _WIN64 + result->blockedMemory = blockedMemory; +#endif if (!CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) { goto error; @@ -823,6 +885,9 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) module->free(module->codeBase, 0, MEM_RELEASE, module->userdata); } +#ifdef _WIN64 + FreePointerList(module->blockedMemory, module->free, module->userdata); +#endif HeapFree(GetProcessHeap(), 0, module); } From 9ecfeb025d9d13160038518df7dc69973fb6ee0f Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 20:41:25 +0100 Subject: [PATCH 26/35] Remove all object files on clean. --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 014cc80..028bcad 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -89,7 +89,7 @@ SampleExports.cpp: generate-exports.sh $(RC) $(RCFLAGS) -o $*.res $< clean: - $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) + $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) $(TESTSUITE_OBJ) SampleExports.o test: all ./runwine.sh $(PLATFORM) TestSuite.exe From 663ddca84b9ef35ca6fd1e705599f30d8d1cda32 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 20:49:55 +0100 Subject: [PATCH 27/35] Update WINEPATH for Trusty. --- tests/runwine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runwine.sh b/tests/runwine.sh index eaee1fc..c56fa27 100755 --- a/tests/runwine.sh +++ b/tests/runwine.sh @@ -10,6 +10,6 @@ else export WINEPREFIX=${HOME}/.wine/ WINE=wine fi -export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.6/ +export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.8/;/usr/${PLATFORM}-w64-mingw32/lib exec ${WINE} $@ From 0acf4e7785d547ac37ddbf339aa00cb4f7a2b07d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 20:52:52 +0100 Subject: [PATCH 28/35] Fix typo. --- tests/runwine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runwine.sh b/tests/runwine.sh index c56fa27..826b8c3 100755 --- a/tests/runwine.sh +++ b/tests/runwine.sh @@ -10,6 +10,6 @@ else export WINEPREFIX=${HOME}/.wine/ WINE=wine fi -export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.8/;/usr/${PLATFORM}-w64-mingw32/lib +export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.8/:/usr/${PLATFORM}-w64-mingw32/lib exec ${WINE} $@ From e7d53b53e0e9111cb1910940a98df375c25e655c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 21:48:58 +0100 Subject: [PATCH 29/35] Only install packages necessary for job. --- .travis.yml | 100 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 77 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 737c970..0ea5624 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,82 @@ sudo: false -env: - - PLATFORM=x86_64 UNICODE= CMAKE= - - PLATFORM=i686 UNICODE= CMAKE= - - PLATFORM=x86_64 UNICODE=1 CMAKE= - - PLATFORM=i686 UNICODE=1 CMAKE= - - PLATFORM=x86_64 UNICODE= CMAKE=1 - - PLATFORM=i686 UNICODE= CMAKE=1 - - PLATFORM=x86_64 UNICODE=1 CMAKE=1 - - PLATFORM=i686 UNICODE=1 CMAKE=1 +matrix: + include: + - env: PLATFORM=x86_64 UNICODE= CMAKE= + addons: + apt: + packages: + - binutils-mingw-w64-x86-64 + - mingw-w64-x86-64-dev + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - wine:amd64 + - env: PLATFORM=i686 UNICODE= CMAKE= + addons: + apt: + packages: + - binutils-mingw-w64-i686 + - mingw-w64-i686-dev + - g++-mingw-w64-i686 + - gcc-mingw-w64-i686 + - wine:i386 + - env: PLATFORM=x86_64 UNICODE=1 CMAKE= + addons: + apt: + packages: + - binutils-mingw-w64-x86-64 + - mingw-w64-x86-64-dev + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - wine:amd64 + - env: PLATFORM=i686 UNICODE=1 CMAKE= + addons: + apt: + packages: + - binutils-mingw-w64-i686 + - mingw-w64-i686-dev + - g++-mingw-w64-i686 + - gcc-mingw-w64-i686 + - wine:i386 + - env: PLATFORM=x86_64 UNICODE= CMAKE=1 + addons: + apt: + packages: + - binutils-mingw-w64-x86-64 + - mingw-w64-x86-64-dev + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - wine:amd64 + - env: PLATFORM=i686 UNICODE= CMAKE=1 + addons: + apt: + packages: + - binutils-mingw-w64-i686 + - cmake + - mingw-w64-i686-dev + - g++-mingw-w64-i686 + - gcc-mingw-w64-i686 + - wine:i386 + - env: PLATFORM=x86_64 UNICODE=1 CMAKE=1 + addons: + apt: + packages: + - binutils-mingw-w64-x86-64 + - cmake + - mingw-w64-x86-64-dev + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - wine:amd64 + - env: PLATFORM=i686 UNICODE=1 CMAKE=1 + addons: + apt: + packages: + - binutils-mingw-w64-i686 + - cmake + - mingw-w64-i686-dev + - g++-mingw-w64-i686 + - gcc-mingw-w64-i686 + - wine:i386 language: cpp @@ -16,20 +84,6 @@ cache: - apt - ccache -addons: - apt: - packages: - - binutils-mingw-w64-i686 - - binutils-mingw-w64-x86-64 - - cmake - - mingw-w64-i686-dev - - mingw-w64-x86-64-dev - - g++-mingw-w64-i686 - - g++-mingw-w64-x86-64 - - gcc-mingw-w64-i686 - - gcc-mingw-w64-x86-64 - - wine - before_script: - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -DUNICODE=$UNICODE -DTESTSUITE=ON -H. -B.; fi From 403a31e7bbc28967334c081311fa6779588cd033 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 21:54:42 +0100 Subject: [PATCH 30/35] Run with sudo enabled. This fixes an issue where running wine fails on i386 with /usr/bin/wine: error while loading shared libraries: libwine.so.1: cannot create shared object descriptor: Operation not permitted --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0ea5624..93c6273 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -sudo: false +sudo: true matrix: include: From 060f0bd73608e4233a881ca566dd538ecba78bc1 Mon Sep 17 00:00:00 2001 From: Scavanger Date: Thu, 8 Mar 2018 13:23:39 +0100 Subject: [PATCH 31/35] Search for function names should be case sensitive --- MemoryModule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 05646e1..9f95a70 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -766,14 +766,14 @@ static int _compare(const void *a, const void *b) { const struct ExportNameEntry *p1 = (const struct ExportNameEntry*) a; const struct ExportNameEntry *p2 = (const struct ExportNameEntry*) b; - return _stricmp(p1->name, p2->name); + return strcmp(p1->name, p2->name); } static int _find(const void *a, const void *b) { LPCSTR *name = (LPCSTR *) a; const struct ExportNameEntry *p = (const struct ExportNameEntry*) b; - return _stricmp(*name, p->name); + return strcmp(*name, p->name); } FARPROC MemoryGetProcAddress(HMEMORYMODULE mod, LPCSTR name) From a15e0769b01f59a0f5f33ab411bc3db6e59864a1 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Fri, 18 May 2018 00:37:57 -0600 Subject: [PATCH 32/35] Make .h file accessible to superprojects As is, you need to add_subdirectory and also add the include, this kills two birds with one stone --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e3ba63c..cfddbfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ else () endif () add_library (MemoryModule STATIC MemoryModule.c MemoryModule.h) +target_include_directories(MemoryModule PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") if (NOT MSVC) set_target_properties ("MemoryModule" PROPERTIES PREFIX "") endif () From d1a08247332aa24dec8491df77fb5ca2efd6530a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 24 Feb 2019 13:49:51 +0100 Subject: [PATCH 33/35] Fix version for AppVeyor. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 4282d88..5bc1608 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ # Status available at # https://ci.appveyor.com/project/fancycode/memorymodule -version: #{build} +version: 1.0.{build} os: - Visual Studio 2015 From 9f379524076322f7875175f251b38e9c4083600a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 24 Feb 2019 15:07:24 +0100 Subject: [PATCH 34/35] Switch to Xenial for CI runs. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 93c6273..2a0f624 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,6 +80,8 @@ matrix: language: cpp +dist: xenial + cache: - apt - ccache From 316aa59c48cd6ab1c10b8a1a99bc1e7aa6f719f4 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 24 Feb 2019 15:17:41 +0100 Subject: [PATCH 35/35] Get latest stable version of Wine when testing. --- .travis.yml | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2a0f624..0bb4efe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ sudo: true matrix: include: - - env: PLATFORM=x86_64 UNICODE= CMAKE= + - env: PLATFORM=x86_64 UNICODE= CMAKE= WINE_PACKAGE=winehq-stable:amd64 addons: apt: packages: @@ -10,8 +10,7 @@ matrix: - mingw-w64-x86-64-dev - g++-mingw-w64-x86-64 - gcc-mingw-w64-x86-64 - - wine:amd64 - - env: PLATFORM=i686 UNICODE= CMAKE= + - env: PLATFORM=i686 UNICODE= CMAKE= WINE_PACKAGE=winehq-stable:i386 addons: apt: packages: @@ -19,8 +18,7 @@ matrix: - mingw-w64-i686-dev - g++-mingw-w64-i686 - gcc-mingw-w64-i686 - - wine:i386 - - env: PLATFORM=x86_64 UNICODE=1 CMAKE= + - env: PLATFORM=x86_64 UNICODE=1 CMAKE= WINE_PACKAGE=winehq-stable:amd64 addons: apt: packages: @@ -28,8 +26,7 @@ matrix: - mingw-w64-x86-64-dev - g++-mingw-w64-x86-64 - gcc-mingw-w64-x86-64 - - wine:amd64 - - env: PLATFORM=i686 UNICODE=1 CMAKE= + - env: PLATFORM=i686 UNICODE=1 CMAKE= WINE_PACKAGE=winehq-stable:i386 addons: apt: packages: @@ -37,8 +34,7 @@ matrix: - mingw-w64-i686-dev - g++-mingw-w64-i686 - gcc-mingw-w64-i686 - - wine:i386 - - env: PLATFORM=x86_64 UNICODE= CMAKE=1 + - env: PLATFORM=x86_64 UNICODE= CMAKE=1 WINE_PACKAGE=winehq-stable:amd64 addons: apt: packages: @@ -46,8 +42,7 @@ matrix: - mingw-w64-x86-64-dev - g++-mingw-w64-x86-64 - gcc-mingw-w64-x86-64 - - wine:amd64 - - env: PLATFORM=i686 UNICODE= CMAKE=1 + - env: PLATFORM=i686 UNICODE= CMAKE=1 WINE_PACKAGE=winehq-stable:i386 addons: apt: packages: @@ -56,8 +51,7 @@ matrix: - mingw-w64-i686-dev - g++-mingw-w64-i686 - gcc-mingw-w64-i686 - - wine:i386 - - env: PLATFORM=x86_64 UNICODE=1 CMAKE=1 + - env: PLATFORM=x86_64 UNICODE=1 CMAKE=1 WINE_PACKAGE=winehq-stable:amd64 addons: apt: packages: @@ -66,8 +60,7 @@ matrix: - mingw-w64-x86-64-dev - g++-mingw-w64-x86-64 - gcc-mingw-w64-x86-64 - - wine:amd64 - - env: PLATFORM=i686 UNICODE=1 CMAKE=1 + - env: PLATFORM=i686 UNICODE=1 CMAKE=1 WINE_PACKAGE=winehq-stable:i386 addons: apt: packages: @@ -76,7 +69,6 @@ matrix: - mingw-w64-i686-dev - g++-mingw-w64-i686 - gcc-mingw-w64-i686 - - wine:i386 language: cpp @@ -87,6 +79,9 @@ cache: - ccache before_script: + - curl https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add - + - echo "deb https://dl.winehq.org/wine-builds/ubuntu/ xenial main" | sudo tee /etc/apt/sources.list.d/winehq.list + - sudo apt-get -y update && sudo apt-get -y install --install-recommends $WINE_PACKAGE - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -DUNICODE=$UNICODE -DTESTSUITE=ON -H. -B.; fi script: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy