engine: library: fix saves on 64-bit Windows, compile custom loader only on x86

This commit is contained in:
Alibek Omarov 2021-06-27 00:03:39 +03:00
parent 21174dc9cf
commit a0af256641
2 changed files with 43 additions and 160 deletions

View File

@ -31,7 +31,7 @@ typedef struct dll_user_s
dword *funcs; dword *funcs;
char *names[MAX_LIBRARY_EXPORTS]; // max 4096 exports supported char *names[MAX_LIBRARY_EXPORTS]; // max 4096 exports supported
int num_ordinals; // actual exports count int num_ordinals; // actual exports count
dword funcBase; // base offset uintptr_t funcBase; // base offset
} dll_user_t; } dll_user_t;
dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath ); dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath );

View File

@ -16,7 +16,11 @@ GNU General Public License for more details.
#if XASH_LIB == LIB_WIN32 #if XASH_LIB == LIB_WIN32
#include "common.h" #include "common.h"
#include "library.h" #include "library.h"
#include <winnt.h>
#define CALCULATE_ADDRESS( base, offset ) ( ( DWORD )( base ) + ( DWORD )( offset ) )
#if XASH_X86
/* /*
--------------------------------------------------------------- ---------------------------------------------------------------
@ -25,106 +29,11 @@ GNU General Public License for more details.
--------------------------------------------------------------- ---------------------------------------------------------------
*/ */
#define DOS_SIGNATURE 0x5A4D // MZ
#define NT_SIGNATURE 0x00004550 // PE00
#define NUMBER_OF_DIRECTORY_ENTRIES 16 #define NUMBER_OF_DIRECTORY_ENTRIES 16
#ifndef IMAGE_SIZEOF_BASE_RELOCATION #ifndef IMAGE_SIZEOF_BASE_RELOCATION
#define IMAGE_SIZEOF_BASE_RELOCATION ( sizeof( IMAGE_BASE_RELOCATION )) #define IMAGE_SIZEOF_BASE_RELOCATION ( sizeof( IMAGE_BASE_RELOCATION ))
#endif #endif
typedef struct
{
// dos .exe header
word e_magic; // magic number
word e_cblp; // bytes on last page of file
word e_cp; // pages in file
word e_crlc; // relocations
word e_cparhdr; // size of header in paragraphs
word e_minalloc; // minimum extra paragraphs needed
word e_maxalloc; // maximum extra paragraphs needed
word e_ss; // initial (relative) SS value
word e_sp; // initial SP value
word e_csum; // checksum
word e_ip; // initial IP value
word e_cs; // initial (relative) CS value
word e_lfarlc; // file address of relocation table
word e_ovno; // overlay number
word e_res[4]; // reserved words
word e_oemid; // OEM identifier (for e_oeminfo)
word e_oeminfo; // OEM information; e_oemid specific
word e_res2[10]; // reserved words
long e_lfanew; // file address of new exe header
} DOS_HEADER;
typedef struct
{
// win .exe header
word Machine;
word NumberOfSections;
dword TimeDateStamp;
dword PointerToSymbolTable;
dword NumberOfSymbols;
word SizeOfOptionalHeader;
word Characteristics;
} PE_HEADER;
typedef struct
{
dword VirtualAddress;
dword Size;
} DATA_DIRECTORY;
typedef struct
{
word Magic;
byte MajorLinkerVersion;
byte MinorLinkerVersion;
dword SizeOfCode;
dword SizeOfInitializedData;
dword SizeOfUninitializedData;
dword AddressOfEntryPoint;
dword BaseOfCode;
dword BaseOfData;
dword ImageBase;
dword SectionAlignment;
dword FileAlignment;
word MajorOperatingSystemVersion;
word MinorOperatingSystemVersion;
word MajorImageVersion;
word MinorImageVersion;
word MajorSubsystemVersion;
word MinorSubsystemVersion;
dword Win32VersionValue;
dword SizeOfImage;
dword SizeOfHeaders;
dword CheckSum;
word Subsystem;
word DllCharacteristics;
dword SizeOfStackReserve;
dword SizeOfStackCommit;
dword SizeOfHeapReserve;
dword SizeOfHeapCommit;
dword LoaderFlags;
dword NumberOfRvaAndSizes;
DATA_DIRECTORY DataDirectory[NUMBER_OF_DIRECTORY_ENTRIES];
} OPTIONAL_HEADER;
typedef struct
{
dword Characteristics;
dword TimeDateStamp;
word MajorVersion;
word MinorVersion;
dword Name;
dword Base;
dword NumberOfFunctions;
dword NumberOfNames;
dword AddressOfFunctions; // RVA from base of image
dword AddressOfNames; // RVA from base of image
dword AddressOfNameOrdinals; // RVA from base of image
} EXPORT_DIRECTORY;
typedef struct typedef struct
{ {
PIMAGE_NT_HEADERS headers; PIMAGE_NT_HEADERS headers;
@ -134,26 +43,6 @@ typedef struct
int initialized; int initialized;
} MEMORYMODULE, *PMEMORYMODULE; } MEMORYMODULE, *PMEMORYMODULE;
typedef struct
{
byte Name[8]; // dos name length
union
{
dword PhysicalAddress;
dword VirtualSize;
} Misc;
dword VirtualAddress;
dword SizeOfRawData;
dword PointerToRawData;
dword PointerToRelocations;
dword PointerToLinenumbers;
word NumberOfRelocations;
word NumberOfLinenumbers;
dword Characteristics;
} SECTION_HEADER;
// Protection flags for memory pages (Executable, Readable, Writeable) // Protection flags for memory pages (Executable, Readable, Writeable)
static int ProtectionFlags[2][2][2] = static int ProtectionFlags[2][2][2] =
{ {
@ -170,7 +59,6 @@ static int ProtectionFlags[2][2][2] =
typedef BOOL (WINAPI *DllEntryProc)( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ); typedef BOOL (WINAPI *DllEntryProc)( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved );
#define GET_HEADER_DICTIONARY( module, idx ) &(module)->headers->OptionalHeader.DataDirectory[idx] #define GET_HEADER_DICTIONARY( module, idx ) &(module)->headers->OptionalHeader.DataDirectory[idx]
#define CALCULATE_ADDRESS( base, offset ) ((DWORD)(base) + (DWORD)(offset))
static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module ) static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
{ {
@ -598,6 +486,7 @@ library_error:
return NULL; return NULL;
} }
#endif
static DWORD GetOffsetByRVA( DWORD rva, PIMAGE_NT_HEADERS nt_header ) static DWORD GetOffsetByRVA( DWORD rva, PIMAGE_NT_HEADERS nt_header )
{ {
@ -653,41 +542,18 @@ static void FreeNameFuncGlobals( dll_user_t *hInst )
hInst->funcs = NULL; hInst->funcs = NULL;
} }
char *GetMSVCName( const char *in_name )
{
static string out_name;
char *pos;
if( in_name[0] == '?' ) // is this a MSVC C++ mangled name?
{
if(( pos = Q_strstr( in_name, "@@" )) != NULL )
{
int len = pos - in_name;
// strip off the leading '?'
Q_strncpy( out_name, in_name + 1, sizeof( out_name ));
out_name[len-1] = 0; // terminate string at the "@@"
return out_name;
}
}
Q_strncpy( out_name, in_name, sizeof( out_name ));
return out_name;
}
qboolean LibraryLoadSymbols( dll_user_t *hInst ) qboolean LibraryLoadSymbols( dll_user_t *hInst )
{ {
file_t *f; file_t *f;
string errorstring; string errorstring;
DOS_HEADER dos_header; IMAGE_DOS_HEADER dos_header;
LONG nt_signature; LONG nt_signature;
PE_HEADER pe_header; IMAGE_FILE_HEADER pe_header;
SECTION_HEADER section_header; IMAGE_SECTION_HEADER section_header;
qboolean rdata_found; qboolean rdata_found;
OPTIONAL_HEADER optional_header; IMAGE_OPTIONAL_HEADER optional_header;
long rdata_delta = 0; long rdata_delta = 0;
EXPORT_DIRECTORY export_directory; IMAGE_EXPORT_DIRECTORY export_directory;
long name_offset; long name_offset;
long exports_offset; long exports_offset;
long ordinal_offset; long ordinal_offset;
@ -715,7 +581,7 @@ qboolean LibraryLoadSymbols( dll_user_t *hInst )
goto table_error; goto table_error;
} }
if( dos_header.e_magic != DOS_SIGNATURE ) if( dos_header.e_magic != IMAGE_DOS_SIGNATURE )
{ {
Q_sprintf( errorstring, "%s does not have a valid dll signature", hInst->shortPath ); Q_sprintf( errorstring, "%s does not have a valid dll signature", hInst->shortPath );
goto table_error; goto table_error;
@ -733,7 +599,7 @@ qboolean LibraryLoadSymbols( dll_user_t *hInst )
goto table_error; goto table_error;
} }
if( nt_signature != NT_SIGNATURE ) if( nt_signature != IMAGE_NT_SIGNATURE )
{ {
Q_sprintf( errorstring, "%s does not have a valid NT signature", hInst->shortPath ); Q_sprintf( errorstring, "%s does not have a valid NT signature", hInst->shortPath );
goto table_error; goto table_error;
@ -860,7 +726,7 @@ qboolean LibraryLoadSymbols( dll_user_t *hInst )
if( FS_Seek( f, name_offset, SEEK_SET ) != -1 ) if( FS_Seek( f, name_offset, SEEK_SET ) != -1 )
{ {
FsGetString( f, function_name ); FsGetString( f, function_name );
hInst->names[i] = copystring( GetMSVCName( function_name )); hInst->names[i] = copystring( COM_GetMSVCName( function_name ));
} }
else break; else break;
} }
@ -880,8 +746,8 @@ qboolean LibraryLoadSymbols( dll_user_t *hInst )
void *fn_offset; void *fn_offset;
index = hInst->ordinals[i]; index = hInst->ordinals[i];
fn_offset = (void *)COM_GetProcAddress( hInst, "GiveFnptrsToDll" ); fn_offset = COM_GetProcAddress( hInst, "GiveFnptrsToDll" );
hInst->funcBase = (dword)(fn_offset) - hInst->funcs[index]; hInst->funcBase = (uintptr_t)(fn_offset) - hInst->funcs[index];
break; break;
} }
} }
@ -938,7 +804,7 @@ qboolean COM_CheckLibraryDirectDependency( const char *name, const char *depname
importDir = &peHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; importDir = &peHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if( importDir->Size <= 0 ) if( importDir->Size <= 0 )
{ {
Q_snprintf( errorstring, sizeof( errorstring ), "%s has no dependencies. Is this library valid?\n", name ); Con_Printf( S_WARN "%s: %s has no dependencies. Is this library valid?\n", __FUNCTION__, name );
goto libraryerror; goto libraryerror;
} }
@ -956,7 +822,10 @@ qboolean COM_CheckLibraryDirectDependency( const char *name, const char *depname
} }
libraryerror: libraryerror:
if( errorstring[0] ) Con_Printf( errorstring ); if( errorstring[0] )
{
Con_Printf( S_ERROR "%s: %s\n", __FUNCTION__, errorstring );
}
if( data ) Mem_Free( data ); // release memory if( data ) Mem_Free( data ); // release memory
return false; return false;
} }
@ -975,17 +844,22 @@ void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean d
hInst = FS_FindLibrary( dllname, directpath ); hInst = FS_FindLibrary( dllname, directpath );
if( !hInst ) return NULL; // nothing to load if( !hInst ) return NULL; // nothing to load
if( hInst->encrypted )
{
Con_Printf( S_ERROR "LoadLibrary: couldn't load encrypted library %s\n", dllname );
return NULL;
}
#if XASH_X86
if( hInst->custom_loader ) if( hInst->custom_loader )
{ {
if( hInst->encrypted )
{
Con_Printf( S_ERROR "LoadLibrary: couldn't load encrypted library %s\n", dllname );
return NULL;
}
hInst->hInstance = MemoryLoadLibrary( hInst->fullPath ); hInst->hInstance = MemoryLoadLibrary( hInst->fullPath );
} }
else hInst->hInstance = LoadLibrary( hInst->fullPath ); else
#endif
{
hInst->hInstance = LoadLibrary( hInst->fullPath );
}
if( !hInst->hInstance ) if( !hInst->hInstance )
{ {
@ -1017,8 +891,10 @@ void *COM_GetProcAddress( void *hInstance, const char *name )
if( !hInst || !hInst->hInstance ) if( !hInst || !hInst->hInstance )
return NULL; return NULL;
#if XASH_X86
if( hInst->custom_loader ) if( hInst->custom_loader )
return (void *)MemoryGetProcAddress( hInst->hInstance, name ); return (void *)MemoryGetProcAddress( hInst->hInstance, name );
#endif
return (void *)GetProcAddress( hInst->hInstance, name ); return (void *)GetProcAddress( hInst->hInstance, name );
} }
@ -1037,9 +913,16 @@ void COM_FreeLibrary( void *hInstance )
} }
else Con_Reportf( "Sys_FreeLibrary: Unloading %s\n", hInst->dllName ); else Con_Reportf( "Sys_FreeLibrary: Unloading %s\n", hInst->dllName );
#if XASH_X86
if( hInst->custom_loader ) if( hInst->custom_loader )
{
MemoryFreeLibrary( hInst->hInstance ); MemoryFreeLibrary( hInst->hInstance );
else FreeLibrary( hInst->hInstance ); }
else
#endif
{
FreeLibrary( hInst->hInstance );
}
hInst->hInstance = NULL; hInst->hInstance = NULL;