diff --git a/Contrib/System/SConscript b/Contrib/System/SConscript index bb26e7ab..9ffb1040 100644 --- a/Contrib/System/SConscript +++ b/Contrib/System/SConscript @@ -2,6 +2,7 @@ target = 'System' files = Split(""" Source/Buffers.c + Source/Call.S Source/Plugin.c Source/System.c """) @@ -32,7 +33,6 @@ BuildPlugin( libs, examples, docs, - entry = '_DllMainCRTStartup', nodeflib = False, defines = ['SYSTEM_EXPORTS'] ) diff --git a/Contrib/System/Source/Buffers.h b/Contrib/System/Source/Buffers.h index 3f59c932..2fd5f70b 100644 --- a/Contrib/System/Source/Buffers.h +++ b/Contrib/System/Source/Buffers.h @@ -1,2 +1,8 @@ +#if defined(_MSC_VER) && (_MSC_VER >= 1020) #pragma once +#endif +#ifndef BUFFERS_H +#define BUFFERS_H + +#endif /* BUFFERS_H */ diff --git a/Contrib/System/Source/Call.S b/Contrib/System/Source/Call.S new file mode 100644 index 00000000..92cc806d --- /dev/null +++ b/Contrib/System/Source/Call.S @@ -0,0 +1,968 @@ +;# Copyright (c) 2008 Thomas Gaugler +;# +;# Permission is hereby granted, free of charge, to any person +;# obtaining a copy of this software and associated documentation +;# files (the "Software"), to deal in the Software without +;# restriction, including without limitation the rights to use, +;# copy, modify, merge, publish, distribute, sublicense, and/or sell +;# copies of the Software, and to permit persons to whom the +;# Software is furnished to do so, subject to the following +;# conditions: +;# +;# The above copyright notice and this permission notice shall be +;# included in all copies or substantial portions of the Software. +;# +;# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +;# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +;# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +;# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +;# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +;# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +;# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +;# OTHER DEALINGS IN THE SOFTWARE. +;# +;# +;# Implementation of the functions CallProc, RealCallBack and +;# CallBack of the System plugin in pure x86 assembly. +;# +;# This is a hybrid assembly source file supporting both the +;# MASM as well as the GNU assembler in one file. +;# +;# +;# MASM: +;# ml.exe /c /nologo /Fo"call.obj" /W3 /Zi /errorReport:prompt /Ta"call.S" +;# +;# For enabling debug support use: +;# ml.exe /c /nologo /D"SYSTEM_LOG_DEBUG" /Fo"call.obj" /W3 /Zi /errorReport:prompt /Ta"call.S" +;# +;# GNU toolchain: +;# gcc -x assembler-with-cpp -s call.S -c +;# +;# For enabling debug support use: +;# gcc -x assembler-with-cpp -DSYSTEM_LOG_DEBUG -s call.S -c +;# +;# + +; .if 0 +;# MASM specific block +.386 +.model flat +OPTION casemap:none +;# SYSCALL is identical to the C calling convention, +;# but does not add an underscore prefix to symbols. +OPTION language:syscall + +SECTION_DATA equ .data +SECTION_CODE equ .code + +DATA_SUFFIX equ + +ASCII equ DB + +TEMP_LABEL equ @@ +TEMP_LABEL_AHEAD equ @f +TEMP_LABEL_BACK equ @b + +MACRO_DECL equ + +FUNC_DECL MACRO name +name PROC +ENDM + +FUNC_END MACRO name +name ENDP +ENDM + +;# end of MASM specific block +IF 0 +; .else +;# GNU toolchain specific block +.intel_syntax noprefix +.set __GNU__,1 + +#ifdef SYSTEM_LOG_DEBUG +;# Disable further proprocessing of SYSTEM_LOG_DEBUG +;# and hand it over to the GNU assembler +#undef SYSTEM_LOG_DEBUG +.set SYSTEM_LOG_DEBUG,1 +#endif + +#define IFDEF .ifdef +#define ELSE .else +#define ENDIF .endif + +#define EXTERN .extern + +#define SECTION_DATA .data +#define SECTION_CODE .text + +#define DATA_SUFFIX : +#define BYTE .byte +#define DWORD .int +#define ASCII .ascii + +#define MACRO_DECL .macro +#define MACRO +#define ENDM .endm + +#define TEMP_LABEL 1 +#define TEMP_LABEL_AHEAD 1f +#define TEMP_LABEL_BACK 1b + +.macro FUNC_DECL name +.global \name +.func \name +\name: +.endm + +.macro FUNC_END name +.endfunc +.endm + +;# /* +;# http://gcc.gnu.org/ml/gcc/2006-11/msg00081.html +;# _alloca_probe <=> _chkstk <=> _alloca (in libgcc) +;# */ + +#define __alloca_probe __alloca + +#define END .end + +;# end of GNU toolchain specific block +ENDIF + +IFDEF SYSTEM_LOG_DEBUG + EXTERN _WriteToLog : PROC + EXTERN _syslogbuf : DWORD +ENDIF + +EXTERN __alloca_probe : PROC + +EXTERN __imp__GlobalFree@4 : PROC +EXTERN __imp__GetLastError@0 : PROC +EXTERN __imp__wsprintfA : PROC + +EXTERN _GlobalCopy : PROC + +EXTERN _LastStackPlace : DWORD +EXTERN _LastStackReal : DWORD +EXTERN _LastError : DWORD +EXTERN _LastProc : DWORD +EXTERN _CallbackIndex : DWORD + +EXTERN _retexpr : DWORD +EXTERN _retaddr : PTR + +EXTERN _GetNewStackSize : PROC +EXTERN _GetGenStackOption : PROC +EXTERN _GetCDeclOption : PROC +EXTERN _GetErrorOption : PROC +EXTERN _GetProcOffset : PROC +EXTERN _GetCloneOffset : PROC +EXTERN _GetProcNameOffset : PROC +EXTERN _GetArgsSizeOffset : PROC +EXTERN _GetParamCount : PROC +EXTERN _GetParamsOffset : PROC +EXTERN _GetSizeOfProcParam : PROC +EXTERN _GetSizeOffsetParam : PROC +EXTERN _GetValueOffsetParam : PROC +EXTERN _Get_valueOffsetParam : PROC +EXTERN _SetCloneOption : PROC +EXTERN _SetProcResultOk : PROC +EXTERN _SetProcResultCallback : PROC + +SECTION_DATA + + ;# Low double word of result + _z1 DATA_SUFFIX DWORD 0 + + ;# High double word of result + _z2 DATA_SUFFIX DWORD 0 + +IFDEF SYSTEM_LOG_DEBUG + + LogStack DATA_SUFFIX ASCII "%s ESP = 0x%08X Stack = 0x%08X Real = 0x%08X" + BYTE 0 + + LogCall DATA_SUFFIX BYTE 9,9 + ASCII "Call:" + BYTE 10,0 + + LogBeforeCall DATA_SUFFIX BYTE 9,9,9 + ASCII "Before call " + BYTE 0 + + LogNearCall DATA_SUFFIX BYTE 10,9,9,9 + ASCII "Near call " + BYTE 0 + + LogBackFrom DATA_SUFFIX BYTE 9 + ASCII "Back from " + BYTE 0 + + LogAfterCall DATA_SUFFIX BYTE 10,9,9,9 + ASCII "After call " + BYTE 0 + + LogReturnAfter DATA_SUFFIX BYTE 10,9,9,9 + ASCII "Return 0x%08X 0x%08X" + BYTE 0 + + LogCalled DATA_SUFFIX ASCII "Called callback from " + BYTE 0 + + LogShortAfter DATA_SUFFIX BYTE 10,9,9,9 + ASCII "Short-After call " + BYTE 0 + + LogReturn DATA_SUFFIX BYTE 9,9 + ASCII "Return from callback:" + BYTE 10,0 + + LogBefore DATA_SUFFIX BYTE 9,9,9 + ASCII "Before call-back " + BYTE 0 + + LogShortBefore DATA_SUFFIX BYTE 10,9,9,9 + ASCII "Sh-Before call-back" + BYTE 0 + + LogLF DATA_SUFFIX BYTE 10,0 + +ENDIF + +SECTION_CODE + +IFDEF SYSTEM_LOG_DEBUG + +;# Sets edi to address of the end of the syslog buffer (terminating zero) +MACRO_DECL SYSTEM_LOG_INIT MACRO + mov edi,offset _syslogbuf +TEMP_LABEL: + ;# End loop if terminating zero of buffer was found otherwise move + ;# to next character and check again + cmp byte ptr [edi],0 + je TEMP_LABEL_AHEAD + inc edi + jmp TEMP_LABEL_BACK +TEMP_LABEL: +ENDM + +;# Appends log information and advances edi accordingly. +;# +;# edi must point to the address of the log buffer where +;# the log information should be appended. +;# +;# eax returns number of bytes appended to log buffer +MACRO_DECL SYSTEM_LOG_ADD MACRO arg1,arg2 + ;# Format string +IFDEF __GNU__ + push \arg1 \arg2 +ELSE + push arg1 arg2 +ENDIF + ;# Log buffer + push edi + call dword ptr [__imp__wsprintfA] + ;# If wsprintf succeeds then advance edi by number of bytes + ;# written to buffer + cmp eax,0 + jl TEMP_LABEL_AHEAD + add edi,eax +TEMP_LABEL: + add esp,8 +ENDM + +;# Writes stackpointer and additional information to log +;# and advances edi accordingly (terminating zero of buffer). +;# +;# edi must point to the address of the log buffer where +;# the log information should be appended. +;# +;# eax returns number of bytes appended to log buffer +MACRO_DECL SYSTEM_EVENT MACRO arg1,arg2 + ;# Save current stack pointer in eax + mov eax,esp + ;# Stackpointer information + push dword ptr [_LastStackReal] + push dword ptr [_LastStackPlace] + push eax + ;# Event information +IFDEF __GNU__ + push \arg1 \arg2 +ELSE + push arg1 arg2 +ENDIF + SYSTEM_LOG_ADD offset LogStack + add esp,16 +ENDM + +;# Flush log information and reset log buffer. +;# +;# edi must point to the address of the log buffer where +;# the log information should be appended. +;# +;# eax returns number of bytes appended to log buffer +MACRO_DECL SYSTEM_LOG_POST MACRO + ;# Append line feed to log information + SYSTEM_LOG_ADD offset LogLF + ;# Flush log information + push offset _syslogbuf + call _WriteToLog + add esp,4 + ;# Reset log buffer + mov byte ptr [_syslogbuf],0 +ENDM + +ENDIF + +FUNC_DECL _CallProc + ;# Save stack + push ebp + mov ebp,esp + ;# Stack space for local variables + ;# ebp-4 = Size of ProcParameter structure + sub esp,4 + ;# Save all usable registers to free our hands + push ebx + push edi + push esi + push ebp + + IFDEF SYSTEM_LOG_DEBUG + SYSTEM_LOG_INIT + SYSTEM_LOG_ADD offset LogCall + SYSTEM_EVENT offset LogBeforeCall + ENDIF + + ;# CallbackIndex != 0 + cmp dword ptr [_CallbackIndex],0 + je stack_expand_done + + ;# proc->Options without POPT_GENSTACK + push dword ptr [ebp+8] + call _GetGenStackOption + cmp eax,0 + ;# Remove ebp from stack, no need to generate stack + pop eax + jne stack_expand_done + + ;# Save previous stack location + mov dword ptr [_LastStackReal],esp + cmp dword ptr [_LastStackPlace],0 + jne stack_adjust + ;# Create new stack + call _GetNewStackSize + call __alloca_probe + mov dword ptr [_LastStackPlace],esp + jmp stack_expand_done +stack_adjust: + ;# Move stack pointer + mov esp,dword ptr [_LastStackPlace] + +stack_expand_done: + ;# Push arguments to stack + ;# + ;# Get number of parameters + push dword ptr [ebp+8] + call _GetParamCount + add esp,4 + + ;# Skip if there are no parameters + cmp eax,0 + jle params_loop_done + + ;# Save number of paramters on stack + push eax + + ;# Get offset for element Params of SystemProc structure + call _GetParamsOffset + add eax,dword ptr [ebp+8] + push eax + + call _GetSizeOfProcParam + mov dword ptr [ebp-4],eax + + ;# Calculate offset for the last Parameter + pop ebx + pop ecx + mul ecx + add ebx,eax + + ;# Save offset of last paramter on stack + push ebx + ;# Save number of paramters on stack + push ecx + + ;# Size offset of parameter + call _GetSizeOffsetParam + push eax + + ;# Value offset of parameter + call _GetValueOffsetParam + push eax + + ;# _value offset of parameter + call _Get_valueOffsetParam + push eax + + ;# ebx = _value offset + pop ebx + ;# edx = Value offset + pop edx + ;# esi = Size offset + pop esi + ;# ecx = n-th parameter + pop ecx + ;# eax = offset of current worked on parameter + pop eax + +params_loop: + ;# Check Size of param + cmp dword ptr [eax+esi],2 + jne params_default + + ;# Long type + push dword ptr [eax+ebx] + +params_default: + ;# Default for all types + push dword ptr [eax+edx] + + + ;# Continue with next parameter + sub eax,dword ptr[ebp-4] + loop params_loop + +params_loop_done: + ;# Save proc + ;# proc->Clone + call _GetCloneOffset + mov ecx,dword ptr [ebp+8] + add eax,ecx + + ;# proc->Clone = LastProc + mov edx,dword ptr [_LastProc] + mov dword ptr [eax],edx + + ;# LastProc = proc + mov dword ptr [_LastProc],ecx + + IFDEF SYSTEM_LOG_DEBUG + SYSTEM_EVENT offset LogNearCall + SYSTEM_LOG_POST + ENDIF + + ;# Get address of procedure + call _GetProcOffset + mov ecx,dword ptr [ebp+8] + mov ecx,dword ptr [eax+ecx] + + ;# /* + ;# workaround for bug #1535007 + ;# http://sf.net/tracker/index.php?func=detail&aid=1535007&group_id=22049&atid=373085 + ;# + ;# If a function returns short and doesn't clear eax in the process, + ;# it will only set 2 bytes of eax, and the other 2 bytes remain + ;# "random". In this case, they'll be part of the proc pointer. + ;# + ;# To avoid this, eax is cleared before the function is called. This + ;# makes sure the value eax will contain is only what the function + ;# actually sets. + ;# */ + xor eax,eax + + ;# Call + call ecx + + ;# Return + mov dword ptr [_z1],eax + mov dword ptr [_z2],edx + + IFDEF SYSTEM_LOG_DEBUG + SYSTEM_LOG_INIT + SYSTEM_LOG_ADD offset LogBackFrom + ;# LastProc->ProcName + call _GetProcNameOffset + mov ecx,dword ptr [_LastProc] + add eax,ecx + SYSTEM_LOG_ADD eax + SYSTEM_EVENT offset LogShortAfter + ENDIF + + cmp dword ptr [_CallbackIndex],0 + je stack_restore_done + mov eax,dword ptr [_LastProc] + push eax + call _GetGenStackOption + cmp eax,0 + pop eax + jne stack_restore_done + + ;# Restore real stack location + mov dword ptr [_LastStackPlace],esp + mov esp,dword ptr [_LastStackReal] + pop ebp + +stack_restore_done: + ;# Restore proc + mov edx,dword ptr [_LastProc] + mov dword ptr [ebp+8],edx + + ;# proc->Clone + call _GetCloneOffset + add eax,edx + + ;# LastProc = proc->Clone + mov eax,dword ptr [eax] + mov dword ptr [_LastProc],eax + + ;# In case of cdecl convention we should clear stack + + ;# if ((proc->Options & POPT_CDECL) != 0) + push edx + call _GetCDeclOption + cmp eax,0 + pop edx + je stack_clear_done + + ;# Get number of parameters + push edx + call _GetParamCount + add esp,4 + + ;# Skip if there are no parameters + cmp eax,0 + jle stack_clear_done + + ;# Save number of parameters on stack + push eax + + ;# Get offset for element Params of SystemProc structure + call _GetParamsOffset + add eax,dword ptr [ebp+8] + + ;# Calculate offset for the Parameter 1 + add eax,dword ptr [ebp-4] + + ;# Save offset for the Parameter 1 on stack + push eax + + ;# Size offset of parameter + call _GetSizeOffsetParam + push eax + + ;# if ((CallbackIndex > 0) && ((proc->Options & POPT_GENSTACK) == 0)) + cmp dword ptr [_CallbackIndex],0 + jle real_stack_cleanup + push dword ptr [ebp+8] + call _GetGenStackOption + cmp eax,0 + pop eax + jne real_stack_cleanup + + ;# In case of temporary stack + ;# + ;# esi = Size offset + pop esi + ;# eax = offset of current worked on parameter + pop eax + ;# ecx = n-th paramter + pop ecx + +temp_stack_loop: + ;# LastStackPlace += 4* Size of current parameter; + mov edx,dword ptr [eax+esi] + mov ebx,dword ptr [_LastStackPlace] + lea edx,[ebx+edx*4] + mov dword ptr [_LastStackPlace],edx + + ;# Go to next + add eax,dword ptr [ebp-4] + loop temp_stack_loop + + ;# End of stack cleanup + jmp stack_clear_done + +real_stack_cleanup: + ;# In case of real stack + ;# + ;# esi = Size offset + pop esi + ;# eax = offset of current worked on parameter + pop eax + ;# ecx = Number of paramters + pop ecx + +real_stack_loop: + ;# Size of current parameter == 2 + cmp dword ptr [eax+esi],2 + jne real_stack_default + ;# Long type + pop edx + +real_stack_default: + ;# Default + pop edx + add eax,dword ptr [ebp-4] + loop real_stack_loop + +stack_clear_done: + ;# In case of cleared call-proc-queue -> clear allocated stack place (more flexible) + cmp dword ptr [_LastProc],0 + jne stack_cleanup_done + mov dword ptr [_LastStackPlace],0 + +stack_cleanup_done: + + ;# Save return + + ;# Get offset for element Params of SystemProc structure + call _GetParamsOffset + mov edx,dword ptr [ebp+8] + add edx,eax + + ;# proc->Params[0].Value = Low double word of result + call _GetValueOffsetParam + mov ecx,dword ptr [_z1] + mov dword ptr [edx+eax],ecx + + ;# proc->Params[0]._value = High double word of result + call _Get_valueOffsetParam + mov ecx,dword ptr [_z2] + mov dword ptr [edx+eax],ecx + + ;# Proc result: OK + push dword ptr [ebp+8] + call _SetProcResultOk + ;# In case of POPT_ERROR -> Get_LastError + call _GetErrorOption + cmp eax,0 + pop eax + je handling_error_option_done + call dword ptr [__imp__GetLastError@0] + mov dword ptr [_LastError],eax + +handling_error_option_done: + IFDEF SYSTEM_LOG_DEBUG + SYSTEM_EVENT offset LogAfterCall + + push dword ptr [_z2] + push dword ptr [_z1] + SYSTEM_LOG_ADD offset LogReturnAfter + add esp,8 + + SYSTEM_LOG_POST + ENDIF + + ;# Return + mov eax,dword ptr [ebp+8] + ;# Restore registers + pop esi + pop edi + pop ebx + ;# Restore stack pointer + mov esp,ebp + pop ebp + ret +FUNC_END _CallProc + + + +FUNC_DECL _RealCallBack + ;# Save stack + push ebp + mov ebp,esp + + ;# Stack space for local variables + ;# ebp-16 = Size of ProcParameter structure + ;# ebp-12 = ArgsSize + ;# ebp-8 = Arguments pointer + ;# ebp-4 = proc + sub esp,16 + + ;# Save all usable registers to free our hands + push ebx + push edi + push esi + + ;# Arguments pointer + ;# 1-st arg (4 bytes), return (4 bytes) => add 8 bytes + mov dword ptr [ebp-8],ebp + add dword ptr [ebp-8],8 + + ;# Our callback proc + mov dword ptr [ebp-4],eax + + IFDEF SYSTEM_LOG_DEBUG + SYSTEM_LOG_INIT + SYSTEM_LOG_ADD offset LogCalled + ;# LastProc->ProcName + call _GetProcNameOffset + mov ecx,dword ptr [_LastProc] + add eax,ecx + SYSTEM_LOG_ADD eax + SYSTEM_EVENT offset LogShortAfter + SYSTEM_LOG_POST + ENDIF + + call _GetCloneOffset + mov edx,eax + mov ecx,dword ptr [ebp-4] + + ;# 1. Find last unused clone + jmp clone_load +clone_next: + mov ecx,dword ptr [eax] + mov dword ptr [ebp-4],ecx +clone_load: + lea eax,[ecx+edx] + cmp dword ptr [eax],0 + jne clone_next + + ;# 2. Create new clone + push edx + push ecx + call _GlobalCopy + pop ecx + pop edx + ;# proc->Clone = Result of GlobalCopy + mov ecx,dword ptr [ebp-4] + mov dword ptr [ecx+edx],eax + ;# proc = proc->Clone + mov dword ptr [ebp-4],eax + + ;# 3. Set clone option + push eax + call _SetCloneOption + pop eax + + ;# proc->ArgsSize = 0 + mov dword ptr [ebp-12],0 + + ;# Read Arguments + + ;# Get number of parameters + push dword ptr [ebp-4] + call _GetParamCount + add esp,4 + + ;# Skip if there are no parameters + cmp eax,0 + jle cb_params_loop_done + + ;# Save number of parameters on stack + push eax + + ;# Get size of ProcParameter structure + call _GetSizeOfProcParam + mov dword ptr [ebp-16],eax + + ;# Get offset for element Params of SystemProc structure + call _GetParamsOffset + add eax,dword ptr [ebp-4] + + ;# Calculate offset for the Parameter 1 + add eax,dword ptr [ebp-16] + + ;# Save offset for the Parameter 1 on stack + push eax + + ;# Size offset of parameter + call _GetSizeOffsetParam + push eax + + ;# Value offset of parameter + call _GetValueOffsetParam + push eax + + ;# _value offset of parameter + call _Get_valueOffsetParam + push eax + + ;# ebx = _value offset + pop ebx + ;# edx = Value offset + pop edx + ;# esi = Size offset + pop esi + ;# eax = offset of current worked on parameter + pop eax + ;# ecx = n-th parameter + pop ecx + +cb_params_loop: + push ecx + + ;# Default + mov ecx,dword ptr [ebp-8] + mov ecx,dword ptr [ecx] + mov dword ptr [eax+edx],ecx + ;# (Arguments pointer)++ + add dword ptr [ebp-8],4 + ;# ArgsSize += 4 + add dword ptr [ebp-12],4 + + ;# Size of current parameter == 2 + cmp dword ptr [eax+esi],2 + jne cb_params_next + ;# Long type + mov ecx,dword ptr [ebp-8] + mov ecx,dword ptr [ecx] + mov dword ptr [eax+ebx],ecx + ;# (Arguments pointer)++ + add dword ptr [ebp-8],4 + ;# ArgsSize += 4 + add dword ptr [ebp-12],4 + +cb_params_next: + ;# Next parameter + add eax,dword ptr [ebp-16] + + pop ecx + loop cb_params_loop + +cb_params_loop_done: + ;# proc->ArgsSize = ArgsSize + call _GetArgsSizeOffset + add eax,dword ptr [ebp-4] + mov ecx,dword ptr [ebp-12] + mov dword ptr [eax],ecx + + push dword ptr [ebp-4] + call _SetProcResultCallback + pop eax + + ;# Return + ;# eax = proc + ;# Save temporary stack info + push ebp + ;# Push LastStackPlace + mov dword ptr [_LastStackPlace],esp + ;# Restore real stack + mov esp,dword ptr [_LastStackReal] + ;# Pop LastStackReal + pop ebp + + ;# Fake return from System::Call + + ;# Restore registers + pop esi + pop edi + pop ebx + ;# Restore stack pointer + mov esp,ebp + pop ebp + ;# Return + ret +FUNC_END _RealCallBack + + + +FUNC_DECL _CallBack + ;# Save stack + push ebp + mov ebp,esp + + ;# Save all usable registers to free our hands + push ebx + push edi + push esi + + IFDEF SYSTEM_LOG_DEBUG + SYSTEM_LOG_INIT + SYSTEM_LOG_ADD offset LogReturn + SYSTEM_EVENT offset LogBefore + SYSTEM_LOG_POST + ENDIF + + ;# Get offset for element Params of SystemProc structure + call _GetParamsOffset + add eax,dword ptr [ebp+8] + push eax + + ;# Value offset + call _GetValueOffsetParam + push eax + + ;# _value offset + call _Get_valueOffsetParam + mov edx,eax + + ;# offset of Value element within SystemProc structure + pop ecx + + ;# offset of Params element within SystemProc structure + pop eax + + ;# Callback proc result + push dword ptr [eax+ecx] + push dword ptr [eax+edx] + + ;# Adjust return statement + ;# if ((proc->Options & POPT_CDECL) != 0) + push dword ptr [ebp+8] + call _GetCDeclOption + cmp eax,0 + pop edx + jne _retexpr_stdcall + ;# retexpr[1] = proc->ArgsSize + call _GetArgsSizeOffset + mov ecx,dword ptr [ebp+8] + mov al,byte ptr [ecx+eax] + mov byte ptr [_retexpr+1],al + jmp set_return_addr +_retexpr_stdcall: + ;# retexpr[1] = 0 + mov byte ptr [_retexpr+1],0 +set_return_addr: + ;# Right return statement address + mov dword ptr [_retaddr],offset _retexpr + + ;# Remove unneeded callback proc + push dword ptr [ebp+8] + call dword ptr [__imp__GlobalFree@4] + + ;# Prepare return + ;# Callback proc result + pop edx + pop eax + + ;# Restore temporary stack and return + + ;# Save real stack info + ;# Save previous stack location + ;# Push _LastStackReal + push ebp + mov dword ptr [_LastStackReal],esp + ;# Move stack pointer + mov esp,dword ptr [_LastStackPlace] + ;# Pop _LastStackPlace + pop ebp + + IFDEF SYSTEM_LOG_DEBUG + push eax + push edx + SYSTEM_EVENT offset LogShortBefore + SYSTEM_LOG_POST + ;# Callback proc result + pop edx + pop eax + ENDIF + + ;# Fake return from Callback + + ;# Restore registers + pop esi + pop edi + pop ebx + ;# Restore stack pointer + mov esp,ebp + pop ebp + ;# Return + jmp dword ptr [_retaddr] + +FUNC_END _CallBack + +END + diff --git a/Contrib/System/Source/System.c b/Contrib/System/Source/System.c index 53a3f76a..62ab4adf 100644 --- a/Contrib/System/Source/System.c +++ b/Contrib/System/Source/System.c @@ -6,10 +6,18 @@ #include "Buffers.h" #include "System.h" #ifndef __GNUC__ +#define _DECL_DLLMAIN /* enable prototypes for DllMain and _CRT_INIT */ +#include #include +#else +#define _RPT0(type, msg) +#define _CRT_WARN 0 #endif /* __GNUC__ */ #include +// Type conversion macro +#define INT_TO_POINTER(i) ((void *) (int) (i)) + // Parse Section Type #define PST_PROC 0 #define PST_PARAMS 1 @@ -29,7 +37,6 @@ const int ParamSizeByType[7] = {0, // PAT_VOID (Size will be equal to 1) 1, // PAT_GUID 0}; // PAT_CALLBACK (Size will be equal to 1) -int z1, z2; // I've made them static for easier use at callback procs int LastStackPlace; int LastStackReal; DWORD LastError; @@ -41,15 +48,6 @@ HINSTANCE g_hInstance; char retexpr[4]; HANDLE retaddr; -#ifndef __GNUC__ - -/* -FIXME: -GCC cannot compile the inline assembly used by System::Call and -System::Get, so those functions and their supporting functions -are disabled when using GCC. -*/ - char *GetResultStr(SystemProc *proc) { char *buf = AllocString(); @@ -61,14 +59,13 @@ char *GetResultStr(SystemProc *proc) #ifdef SYSTEM_LOG_DEBUG -// System log debuggin turned on -#define SYSTEM_EVENT(a) { _asm { mov logespsave, esp }; LogEvent(a); } -#define SYSTEM_LOG_ADD(a) { lstrcat(syslogbuf, a); } -#define SYSTEM_LOG_POST { lstrcat(syslogbuf, "\n"); WriteToLog(syslogbuf); *syslogbuf = 0; } +// System log debugging turned on +#define SYSTEM_LOG_ADD(a) { register int _len = lstrlen(syslogbuf); lstrcpyn(syslogbuf + _len, a, sizeof(syslogbuf) - _len); } +#define SYSTEM_LOG_POST { SYSTEM_LOG_ADD("\n"); WriteToLog(syslogbuf); *syslogbuf = 0; } HANDLE logfile = NULL; char syslogbuf[4096] = ""; -int logop = 0, logespsave; +int logop = 0; void WriteToLog(char *buffer) { @@ -92,14 +89,6 @@ void WriteToLog(char *buffer) // FlushFileBuffers(logfile); } -void LogEvent(char *a) -{ - char buffer[1024]; - wsprintf(buffer, "%s ESP = 0x%08X Stack = 0x%08X Real = 0x%08X", a, - logespsave, LastStackPlace, LastStackReal); - SYSTEM_LOG_ADD(buffer); -} - PLUGINFUNCTION(Debug) { char *o1; @@ -261,8 +250,6 @@ PLUGINFUNCTION(Call) GlobalFree((HANDLE) proc); // No, free it } PLUGINFUNCTIONEND -#endif /* __GNUC__ */ - PLUGINFUNCTIONSHORT(Int64Op) { __int64 i1, i2 = 0, i3, i4; @@ -320,8 +307,6 @@ __int64 GetIntFromString(char **p) return myatoi(buffer); } -#ifndef __GNUC__ - SystemProc *PrepareProc(BOOL NeedForCall) { int SectionType = PST_PROC, // First section is always proc spec @@ -402,7 +387,7 @@ SystemProc *PrepareProc(BOOL NeedForCall) if (proc != NULL) GlobalFree(proc); // Get already defined proc - proc = (SystemProc *) myatoi(cbuf); + proc = (SystemProc *) INT_TO_POINTER(myatoi(cbuf)); if (!proc) break; // Find the last clone at proc queue @@ -683,7 +668,7 @@ SystemProc *PrepareProc(BOOL NeedForCall) // Use direct system proc address int addr; - proc->Dll = (HANDLE) myatoi(proc->DllName); + proc->Dll = (HANDLE) INT_TO_POINTER(myatoi(proc->DllName)); if (proc->Dll == 0) { @@ -712,7 +697,7 @@ SystemProc *PrepareProc(BOOL NeedForCall) if (*proc->DllName == 0) { // Use direct system proc address - if ((proc->Proc = (HANDLE) myatoi(proc->ProcName)) == 0) + if ((proc->Proc = (HANDLE) INT_TO_POINTER(myatoi(proc->ProcName))) == 0) proc->ProcResult = PR_ERROR; } else { @@ -735,7 +720,7 @@ SystemProc *PrepareProc(BOOL NeedForCall) } break; case PT_STRUCT: - if (*(proc->ProcName) != 0) proc->Proc = (HANDLE) myatoi(proc->ProcName); + if (*(proc->ProcName) != 0) proc->Proc = (HANDLE) INT_TO_POINTER(myatoi(proc->ProcName)); break; } } @@ -817,7 +802,7 @@ void ParamsIn(SystemProc *proc) case PAT_CALLBACK: // Generate new or use old callback if (lstrlen(realbuf) > 0) - par->Value = (int) CreateCallback((SystemProc*) myatoi(realbuf)); + par->Value = (int) CreateCallback((SystemProc*) INT_TO_POINTER(myatoi(realbuf))); break; } GlobalFree(realbuf); @@ -916,368 +901,6 @@ void ParamsOut(SystemProc *proc) while (i >= 0); } -void _alloca_probe(); - -SystemProc __declspec(naked) *CallProc(SystemProc *proc) -{ - int z3; - - _asm - { - // Save stack - push ebp - mov ebp, esp - // Stack space for local variables - sub esp, __LOCAL_SIZE - // Save all usable registers to free our hands - push ebx - push edi - push esi - } - - SYSTEM_LOG_ADD("\t\tCall:\n"); - SYSTEM_EVENT("\t\t\tBefore call ") - - if (CallbackIndex && (!(proc->Options & POPT_GENSTACK))) - { - _asm - { - push ebp - // Save previous stack location - mov LastStackReal, esp - } - - if (LastStackPlace == 0) - { - _asm - { - // Create new stack - mov eax, NEW_STACK_SIZE - call _alloca_probe - mov LastStackPlace, esp - } - } else - _asm - { - // Move stack pointer - mov esp, LastStackPlace - } - } - - // Push arguments to stack - for (z1 = proc->ParamCount; z1 > 0; z1--) - { - // Long types - if (proc->Params[z1].Size == 2) - { - z2 = proc->Params[z1]._value; - _asm push z2; - } - // Default - z2 = proc->Params[z1].Value; - _asm push z2; - } - - // Call the proc and save return - z1 = (int) proc->Proc; - - // Save proc - proc->Clone = (SystemProc *) LastProc; - _asm - { - mov eax, proc - mov LastProc, eax - } - //LastProc = proc; - - SYSTEM_EVENT("\n\t\t\tNear call ") - SYSTEM_LOG_POST; - - // workaround for bug #1535007 - // http://sf.net/tracker/index.php?func=detail&aid=1535007&group_id=22049&atid=373085 - // - // If a function returns short and doesn't clear eax in the process, - // it will only set 2 bytes of eax, and the other 2 bytes remain - // "random". In this case, they'll be part of the proc pointer. - // - // To avoid this, eax is cleared before the function is called. This - // makes sure the value eax will contain is only what the function - // actually sets. - _asm xor eax, eax - - _asm - { - // Call - call z1 - // Return - mov z1, eax - mov z2, edx - } - - SYSTEM_LOG_ADD("Back from "); - SYSTEM_LOG_ADD(LastProc->ProcName); - SYSTEM_EVENT("\n\t\t\tShort-After call ") - - if ((CallbackIndex) && (!(LastProc->Options & POPT_GENSTACK))) - { - _asm - { - // Restore real stack location - mov LastStackPlace, esp - mov esp, LastStackReal - pop ebp - } - } - - // Restore proc - _asm - { - mov eax, LastProc - mov proc, eax - } -// proc = LastProc; - LastProc = proc->Clone; - - // In case of cdecl convention we should clear stack - if ((proc->Options & POPT_CDECL) != 0) - { - if ((CallbackIndex > 0) && ((proc->Options & POPT_GENSTACK) == 0)) - { - // In case of temporary stack - for (z3 = 1; z3 <= proc->ParamCount; z3++) - LastStackPlace += 4*proc->Params[z3].Size; - } else - { - // in case of real stack - for (z3 = 1; z3 <= proc->ParamCount; z3++) - { - if (proc->Params[z3].Size == 2) - _asm pop edx; - _asm pop edx; - } - } - } - - // In case of cleared call-proc-queue -> clear allocated stack place (more flexible) - if (LastProc == NULL) LastStackPlace = (int) NULL; - - // Save return - proc->Params[0].Value = z1; -// if (proc->Params[0].Size == 2) - proc->Params[0]._value = z2; - // Proc result: OK - proc->ProcResult = PR_OK; - - // In case of POPT_ERROR -> GetLastError - if ((proc->Options & POPT_ERROR) != 0) - { - LastError = GetLastError(); - } - - SYSTEM_EVENT("\n\t\t\tAfter call ") -#ifdef SYSTEM_LOG_DEBUG - { - char buf[1024]; - wsprintf(buf, "\n\t\t\tReturn 0x%08X 0x%08X", z1, z2); - SYSTEM_LOG_ADD(buf); - } -#endif - SYSTEM_LOG_POST; - - _asm - { - // Return - mov eax, proc - // Restore registers - pop esi - pop edi - pop ebx - // Restore stack pointer - mov esp, ebp - pop ebp - // Return - ret - } -} - -SystemProc __declspec(naked) *RealCallBack() -{ - SystemProc *proc; - - _asm - { - // Save stack - push ebp - mov ebp, esp - // Stack space for local variables - sub esp, __LOCAL_SIZE - // Save all usable registers to free our hands - push ebx - push edi - push esi - - // Arguments pointer - mov z2, esp // 1-st arg - 4*4 (pushes) - 4 (return) - __LOCAL_SIZE - add z2, __LOCAL_SIZE - add z2, 5*4 - // Our callback proc - mov proc, eax - } - - SYSTEM_LOG_ADD("Called callback from "); - SYSTEM_LOG_ADD(LastProc->ProcName); - SYSTEM_EVENT("\n\t\t\tShort-After call ") - SYSTEM_LOG_POST; - - // Find last unused clone - while ((proc->Clone != NULL)) proc = proc->Clone; - // 2. Create new clone - proc = (proc->Clone = GlobalCopy(proc)); - // 3. Set clone option - proc->Options |= POPT_CLONE; - - // Read arguments - proc->ArgsSize = 0; - for (z1 = 1; z1 <= proc->ParamCount; z1++) - { - // Default - proc->Params[z1].Value = *(((int*)z2)++); - proc->ArgsSize += 4; - // Long only - if (proc->Params[z1].Size == 2) - { - proc->Params[z1]._value = *(((int*)z2)++); - proc->ArgsSize += 4; - } - } - proc->ProcResult = PR_CALLBACK; - - _asm - { - // Return - mov eax, proc - - // Save temporary stack info - push ebp -// push LastStackPlace - mov LastStackPlace, esp - // Restore real stack - mov esp, LastStackReal - pop ebp -// pop LastStackReal - } - - _asm - { - // Fake return from System::Call - - // Restore registers - pop esi - pop edi - pop ebx - // Restore stack pointer - mov esp, ebp - pop ebp - // Return - ret - } -} - - -SystemProc __declspec(naked) *CallBack(SystemProc *proc) -{ - _asm - { - // Save stack - push ebp - mov ebp, esp - // Stack space for local variables - sub esp, __LOCAL_SIZE - // Save all usable registers to free our hands - push ebx - push edi - push esi - } - - // MessageBox(NULL, "cool1", "Cool", MB_OK); - - SYSTEM_LOG_ADD("\t\tReturn from callback:\n"); - SYSTEM_EVENT("\t\t\tBefore call-back "); - SYSTEM_LOG_POST; - - //z1 = proc->Params[0].Value; - //z2 = proc->Params[0]._value; - //z1 = &(proc->Params[0].Value); - _asm - { - mov eax, proc - add eax, SYSTEM_ZERO_PARAM_VALUE_OFFSET - push [eax] - push [eax+4] - } - - // Adjust return statement - if ((proc->Options & POPT_CDECL) == 0) retexpr[1] = proc->ArgsSize; - else retexpr[1] = 0x0; - - // Right return statement address - retaddr = (HANDLE) retexpr; - - // Remove unneeded callback proc - GlobalFree((HANDLE) proc); - -// MessageBox(NULL, "cool2", "Cool", MB_OK); - - _asm - { - // Prepare return - // callback proc result - pop edx - pop eax - - // Restore temporary stack and return - - // Save real stack info - // Save previous stack location -// push LastStackReal - push ebp - mov LastStackReal, esp - // Move stack pointer - mov esp, LastStackPlace -// pop LastStackPlace - pop ebp - } - -#ifdef SYSTEM_LOG_DEBUG - _asm - { - push eax - push edx - } - SYSTEM_EVENT("\n\t\t\tSh-Before call-back"); - SYSTEM_LOG_POST; - _asm - { - // callback proc result - pop edx - pop eax - } -#endif - - // Fake return from Callback - _asm { - // Restore registers - pop esi - pop edi - pop ebx - // Restore stack pointer - mov esp, ebp - pop ebp - // Return - jmp retaddr - } -} - HANDLE CreateCallback(SystemProc *cbproc) { char *mem; @@ -1290,7 +913,8 @@ HANDLE CreateCallback(SystemProc *cbproc) mem = (char *) (cbproc->Proc = VirtualAlloc(NULL, 10, MEM_COMMIT, PAGE_EXECUTE_READWRITE)); *(mem++) = (char) 0xB8; // Mov eax, const - *(((int *)mem)++) = (int) cbproc; + *((int *)mem) = (int) cbproc; + mem += sizeof(int); *(mem++) = (char) 0xe9; // Jmp relative *((int *)mem) = (int) RealCallBack; *((int *)mem) -= ((int) mem) + 4; @@ -1387,16 +1011,25 @@ void CallStruct(SystemProc *proc) proc->Params[0].Value = (int) proc->Proc; } -#endif /* __GNUC__ */ +/* +Use of system _DllMainCRTStartup to avoid endless recursion for the debug +report macro _RPT0. -BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +The system _DllMainCRTStartup initializes the C runtime environment. +In particular the value for _osplatform is initialized. In the function +_get_winmajor called in the execution of the _RPT0 macro an assertion +failure is raised if _osplatform is not set. The assertion is reported by +the same means as used for the _RPT0 macro. This leads to an endless recursion. +*/ + +BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { g_hInstance=hInst; if (ul_reason_for_call == DLL_PROCESS_ATTACH) { // change the protection of return command - VirtualProtect(&retexpr, sizeof(retexpr), PAGE_EXECUTE_READWRITE, &LastStackPlace); + VirtualProtect(&retexpr, sizeof(retexpr), PAGE_EXECUTE_READWRITE, (PDWORD)&LastStackPlace); // initialize some variables LastStackPlace = 0; @@ -1411,3 +1044,139 @@ BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lp return TRUE; } +/* +Returns size by which the stack should be expanded +*/ +unsigned int GetNewStackSize(void) +{ + return NEW_STACK_SIZE; +} + +/* +Returns non-zero value if GENSTACK option is set +*/ +unsigned int GetGenStackOption(SystemProc *proc) +{ + return (proc->Options & POPT_GENSTACK); +} + +/* +Returns non-zero value if CDECL option is set +*/ +unsigned int GetCDeclOption(SystemProc *proc) +{ + return (proc->Options & POPT_CDECL); +} + +/* +Returns non-zero value if Error option is set +*/ +unsigned int GetErrorOption(SystemProc *proc) +{ + return (proc->Options & POPT_ERROR); +} + +/* +Returns offset for element Proc of SystemProc structure +*/ +unsigned int GetProcOffset(void) +{ + return (unsigned int)(&(((SystemProc *)0)->Proc)); +} + +/* +Returns offset for element Clone of SystemProc structure +*/ +unsigned int GetCloneOffset(void) +{ + return (unsigned int)(&(((SystemProc *)0)->Clone)); +} + +/* +Returns offset for element ProcName of SystemProc structure +*/ +unsigned int GetProcNameOffset(void) +{ + return (unsigned int)(&(((SystemProc *)0)->ProcName)); +} + +/* +Returns offset for element ArgsSize of SystemProc structure +*/ +unsigned int GetArgsSizeOffset(void) +{ + return (unsigned int)(&(((SystemProc *)0)->ArgsSize)); +} + +/* +Returns number of parameters +*/ +unsigned int GetParamCount(SystemProc *proc) +{ + return proc->ParamCount; +} + +/* +Returns offset for element Params of SystemProc structure +*/ +unsigned int GetParamsOffset(void) +{ + return (unsigned int)(&(((SystemProc *)0)->Params)); +} + +/* +Returns size of ProcParameter structure +*/ +unsigned int GetSizeOfProcParam(void) +{ + return (sizeof(ProcParameter)); +} + + +/* +Returns offset for element Size of ProcParameter structure +*/ +unsigned int GetSizeOffsetParam(void) +{ + return (unsigned int)(&(((ProcParameter *)0)->Size)); +} + +/* +Returns offset for element Value of ProcParameter structure +*/ +unsigned int GetValueOffsetParam(void) +{ + return (unsigned int)(&(((ProcParameter *)0)->Value)); +} + +/* +Returns offset for element _value of ProcParameter structure +*/ +unsigned int Get_valueOffsetParam(void) +{ + return (unsigned int)(&(((ProcParameter *)0)->_value)); +} + +/* +Sets "CLONE" option +*/ +void SetCloneOption(SystemProc *proc) +{ + proc->Options |= POPT_CLONE; +} + +/* +Sets Result of procedure call to be "OK" +*/ +void SetProcResultOk(SystemProc *proc) +{ + proc->ProcResult = PR_OK; +} + +/* +Sets Result of procedure call to be "CALLBACK" +*/ +void SetProcResultCallback(SystemProc *proc) +{ + proc->ProcResult = PR_CALLBACK; +} diff --git a/Contrib/System/Source/System.h b/Contrib/System/Source/System.h index ec34e31f..4c5ddc88 100644 --- a/Contrib/System/Source/System.h +++ b/Contrib/System/Source/System.h @@ -58,10 +58,6 @@ typedef struct { int Type; int Option; // -1 -> Pointer, 1-... -> Special+1 - - // if you'll change ProcParameter or SystemProc structure - update this value -#define SYSTEM_ZERO_PARAM_VALUE_OFFSET 0x820 - int Value; // it can hold any 4 byte value int _value; // value buffer for structures > 4 bytes (I hope 8 bytes will be enough) int Size; // Value real size (should be either 1 or 2 (the number of pushes)) diff --git a/Contrib/System/Source/stdafx.h b/Contrib/System/Source/stdafx.h index 058fd207..f008744a 100644 --- a/Contrib/System/Source/stdafx.h +++ b/Contrib/System/Source/stdafx.h @@ -3,7 +3,12 @@ // are changed infrequently // +#if defined(_MSC_VER) && (_MSC_VER >= 1020) #pragma once +#endif + +#ifndef STDAFX_H +#define STDAFX_H #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files: @@ -11,3 +16,5 @@ // TODO: reference additional headers your program requires here //#define SYSTEM_LOG_DEBUG + +#endif /* STDAFX_H */ diff --git a/SCons/Config/ms b/SCons/Config/ms index 8d9d027c..e439efa3 100644 --- a/SCons/Config/ms +++ b/SCons/Config/ms @@ -20,6 +20,8 @@ if float(defenv['MSVS_VERSION'].replace('Exp','')) >= 8.0: else: defenv['EXCEPTION_FLAG'] = '/GX' +defenv.Append(ASFLAGS = ['/coff']) + ### debug if defenv['DEBUG']: diff --git a/SConstruct b/SConstruct index ec66ceea..b9722848 100644 --- a/SConstruct +++ b/SConstruct @@ -127,20 +127,8 @@ if 'msvc' in defenv['TOOLS'] or 'mstoolkit' in defenv['TOOLS']: ignore_tests = 'none' else: ignore_tests = ','.join(Split(""" -Examples/LogicLib.nsi -Examples/StrFunc.nsi -Examples/TextFunc.nsi -Examples/TextFuncTest.nsi -Examples/FileFunc.nsi -Examples/FileFuncTest.nsi -Examples/Library.nsi Examples/makensis.nsi -Examples/gfx.nsi -Examples/System/System.nsi -Examples/nsDialogs/example.nsi -Examples/nsDialogs/InstallOptions.nsi -Examples/nsDialogs/welcome.nsi""") - + ['Examples/Modern UI/WelcomeFinish.nsi']) +Examples/gfx.nsi""")) # version opts.Add(('VERSION', 'Version of NSIS', cvs_version))