├── lib ├── otcc │ ├── orig │ │ ├── test.c │ │ ├── compile.bat │ │ └── otccn.c │ ├── otccn.vcxproj.filters │ ├── otccn.sln │ ├── otccn.vcxproj │ ├── test.c │ └── otccn.c ├── LICENSE └── README ├── .gitattributes ├── .gitignore ├── test ├── Module1.bas ├── Project1.vbp └── Form1.frm ├── LICENSE ├── README.md └── src └── mdRtcc.bas /lib/otcc/orig/test.c: -------------------------------------------------------------------------------- 1 | main(n, t) { 2 | return 0x42; 3 | } -------------------------------------------------------------------------------- /lib/otcc/orig/compile.bat: -------------------------------------------------------------------------------- 1 | C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\vsvars32.bat 2 | cl -DTINY -DTEST otccn.c -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text eol=crlf 3 | 4 | *.exe -text 5 | *.dll -text 6 | *.cmp -text 7 | *.cobj -text 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## VB6 workspace 2 | 3 | *.vbw 4 | *.bak 5 | *.log 6 | *.scc 7 | *.zip 8 | *.exp 9 | *.lib 10 | *.obj 11 | *.dll 12 | *.exe 13 | *.pdb 14 | ~* 15 | *.db 16 | *.opendb 17 | *.tmp 18 | 19 | _del/ 20 | [Rr]elease/ 21 | [Dd]ebug/ 22 | .vs/ 23 | -------------------------------------------------------------------------------- /test/Module1.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "Module1" 2 | '========================================================================= 3 | ' 4 | ' Runtime Tiny C Compiler for VB6 5 | ' 6 | ' Copyright (c) 2018 by wqweto@gmail.com 7 | ' 8 | ' Thunks based on Obfuscated Tiny C Compiler 9 | ' Copyright (C) 2001-2003 Fabrice Bellard 10 | ' 11 | '========================================================================= 12 | Option Explicit 13 | DefObj A-Z 14 | 15 | Public Function CallMul(ByVal pfn As Long, ByVal lFirst As Long, ByVal lSecond As Long) As Long 16 | '--- on first call will self-patch to call `pfn` with args `lFirst` and `lSecond` directly 17 | RtccPatchProto AddressOf Module1.CallMul 18 | CallMul = CallMul(pfn, lFirst, lSecond) 19 | End Function 20 | 21 | -------------------------------------------------------------------------------- /test/Project1.vbp: -------------------------------------------------------------------------------- 1 | Type=Exe 2 | Form=Form1.frm 3 | Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\..\Windows\SysWOW64\stdole2.tlb#OLE Automation 4 | Module=mdRtcc; ..\src\mdRtcc.bas 5 | Module=Module1; Module1.bas 6 | IconForm="Form1" 7 | Startup="Form1" 8 | HelpFile="" 9 | ExeName32="Project1.exe" 10 | Command32="" 11 | Name="Project1" 12 | HelpContextID="0" 13 | CompatibleMode="0" 14 | MajorVer=1 15 | MinorVer=0 16 | RevisionVer=0 17 | AutoIncrementVer=0 18 | ServerSupportFiles=0 19 | VersionCompanyName="Unicontsoft" 20 | CompilationType=0 21 | OptimizationType=2 22 | FavorPentiumPro(tm)=0 23 | CodeViewDebugInfo=-1 24 | NoAliasing=0 25 | BoundsCheck=0 26 | OverflowCheck=0 27 | FlPointCheck=0 28 | FDIVCheck=0 29 | UnroundedFP=0 30 | StartMode=0 31 | Unattended=0 32 | Retained=0 33 | ThreadPerObject=0 34 | MaxNumberOfThreads=1 35 | -------------------------------------------------------------------------------- /lib/LICENSE: -------------------------------------------------------------------------------- 1 | Obfuscated Tiny C Compiler 2 | 3 | Copyright (C) 2001-2003 Fabrice Bellard 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product and its documentation 16 | *is* required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /lib/otcc/otccn.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Vladimir Vissoultchev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/otcc/otccn.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "otccn", "otccn.vcxproj", "{D71717B3-5B6C-47F5-BD79-F316A4AED5DF}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {D71717B3-5B6C-47F5-BD79-F316A4AED5DF}.Debug|x64.ActiveCfg = Debug|x64 17 | {D71717B3-5B6C-47F5-BD79-F316A4AED5DF}.Debug|x64.Build.0 = Debug|x64 18 | {D71717B3-5B6C-47F5-BD79-F316A4AED5DF}.Debug|x86.ActiveCfg = Debug|Win32 19 | {D71717B3-5B6C-47F5-BD79-F316A4AED5DF}.Debug|x86.Build.0 = Debug|Win32 20 | {D71717B3-5B6C-47F5-BD79-F316A4AED5DF}.Release|x64.ActiveCfg = Release|x64 21 | {D71717B3-5B6C-47F5-BD79-F316A4AED5DF}.Release|x64.Build.0 = Release|x64 22 | {D71717B3-5B6C-47F5-BD79-F316A4AED5DF}.Release|x86.ActiveCfg = Release|Win32 23 | {D71717B3-5B6C-47F5-BD79-F316A4AED5DF}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | Useful links: 2 | 3 | https://bellard.org/otcc/ 4 | http://sovietov.com/txt/otcc/otcc.html 5 | 6 | Author's Comments: 7 | 8 | OTCC is an Obfuscated Tiny C Compiler for i386-linux. It generates 9 | FAST! i386 32 bit code (no bytecode) and it is powerful enough to 10 | compile itself. OTCC supports a strict subset of C. This subset is 11 | compilable by a standard ANSI C compiler. OTCC compiles, 12 | assembles, links and runs C code without the need of any other 13 | program. 14 | 15 | You can use it by typing: 16 | 17 | ./bellard bellard.c [args]... 18 | 19 | or by giving the C source to its standard input. 20 | 21 | 'args' are given to the 'main' function of bellard.c (argv[0] is 22 | bellard.c). 23 | 24 | Examples: 25 | 26 | - Sample compilation and execution: 27 | 28 | ./bellard bellard.otccex.c 10 29 | 30 | - Self compilation: 31 | 32 | ./bellard bellard.c bellard.otccex.c 10 33 | 34 | - Self compilation iterated... 35 | 36 | ./bellard bellard.c bellard.c bellard.otccex.c 10 37 | 38 | An alternate syntax is to use it as a script interpreter: you can 39 | put '#!/usr/local/bin/otcc' at the beginning of your C source if 40 | you installed otcc at this place. 41 | 42 | Supported C language subset (read joint example 'otccex.c' to have 43 | an introduction to OTCC dialect): 44 | 45 | - Expressions: 46 | 47 | * binary operators, by decreasing priority order: '*' '/' '%', 48 | '+' '-', '>>' '<<', '<' '<=' '>' '>=', '==' '!=', '&', 49 | '^', '|', '=', '&&', '||'. 50 | 51 | * '&&' and '||' have the same semantics as C : left to right 52 | evaluation and early exit. 53 | 54 | * Parenthesis are supported. 55 | 56 | * Unary operators: '&', '*' (pointer indirection), '-' 57 | (negation), '+', '!', '~', post fixed '++' and '--'. 58 | 59 | * Pointer indirection ('*') only works with explicit cast to 60 | 'char *', 'int *' or 'int (*)()' (function pointer). 61 | 62 | * '++', '--', and unary '&' can only be used with variable 63 | lvalue (left value). 64 | 65 | * '=' can only be used with variable or '*' (pointer 66 | indirection) lvalue. 67 | 68 | * Function calls are supported with standard i386 calling 69 | convention. Function pointers are supported with explicit 70 | cast. Functions can be used before being declared. 71 | 72 | - Types: only signed integer ('int') variables and functions can 73 | be declared. Variables cannot be initialized in 74 | declarations. Only old K&R function declarations are parsed 75 | (implicit integer return value and no types on arguments). 76 | 77 | - Any function or variable from the libc can be used because OTCC 78 | uses the libc dynamic linker to resolve undefined symbols. 79 | 80 | - Instructions: blocks ('{' '}') are supported as in C. 'if' and 81 | 'else' can be used for tests. The 'while' and 'for' C constructs 82 | are supported for loops. 'break' can be used to exit 83 | loops. 'return' is used for the return value of a function. 84 | 85 | - Identifiers are parsed the same way as C. Local variables are 86 | handled, but there is no local name space (not a problem if 87 | different names are used for local and global variables). 88 | 89 | - Numbers can be entered in decimal, hexadecimal ('0x' or '0X' 90 | prefix), or octal ('0' prefix). 91 | 92 | - '#define' is supported without function like arguments. No macro 93 | recursion is tolerated. Other preprocessor directives are 94 | ignored. 95 | 96 | - C Strings and C character constants are supported. Only '\n', 97 | '\"', '\'' and '\\' escapes are recognized. 98 | 99 | - C Comments can be used (but no C++ comments). 100 | 101 | - No error is displayed if an incorrect program is given. 102 | 103 | - Memory: the code, data, and symbol sizes are limited to 100KB 104 | (it can be changed in the source code). 105 | 106 | Obfuscation: 107 | 108 | No special effort was needed because obfuscation is almost 109 | unavoidable for such a program :-) Defines must be used to 110 | compress the code, and integrated i386 code generator leads to non 111 | obvious code. 112 | 113 | Portability: 114 | 115 | OTCC only works on i386 linux because it generates i386 code. OTCC 116 | also relies on little endianness, unaligned memory accesses and 117 | ASCII representation of characters. It also supposes that no valid 118 | pointers are less than 512. If all those constraints are met, then 119 | OTCC could be theoretically used to "cross compile", although no 120 | such support is currently integrated. 121 | 122 | It was successfully compiled with gcc version 2.95.2. You get some 123 | warnings because old K&R protos are used, some casts are implicit 124 | and some functions are used before being defined. OTCC uses the 125 | dynamic linker to resolve symbols with 'dlsym()', so '-ldl' must 126 | be used as library when you compile it. 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## VbRtcc 2 | Runtime Tiny C Compiler for VB6 3 | 4 | ### Description 5 | 6 | VbRtcc is a fork of [OTCC by Fabrice Bellard](https://bellard.org/otcc/) with some additional tweaks -- relocatable code, stdcall calling convention, `short *` access, `_asm` for inline assembly, local and global arrays. 7 | 8 | ### Sample usage 9 | 10 | First download and add `src\mdRtcc.bas` to your VB6 project so that all `Rtcc` prefixed functions are accessible (see `API` section below). 11 | 12 | Here is a sample form that on button click compiles a C program that calls `GetVersionEx` API function and returns current OS version. 13 | 14 | ``` 15 | Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, Optional ByVal hWnd As Long, Optional ByVal Msg As Long, Optional ByVal wParam As Long, Optional ByVal lParam As Long) As Long 16 | 17 | Private m_ctx As UcsRtccContextType 18 | 19 | Private Sub Command1_Click() 20 | Dim pfn As Long 21 | 22 | pfn = RtccCompile(m_ctx, _ 23 | "main(n, t, wParam, lParam) {" & vbCrLf & _ 24 | " int v; " & vbCrLf & _ 25 | " v = GlobalAlloc(0x40, 148); " & vbCrLf & _ 26 | " *(int *)v = 148; " & vbCrLf & _ 27 | " GetVersionExA(v); " & vbCrLf & _ 28 | " return *(int *)(v + 4) * 100 + *(int *)(v + 8); " & vbCrLf & _ 29 | "}") 30 | Print CallWindowProc(pfn), "&H" & Hex(pfn) 31 | 32 | RtccFree m_ctx 33 | End Sub 34 | ``` 35 | All functions are compiled with stdcall calling convention and unresolved externals like `GlobalAlloc` and `GetVersionExA` are searched in currently loaded DLLs. 36 | 37 | Context `m_ctx` is reusable for additional invokations of `RtccCompile` with all previous symbols in scope, so already compiled functions can be called from subsequent compilations. 38 | 39 | Returned `pfn` are usable until `m_ctx` is destroyed with `RtccFree`. 40 | 41 | ### API 42 | 43 | - `RtccCompile([in] ctx, [in] source, [in, optional] allocsize)` 44 | 45 | If `ctx` is new initializes internal buffers according to the optional `allocsize`. Then compiles inline C `source` to `ctx`, appending generated code to previously compiled code in `ctx` and returns a callable `pfn` pointer to the entry point of the first function in `source`. 46 | 47 | - `RtccFree([in] ctx)` 48 | 49 | Deallocates `ctx` internal buffers, rendering previously compiled `pfn`s in `ctx` invalid. 50 | 51 | - `RtccGetSymbol([in] ctx, [in] name)` 52 | 53 | Searches function `name` in `ctx` and returns a callable `pfn` pointer to its entry point or `0` (`NULL`) if not found. `RtccGetSymbol` can be used when compiling sources with multiple functions that call each other because OTCC can compile calls to forward references e.g. `f` calling `g` and `g` calling `f` in a single source code. 54 | 55 | - `RtccPatchProto([in] addressof)` 56 | 57 | Helper function that patches a native VB6 function to become a `pfn` calling trampoline. For instance a VB6 function with declaration `Function MyProto(byval pfn As Long, a1 As Long, a2 As Long, ...) As Long` can be patched with a call to `RtccPatchProto AddressOf MyProto` to jump at run-time to `pfn` with arguments `a1, a2, ...`. 58 | 59 | This allows calling `RtccCompile`d `pfn` without resorting to `CallWindowProc` or similar work-arounds that are usually slower that implementing simple trampolines with `RtccPatchProto`. 60 | 61 | ### Allowed C syntax 62 | 63 | See `README` in `lib/ottc` for original Bellard's comments. 64 | 65 | - All local variables are `signed int`, including pointers. 66 | - Array indexing is not supported but global and local arrays declaration is possible. 67 | - Three types of dereferencing are allowed - `*(char *)p` for byte, `*(short *)p` for 16-bit word and `*(int *)p` for 32-bit dword. 68 | - Pointer arithmetic uses byte offset, e.g. use `*(int *)(p + 4)` to get second dword. 69 | - Shifts are signed e.g. `i = i >> 8` extends the sign bit. 70 | - Function retval/parameters are always `int` (no types allowed) e.g. `main(n, t)` returns `int` and has two `int` parameters. 71 | - Char literals are cast to dword e.g. `v = 'a'` is sign-extended 72 | - Char/strings escape allows hex values e.g. `"\x12\x5f"` and `\r`, `\n` and `\t` 73 | - Unicode char/strings allowed with `L"string"` and `L'a'` and hex word escapes with `L"\x1234\xabff"` 74 | - Supported statements: `if`/`else` `while` `for` `break` `return` 75 | - Supported operators: `+` `-` `*` `/` `%` `!` `~` `>>` `<<` `|` `&` `^` `++` `--` `&&` `||` `==` `!=` `<` `>` `<=` `>=` 76 | - Not supported operators: `+=` (and family) `?:` (ternary) `,` (comma in for loops too) 77 | - Block comments only (no `//` line comments) 78 | - `#define` supports constants only (no macro expansion) 79 | - Function `alloca` can be used for stack allocation of local arrays 80 | - Only global arrays declaration is supported w/ size in bytes e.g. `int a[100]` reserves 100 bytes (from `ctx->glob`) 81 | - `_asm _emit ` allows encoding custom instructions in codegen 82 | - `_asm mov eax, ` supported only, where `` can be const/var or complex expression 83 | 84 | ### ToDo 85 | 86 | - [x] Support `short` data type (for Unicode strings) 87 | - [x] Support inline `_asm _emit` 88 | - [x] Implement get symbol address after compile 89 | -------------------------------------------------------------------------------- /lib/otcc/otccn.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {D71717B3-5B6C-47F5-BD79-F316A4AED5DF} 23 | Win32Proj 24 | otccn 25 | 8.1 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v140 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | Level3 89 | Disabled 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | CompileAsC 92 | /Oi- /arch:IA32 %(AdditionalOptions) 93 | Cdecl 94 | false 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | 104 | 105 | Level3 106 | Disabled 107 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 108 | CompileAsC 109 | 110 | 111 | Console 112 | true 113 | 114 | 115 | 116 | 117 | Level3 118 | 119 | 120 | MaxSpeed 121 | true 122 | false 123 | TINY;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 124 | CompileAsC 125 | /Oi- /arch:IA32 %(AdditionalOptions) 126 | Cdecl 127 | false 128 | 129 | 130 | Console 131 | true 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | Level3 139 | 140 | 141 | MaxSpeed 142 | true 143 | false 144 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 145 | CompileAsC 146 | 147 | 148 | Console 149 | true 150 | true 151 | true 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /src/mdRtcc.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "mdRtcc" 2 | '========================================================================= 3 | ' 4 | ' Runtime Tiny C Compiler for VB6 5 | ' 6 | ' Copyright (c) 2018 by wqweto@gmail.com 7 | ' 8 | ' Thunks based on Obfuscated Tiny C Compiler 9 | ' Copyright (C) 2001-2003 Fabrice Bellard 10 | ' 11 | '========================================================================= 12 | Option Explicit 13 | DefObj A-Z 14 | 15 | '========================================================================= 16 | ' Thunk data 17 | '========================================================================= 18 | 19 | ' Size=7040 20 | Private Const STR_THUNK1 = _ 21 | "VYvsgeyAAAAAU4tdCFaDexQAD4WwAQAAV4t7DI11gIl7HLkfAAAAx0X4JmQqQMdFqC1AJTrHRaxfXkJLx0WwZDw8WsdFtC8wM2XHRbg+PmAvx0W8MDNlPMdFwD0wZj7HRcQ9L2Y8x0XIQC5mPsdFzEAxZj3HRdA9Jmchx0XUPSdnJsdF2CZrfHzHRdwjbCZAx0XgLkJDaMdF5F5ALkLHRehTaXxAx0XsLkIrasdF8H5ALyXHRfRZZCFAx0WAKysjbcdFhC0tJWHHRYhtKkBSx0WMPF4xY8dFkC9AJVvHRZRfW0gzx0WYYyVAJcdFnFtfW0jHRaAzYytAx0WkLkIjZGbHRfxiAPOluRQAAABmpYtDHI11qIt7BIPAfolDDMdFqCBpbnTHRawgaWYgx0WwZWxzZcdFtCB3aGnHRbhsZSBix0W8cmVha8dFwCByZXTHRcR1cm4gx0XIZm9yIMdFzHNob3LHRdB0IGFsx0XUbG9jYcdF2CBfYXPHRdxtICFf" & _ 22 | "x0XgZW1pdMdF5CAhbW/HReh2ICFlx0XsYXggZMdF8GVmaW7HRfRlIG1hZsdF+GluxkX6IPOlZqWki0MEg8BTiUMYiwOJQxRfi1UMi0M8i3MUiVNMiVNIhcB0Hg++CECJSzCJQzyD+QJ1MotDQMdDPAAAAACJQzDrIw++ColLMA++QgHB4AgDyIlLMHQIjUICiUNM6wfHQzD/////i8vorQEAADPSi8voZBUAAIvGXluL5V3DzMzMzMzMzMzMzMzMi9GLSjyFyXQgD74BiUIwjUEBg3owAolCPHU5i0JAx0I8AAAAAIlCMMNWi3JMD74OiUowD75GAcHgCAPBiUIwdAuNRgKJQkyLQjBew8dCMP////9ei0Iww8zMzMzMzMzMVovxg34wXA+FHAEAAItOPIXJdCEPvgGJRjCNQQGDfjACiUY8dTWLRkDHRjwAAAAAiUYw6yaLVkwPvgqJTjAPvkIBweAIA8GJRjB0CI1CAolGTOsHx0Yw/////4tGMIP4" & _ 23 | "bnUJx0YwCgAAAF7Dg/hydQnHRjANAAAAXsOD+HR1CcdGMAkAAABew4P4XHUFiUYwXsOD+HgPhY4AAABXi87o/f7//4v4g/85fgaDzyCD7yeLzujp/v//g/g5fgaDyCCD6CeDx83B5wQD+IN+LAB0VYtGTA++SAEPvgDB4QgDyIP5MHwFg/k5fguDySCD6WGD+QV3MYvO6KX+//+D+Dl+BoPIIIPoJ8HnBIvOA/jojv7//4P4OX4Gg8ggg+gng8fNwecEA/iJfjBfXsPMzMzMzFNWV4vxi04wg/kgdBOD+Ql0DoP5DXQJg/kKdAQz0usFugEAAAAzwIP5Iw+UwAvCD4RiAQAAg/kjD4XwAAAAi048hcl0IQ++AYlGMI1BAYN+MAKJRjx1NYtGQMdGPAAAAACJRjDrJotWTA++ColOMA++QgHB4AgDwYlGMHQIjUICiUZM6wfHRjD/////i87obf///4F+IDADAAB1IovO6F3///+LRhjGACCLRiD/RhjH" & _ 24 | "AAEAAACLTiCLRhiJQQSDfjAKdFaLThiKRjCIAf9GGItOPIXJdCEPvgGJRjCNQQGDfjACiUY8dSyLRkDHRjwAAAAAiUYw6x2LVkwPvgqJTjAPvkIBweAIA8GJRjB0T41CAolGTIN+MAp1qotOGIpGMIgB/0YYi0YYxgAC/0YYi048hcl0NA++AYlGMI1BAYN+MAKJRjwPhbr+//+LRkDHRjwAAAAAiUYw6aj+///HRjD/////6Vv///+LVkwPvgqJTjAPvkIBweAIA8GJRjB0C41CAolGTOl6/v//x0Yw/////+lu/v//g/lMdSCLRkwPvkgBD74AweEIA8GD+CJ0BYP4J3UHuAEAAADrAjPAiUYshcB0TotOPIXJdCEPvgGJRjCNQQGDfjACiUY8dTWLRkDHRjwAAAAAiUYw6yaLVkwPvgqJTjAPvkIBweAIA8GJRjB0CI1CAolGTOsHx0Yw/////4tGMIvIx0YoAAAAAIlGIIP5YXwFg/l6fhKD+UF8" & _ 25 | "BYP5Wn4IjUHQg/gJdwe6AQAAAOsCM9IzwIP5Xw+UwAvCD4QQAQAAi0YYxgAg/0YYi34YiX5Ei04wg/lhfAWD+Xp+EoP5QXwFg/lafgiNQdCD+Al3B7oBAAAA6wIz0jPAg/lfD5TAC8J0YYpGMIgH/0YYi048i34Yhcl0IQ++AYlGMI1BAYN+MAKJRjx1qItGQMdGPAAAAACJRjDrmYtWTA++ColOMA++QgHB4AgDwYlGMHQLjUICiUZM6Xf////HRjD/////6Wv///+LRiCDwNCD+AkPhrABAADGByCLVkSLTgRK6IcTAAArRgSJRiCLRhjGAACLRiCNDMUAAQAAiU4ggfkwAwAAD46OAQAAi0YQA8GJRiCDOAEPhX0BAACLQASLzolGPItGMIlGQOgO+///6Z78//+LTjyFyXQhD74BiUYwjUEBg34wAolGPHU1i0ZAx0Y8AAAAAIlGMOsmi1ZMD74KiU4wD75CAcHgCAPBiUYwdAiNQgKJRkzrB8dG" & _ 26 | "MP////+LRiCD+CcPhJUBAAAzyYP4Lw+UwTPAg34wKg+UwIXID4T2AAAAi87oj/r//4tOMIXJD4TCAAAAi348kIP5KnRIi9eF0nQgD74KQolOMIv6iVY8g/kCdSyLTkAz0jP/iVY8iU4w6x2LXkwPvguJTjAPvkMBweAIA8iJTjB0K41DAolGTIP5KnW6hf90JQ++D0eJTjCJfjyD+QJ1M4tOQDP/iX48iU4w6ybHRjD/////65GLVkwPvgqJTjAPvkIBweAIA8iJTjB0H41CAolGTIP5L3QfhckPhWD///+LzujZ+f//6Wn7//+Dyf+JTjDpSf///8dGMAAAAACLzui7+f//6Uv7//+LTkToXhIAAIlGJMdGIAIAAABfXlvDi1YcD746hf908o2bAAAAAA++WgGDwgLHRiQAAAAAD74Kg+liiU4oeRwzwOsDjUkAQELB4AYDwYlGJA++CoPpYolOKHjrM8lCO14wD5TBM8CD+0APlMALyDPAO34gD5TA" & _ 27 | "hch1Cw++OoX/daVfXlvDO14wdYiLzugl+f//X8dGIAEAAABeW8OLzsdGIAIAAADobPn//4tGMIvOiUYk6P/4//9fi85eW+n1+P//zMzMzMyF0nQUg/r/dA+LQRSIEP9BFMH6CIXSdezDzMzMzMzMzIXSdBRWi0EUizIrwoPoBIkCi9aF9nXuXsPMzMzMzMzMVovxuLgAAACD+P90D4tOFIgB/0YUwfgIhcB17ItGFIkQg0YUBF7DzMzMzMzMzMzMVovxuOkAAACD+P90D4tOFIgB/0YUwfgIhcB17ItGFIkQi0YUjUgEiU4UXsPMzMzMVYvsVovyuoXADwDrA41JAIP6/3QPi0EUiBD/QRTB+giF0nXsjZaEAAAAXoXSdBWQg/r/dA+LQRSIEP9BFMH6CIXSdeyLURSLRQiJAotBFI1QBIlRFF3DzMzMzMzMzMzMVovyujnBAACD+v90D4tBFIgQ/0EUwfoIhdJ17Lq4AAAAg/r/dA+LQRSIEP9BFMH6" & _ 28 | "CIXSdeyLQRS6DwAAAMcAAAAAAINBFASD+v90D4tBFIgQ/0EUwfoIhdJ17I2WkAAAAF6F0nQUg/r/dA+LQRSIEP9BFMH6CIXSdey6wAAAAJCD+v90D4tBFIgQ/0EUwfoIhdJ17MPMzMzMzMzMzMzMzFWL7FaL8YHCgwAAAHQWi/+D+v90D4tGFIgQ/0YUwfoIhdJ17ItVCDPAgfoAAgAAD53ASCWAAAAAg8AFdBeNSQCD+P90D4tOFIgB/0YUwfgIhcB17ItGFIkQg0YUBF5dw1WL7IPsDFNWi/GJVfRXvwEAAACJffyLXiCD+yIPhUYBAACLVgy5uAAAAI2bAAAAAIP5/3QPi0YUiAj/RhTB+QiFyXXsi0YUiRCDRhQEg34wInRxi87o9vb//4tODIpGMIgB/0YMg34sAItODHQLi0YwwfgIiAH/RgyLTjyFyXQhD74BiUYwjUEBg34wAolGPHUsi0ZAx0Y8AAAAAIlGMOsdi1ZMD74KiU4wD75CAcHg" & _ 29 | "CAPBiUYwdGKNQgKJRkyDfjAidY+DfiwAdAmLRgzGAAD/RgyLRgzGAACLRgyLTjyDwAOD4PyJRgyFyXQ6D74BiUYwjUEBg34wAolGPHVbi0ZAi87HRjwAAAAAiUYw6G73//+LXfTp3wMAAMdGMP/////pLf///4tWTA++ColOMA++QgHB4AgDwYlGMHQVjUICi86JRkzoNvf//4td9OmnAwAAx0Yw/////4vO6CD3//+LXfTpkQMAAItGKIt+JIlF+OgK9///g/sCdSy5uAAAAIP5/3QPi0YUiAj/RhTB+QiFyXXsi0YUiTi/AQAAAINGFATpUgMAAIH7SAIAAA+FjQAAAIvO6HYGAAC5g8ADAJCD+f90D4tGFIgI/0YUwfkIhcl17LmD4PwAjaQkAAAAAIP5/3QPi0YUiAj/RhTB+QiFyXXsuSnEAACNpCQAAAAAg/n/dA+LRhSICP9GFMH5CIXJdey5ieAAAI2kJAAAAACD+f8PhPABAACLRhSICP9G" & _ 30 | "FMH5CIXJdeiNeQHpuQIAAIN9+AJ1STPSi87osf3//7m5AAAAg/n/dA+LRhSICP9GFMH5CIXJdeyLRhSL14vOxwAAAAAAg0YUBIP7IQ+FBwEAAOh5/P//jXvg6WoCAACD+yh1FovO6JUFAACLzuje9f//jXvZ6U8CAACD+yoPhUgBAACLzujG9f//i14gi87ovPX//4vO6LX1//+DfiAqdR6Lzuio9f//i87oofX//4vO6Jr1//+LzuiT9f//M9uLzuiK9f//M9KLzugB/f//g34gPQ+FjwAAAIvO6HD1//+5UAAAAIP5/3QPi0YUiAj/RhTB+QiFyXXsi87oAAUAALlZAAAAg/n/dA+LRhSICP9GFMH5CIXJdeyB+xgCAAB1JblmiQEAg/n/D4S6AAAAi0YUiAj/RhTB+QiFyXXojXkB6YMBAAAz0ovOgfsAAQAAD5TCgcKIAQAA6HL6//+/AQAAAOlhAQAAhdsPhHkAAACB+wABAAB1J7mLAAAAjUkA" 31 | Private Const STR_THUNK2 = _ 32 | "g/n/dDmLRhSICP9GFMH5CIXJdez/RhSNeQHpKgEAADPSi86B+xgCAAAPlcJKgeIAAQAAgcIPvgAA6BL6////RhS/AQAAAOn+AAAAg/smdSOLRiCNU+SLzv8w6JH7//+DxASLzuhn9P//vwEAAADp1gAAAIH7EAMAAHQyixOJVfyF0nUui34IiweFwHQgjUkAi1ZEi8joJgoAAIvQiVX8hdJ1D4tHBIPHBIXAdeMz0olV/ItOIDPAg/k9D5TAhUX0dCeLzugH9P//i87osAMAAIt9/IX/dHJXugYAAACLzugM+///g8QE62CD+Sh0WIXSdBNSuggAAACLzujx+v//i1X8g8QEg34oC3U7hdJ0D1Iz0ovO6Nf6//+DxATrGbmDwAAAg/n/dA+LRhSICP9GFMH5CIXJdeyLViSLzugP+f//6Irz//+LffyDfiAoD4VtAQAAg/8BdRy5UAAAAI1JAIP5/3QPi0YUiAj/RhTB+QiFyXXsuYHsAACNpCQAAAAA" & _ 33 | "g/n/dA+LRhSICP9GFMH5CIXJdeyLRhSLzscAAAAAAItGFIlF9IPABIlGFOgg8///M/+DfiApdD+LzujBAgAAuYmEJACD+f90D4tGFIgI/0YUwfkIhcl17ItGFIk4g0YUBIN+ICx1B4vO6OLy//+DxwSDfiApdcGLRfSLzok46M3y//+LVfyF0nU0i1MEuegAAACD+f90D4tGFIgI/0YUwfkIhcl17ItGFF+JEItOFI1BBIlGFF6JSwRbi+Vdw4P6AXVVuf+UJACD+f90D4tGFIgI/0YUwfkIhcl17ItGFLmBxAAAiTiDRhQEjZsAAAAAg/n/dA+LRhSICP9GFMH5CIXJdeyLRhRfxwAEAAAAg0YUBF5bi+VdwytWFLnoAAAAg+oFg/n/dA+LRhSICP9GFMH5CIXJdeyLRhSJEINGFARfXluL5V3DzMzMzMzMzMzMVYvsg+wIVleL+ovxi8dPg/gBdQvoZ/n//19ei+Vdw4vX6Nr////HRfgAAAAAO34o" & _ 34 | "D4VpAQAAU4tGJIvOi14giUX86Lnx//+D/wh+XbmFwA8Ag/n/dA+LRhSICP9GFMH5CIXJdeyLTfyBwYQAAAB0FIP5/3QPi0YUiAj/RhTB+QiFyXXsi0YUi9eLTfiJCIvOi14UiV34jUMEiUYU6F////+LVfzpngAAALlQAAAAi/+D+f90D4tGFIgI/0YUwfkIhcl17IvXi87oM////7lZAAAAg/n/dA+LRhSICP9GFMH5CIXJdeyLVfwzyYP/BQ+UwTPAg/8ED5TAC8h0DIvO6Hz3//+LVfzrO4vKhdJ0FZCD+f90D4tGFIgI/0YUwfkIhcl17IP7JXUbuZIAAACL/4P5/3QPi0YUiAj/RhTB+QiFyXXsi134O34oD4Tn/v//hdt0SoP/CH5FU4vO6L/2//+LXfyDxASL04v4g/IB6E32//+6BQAAAIvO6HH2//+F/3QSi0YUiw8rx4PoBIkHi/mFyXXui9OLzugi9v//W19ei+Vdw8zMzMzMzMzMzMzM" & _ 35 | "ugsAAADpRv7//8zMzMzMzFa6CwAAAIvx6DP+//+5hcAPAIP5/3QPi0YUiAj/RhTB+QiFyXXsuYQAAADrA41JAIP5/3QPi0YUiAj/RhTB+QiFyXXsi0YUxwAAAAAAi0YUjUgEiU4UXsPMzMzMzMzMzFWL7FFTVovxi9pXi34ggf8gAQAAD4XPAAAA6MHv//+Lzui67///i87oc////4vOiUX86Knv//+L04vO6MD///+BfiA4AQAAdXWLzuiQ7///uekAAACD+f90D4tGFIgI/0YUwfkIhcl17ItGFMcAAAAAAIt+FItV/I1HBIlGFIXSdBKLRhSLCivCg+gEiQKL0YXJde6L04vO6GP///+F/w+E9AIAAItGFIsPK8eD6ASJB4v5hcl17l9eW4vlXcOLVfyF0g+E0AIAAI2kJAAAAACLRhSLCivCg+gEiQKL0YXJde5fXluL5V3DM8mB//gBAAAPlMEzwIH/YAEAAA+UwAvID4TyAAAAi87o0u7//4vO" & _ 36 | "6Mvu//+B/2ABAAB1D4teFIvO6Hn+//+JRfzrcIN+IDt0DLoLAAAAi87oovz//4vO6Jvu//+DfiA7i14Ux0X8AAAAAHQKi87oRP7//4lF/IvO6Hru//+DfiApdDAz0ovO6Fv0//+6CwAAAIvOi/joXfz//yteFIvOjVP76ED0//+L14vO6Ofz//+NXwSLzug97v//jVX8i87oU/7//yteFLnpAAAAg+sFg/n/dA+LRhSICP9GFMH5CIXJdeyLRhSJGINGFASLVfyF0g+EuQEAAItGFIsKK8KD6ASJAovRhcl17l9eW4vlXcOB/4ACAAAPhdYAAACLRgTGQDYgi0YExkA9IItGBMZAQiA5fiAPhZwAAACLzui27f//i0YgPbACAAB1VovO6KXt//+DfiAodQeLzuiY7f//g34gAnUti04khcl1C/9GFOsajZsAAAAAg/n/dA+LRhSICP9GFMH5CIXJdeyLzuhl7f//g34gKXUxi87oWO3//+soPegCAAB1" & _ 37 | "IYvO6Ejt//+LzuhB7f//i87oOu3//7oLAAAAi87oLvv//4F+IIACAAAPhGT///+LRgRfxkA2IYtGBMZAPSGLRgReW8ZAQiGL5V3Dg/97dT2Lzuj57P//jVeGi87orwAAAIN+IH0PhJcAAADrA41JAIvTi87o9/z//4N+IH118YvO6Mrs//9fXluL5V3Dgf/AAQAAdTSLzui07P//g34gO3QMugsAAACLzuii+v//i1Y0i87oiPL//4vOiUY06I7s//9fXluL5V3Dgf+QAQAAdSCLzuh47P//ixOLzuhf8v//i86JA+hm7P//X15bi+Vdw4P/O3QMugsAAACLzuhO+v//i87oR+z//19eW4vlXcNVi+yD7AgzwFOL2oXbiV38VovxD5TAM8mJRfhXg34g/w+VwSPIM8CBfiAAAQAAD5TAC8gPhOwBAACNpCQAAAAAi1YggfoAAQAAD4WMAAAAi87o6uv//4N+IDt0c41kJACF23QXg0Y4BItOOItGIPfZ" & _ 38 | "iQiLzujH6///60GLTiCLRgyJAYvO6Lbr//+DfiBbdSiLzuip6///i04ki0YMg8EDA8GLzoPg/IlGDOiR6///i87oiuv//+sEg0YMBIN+ICx1B4vO6Hfr//+DfiA7dZGLzuhq6///6SoBAACLUgSF0nQSi0YUiworwoPoBIkCi9GFyXXui04gi0YUiQGLzug96///i87oNuv//4N+ICm/CAAAAHQii0Ygi86JOIPHBOgc6///g34gLHUHi87oD+v//4N+ICl13ovO6ALr///HRjgAAAAAuVWJ5QDHRjQAAAAAg/n/dA+LRhSICP9GFMH5CIXJdey5gewAAI2bAAAAAIP5/3QPi0YUiAj/RhTB+QiFyXXsi0YUM9KLzscAAAAAAIteFI1DBIlGFOjB+v//i1Y0hdJ0EotGFIsKK8KD6ASJAovRhcl17rnJAAAAjUkAg/n/dA+LRhSICP9GFMH5CIXJdeyDx/i5wgAAAI1kJACD+f90D4tGFIgI/0YUwfkI" & _ 39 | "hcl17ItGFIk4g0YUAotGOIkDi138M9KDfiD/D5XCM8AjVfiBfiAAAQAAD5TAC9APhRv+//9fXluL5V3DzMzMzFWL7IPsEFZXi/mJVfyLRzyLRDh4A8eLcCCF9nUIXzPAXovlXcNTi1gcjQw+A9+JTfiJXfAz9otYJAPfiV30i1gYhdt+P4sEsYvKA8eNZCQAihE6EHUahNJ0EopRATpQAXUOg8ECg8AChNJ15DPA6wUbwIPIAYXAdBSLVfxGi034O/N8wVtfM8Bei+Vdw4tF9ItN8FsPtwRwiwSBA8dfXovlXcPMzMzMzMzMzMzMzMzMVYvsg+wMU4vaiU34VovRiV30V41LAYoDQ4TAdfmKAivZhMB0UotN9Iv6K/mKIYhl/zrEdTaL84vRhdt0F41JAA++BBeNUgEPvkr/TivBdQ6F9nXsi0X4X15bi+Vdw4XAdPKLVfiLTfSKZf+KQgFCR4lV+ITAdbpfXjPAW4vlXcNTVooZD77Dg/ggdA+D+Al0" & _ 40 | "CoP4DXQFg/gKdQNB6+Qz9oD7MHU+gHkBeHU1g8ECi/+KEY1JAYD6MHwFgPo5fhSK2oDLII1DnzwFdzWA+jl+A41T2YPG/Q++wsHmBAPw69CA+zB8G41JAYD7OX8TD77DjTS2ihmNduiNNHCA+zB95YvGXlvDzMzMzMzMzMzMzMw=" 41 | 42 | '========================================================================= 43 | ' API 44 | '========================================================================= 45 | 46 | '--- for VirtualAlloc 47 | Private Const PAGE_EXECUTE_READWRITE As Long = &H40 48 | Private Const MEM_COMMIT As Long = &H1000 49 | Private Const MEM_RELEASE As Long = &H8000 50 | '--- for CryptStringToBinary 51 | Private Const CRYPT_STRING_BASE64 As Long = 1 52 | 53 | Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long) 54 | Private Declare Function VirtualAlloc Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long 55 | Private Declare Function VirtualFree Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long 56 | Private Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, ByRef lpflOldProtect As Long) As Long 57 | Private Declare Function CryptStringToBinary Lib "crypt32" Alias "CryptStringToBinaryW" (ByVal pszString As Long, ByVal cchString As Long, ByVal dwFlags As Long, ByVal pbBinary As Long, ByRef pcbBinary As Long, ByRef pdwSkip As Long, ByRef pdwFlags As Long) As Long 58 | Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, Optional ByVal Msg As Long, Optional ByVal wParam As Long, Optional ByVal lParam As Long) As Long 59 | Private Declare Function GetCurrentProcess Lib "kernel32" () As Long 60 | Private Declare Function EnumProcessModules Lib "psapi" (ByVal hProcess As Long, lphModule As Any, ByVal cb As Long, lpcbNeeded As Any) As Long 61 | Private Declare Function StrStrA Lib "shlwapi" (ByVal pszFirst As Long, ByVal pszSrch As String) As Long 62 | 63 | '========================================================================= 64 | ' Constants and member variables 65 | '========================================================================= 66 | 67 | Private Const ALLOC_SIZE As Long = 2 ^ 15 68 | 69 | Private Type UcsRtccBufferType 70 | m_data() As Byte 71 | End Type 72 | 73 | Public Type UcsRtccContextType 74 | m_prog As Long 75 | m_sym_stk As Long 76 | m_mods As Long 77 | m_glo As Long 78 | m_vars As Long 79 | m_state(0 To 31) As Long 80 | m_buffer(0 To 3) As UcsRtccBufferType 81 | End Type 82 | 83 | '========================================================================= 84 | ' Functions 85 | '========================================================================= 86 | 87 | Public Function RtccCompile(ctx As UcsRtccContextType, sSource As String, Optional ByVal AllocSize As Long = ALLOC_SIZE) As Long 88 | If ctx.m_prog = 0 Then 89 | ctx.m_prog = VirtualAlloc(0, AllocSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE) 90 | ReDim ctx.m_buffer(0).m_data(0 To AllocSize - 1) As Byte 91 | ctx.m_sym_stk = VarPtr(ctx.m_buffer(0).m_data(0)) 92 | ReDim ctx.m_buffer(1).m_data(0 To AllocSize - 1) As Byte 93 | ctx.m_glo = VarPtr(ctx.m_buffer(1).m_data(0)) 94 | ReDim ctx.m_buffer(2).m_data(0 To AllocSize * 8 - 1) As Byte 95 | ctx.m_vars = VarPtr(ctx.m_buffer(2).m_data(0)) 96 | ReDim ctx.m_buffer(3).m_data(0 To 4000 - 1) As Byte 97 | ctx.m_mods = VarPtr(ctx.m_buffer(3).m_data(0)) 98 | Call EnumProcessModules(GetCurrentProcess(), ByVal ctx.m_mods, 1000, ByVal 0) 99 | End If 100 | RtccCompile = CallWindowProc(pvGetThunkAddress, VarPtr(ctx), StrPtr(sSource)) 101 | End Function 102 | 103 | Public Sub RtccFree(ctx As UcsRtccContextType) 104 | Dim uEmpty As UcsRtccContextType 105 | 106 | If ctx.m_prog <> 0 Then 107 | Call VirtualFree(ctx.m_prog, 0, MEM_RELEASE) 108 | ctx = uEmpty 109 | End If 110 | End Sub 111 | 112 | Public Function RtccGetSymbol(ctx As UcsRtccContextType, sName As String) As Long 113 | Dim lPtr As Long 114 | 115 | lPtr = StrStrA(ctx.m_sym_stk, " " & sName & " ") 116 | If lPtr <> 0 Then 117 | lPtr = UnsignedAdd(ctx.m_vars, UnsignedDiff(ctx.m_sym_stk, lPtr) * 8 + &H100) 118 | Call CopyMemory(RtccGetSymbol, ByVal lPtr, 4) 119 | End If 120 | End Function 121 | 122 | Public Sub RtccPatchProto(ByVal pfn As Long) '--- Helper by The trick 123 | Dim bInIDE As Boolean 124 | 125 | Debug.Assert pvSetTrue(bInIDE) 126 | If bInIDE Then 127 | Call CopyMemory(pfn, ByVal UnsignedAdd(pfn, &H16), 4) 128 | Else 129 | Call VirtualProtect(pfn, 8, PAGE_EXECUTE_READWRITE, 0) 130 | End If 131 | ' 0: 58 pop eax 132 | ' 1: 59 pop ecx 133 | ' 2: 50 push eax 134 | ' 3: ff e1 jmp ecx 135 | ' 5: 90 nop 136 | ' 6: 90 nop 137 | ' 7: 90 nop 138 | Call CopyMemory(ByVal pfn, -802975883527609.7192@, 8) 139 | End Sub 140 | 141 | '= private =============================================================== 142 | 143 | Private Function pvGetThunkAddress() As Long 144 | Static lpThunk As Long 145 | Dim baThunk() As Byte 146 | 147 | If lpThunk = 0 Then 148 | baThunk = FromBase64Array(STR_THUNK1 & STR_THUNK2) 149 | lpThunk = VirtualAlloc(0, UBound(baThunk) + 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE) 150 | Call CopyMemory(ByVal lpThunk, baThunk(0), UBound(baThunk) + 1) 151 | End If 152 | pvGetThunkAddress = lpThunk 153 | End Function 154 | 155 | Private Function FromBase64Array(sText As String) As Byte() 156 | Dim lSize As Long 157 | Dim dwDummy As Long 158 | Dim baOutput() As Byte 159 | 160 | Call CryptStringToBinary(StrPtr(sText), Len(sText), CRYPT_STRING_BASE64, 0, lSize, 0, dwDummy) 161 | ReDim baOutput(0 To lSize - 1) As Byte 162 | Call CryptStringToBinary(StrPtr(sText), Len(sText), CRYPT_STRING_BASE64, VarPtr(baOutput(0)), lSize, 0, dwDummy) 163 | FromBase64Array = baOutput 164 | End Function 165 | 166 | Private Function pvSetTrue(bValue As Boolean) As Boolean 167 | bValue = True 168 | pvSetTrue = True 169 | End Function 170 | 171 | Private Function UnsignedAdd(ByVal lUnsignedPtr As Long, ByVal lSignedOffset As Long) As Long 172 | '--- note: safely add *signed* offset to *unsigned* ptr for *unsigned* retval w/o overflow in LARGEADDRESSAWARE processes 173 | UnsignedAdd = ((lUnsignedPtr Xor &H80000000) + lSignedOffset) Xor &H80000000 174 | End Function 175 | 176 | Private Function UnsignedDiff(ByVal lUnsignedPtr1 As Long, ByVal lUnsignedPtr2 As Long) As Long 177 | '--- note: retval is *signed* offset b/n *unsigned* ptr1 and *unsigned* ptr2 w/o overflow in LARGEADDRESSAWARE processes 178 | If (lUnsignedPtr1 Xor lUnsignedPtr2) < 0 Then 179 | UnsignedDiff = (lUnsignedPtr2 - (lUnsignedPtr1 Xor &H80000000)) Xor &H80000000 180 | Else 181 | UnsignedDiff = lUnsignedPtr2 - lUnsignedPtr1 182 | End If 183 | End Function 184 | -------------------------------------------------------------------------------- /lib/otcc/orig/otccn.c: -------------------------------------------------------------------------------- 1 | /* 2 | Obfuscated Tiny C Compiler 3 | 4 | Copyright (C) 2001-2003 Fabrice Bellard 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product and its documentation 17 | *is* required. 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 3. This notice may not be removed or altered from any source distribution. 21 | */ 22 | #ifndef TINY 23 | #include 24 | #endif 25 | #include 26 | 27 | /* vars: value of variables 28 | loc : local variable index 29 | glo : global variable index 30 | ind : output code ptr 31 | rsym: return symbol 32 | prog: output code 33 | dstk: define stack 34 | dptr, dch: macro state 35 | */ 36 | int tok, tokc, tokl, ch, vars, rsym, prog, ind, loc, glo, file, sym_stk, dstk, dptr, dch, last_id; 37 | 38 | #define ALLOC_SIZE 99999 39 | 40 | /* depends on the init string */ 41 | #define TOK_STR_SIZE 48 42 | #define TOK_IDENT 0x100 43 | #define TOK_INT 0x100 44 | #define TOK_IF 0x120 45 | #define TOK_ELSE 0x138 46 | #define TOK_WHILE 0x160 47 | #define TOK_BREAK 0x190 48 | #define TOK_RETURN 0x1c0 49 | #define TOK_FOR 0x1f8 50 | #define TOK_DEFINE 0x218 51 | #define TOK_MAIN 0x250 52 | 53 | #define TOK_DUMMY 1 54 | #define TOK_NUM 2 55 | 56 | #define LOCAL 0x200 57 | 58 | #define SYM_FORWARD 0 59 | #define SYM_DEFINE 1 60 | 61 | /* tokens in string heap */ 62 | #define TAG_TOK ' ' 63 | #define TAG_MACRO 2 64 | 65 | pdef(t) 66 | { 67 | *(char *)dstk++ = t; 68 | } 69 | 70 | inp() 71 | { 72 | if (dptr) { 73 | ch = *(char *)dptr++; 74 | if (ch == TAG_MACRO) { 75 | dptr = 0; 76 | ch = dch; 77 | } 78 | } else 79 | ch = fgetc(file); 80 | /* printf("ch=%c 0x%x\n", ch, ch); */ 81 | } 82 | 83 | isid() 84 | { 85 | return isalnum(ch) | ch == '_'; 86 | } 87 | 88 | /* read a character constant */ 89 | getq() 90 | { 91 | if (ch == '\\') { 92 | inp(); 93 | if (ch == 'n') 94 | ch = '\n'; 95 | } 96 | } 97 | 98 | next() 99 | { 100 | int t, l, a; 101 | 102 | while (isspace(ch) | ch == '#') { 103 | if (ch == '#') { 104 | inp(); 105 | next(); 106 | if (tok == TOK_DEFINE) { 107 | next(); 108 | pdef(TAG_TOK); /* fill last ident tag */ 109 | *(int *)tok = SYM_DEFINE; 110 | *(int *)(tok + 4) = dstk; /* define stack */ 111 | } 112 | /* well we always save the values ! */ 113 | while (ch != '\n') { 114 | pdef(ch); 115 | inp(); 116 | } 117 | pdef(ch); 118 | pdef(TAG_MACRO); 119 | } 120 | inp(); 121 | } 122 | tokl = 0; 123 | tok = ch; 124 | /* encode identifiers & numbers */ 125 | if (isid()) { 126 | pdef(TAG_TOK); 127 | last_id = dstk; 128 | while (isid()) { 129 | pdef(ch); 130 | inp(); 131 | } 132 | if (isdigit(tok)) { 133 | tokc = strtol(last_id, 0, 0); 134 | tok = TOK_NUM; 135 | } else { 136 | *(char *)dstk = TAG_TOK; /* no need to mark end of string (we 137 | suppose data is initied to zero */ 138 | tok = strstr(sym_stk, last_id - 1) - sym_stk; 139 | *(char *)dstk = 0; /* mark real end of ident for dlsym() */ 140 | tok = tok * 8 + TOK_IDENT; 141 | if (tok > TOK_DEFINE) { 142 | tok = vars + tok; 143 | /* printf("tok=%s %x\n", last_id, tok); */ 144 | /* define handling */ 145 | if (*(int *)tok == SYM_DEFINE) { 146 | dptr = *(int *)(tok + 4); 147 | dch = ch; 148 | inp(); 149 | next(); 150 | } 151 | } 152 | } 153 | } else { 154 | inp(); 155 | if (tok == '\'') { 156 | tok = TOK_NUM; 157 | getq(); 158 | tokc = ch; 159 | inp(); 160 | inp(); 161 | } else if (tok == '/' & ch == '*') { 162 | inp(); 163 | while (ch) { 164 | while (ch != '*') 165 | inp(); 166 | inp(); 167 | if (ch == '/') 168 | ch = 0; 169 | } 170 | inp(); 171 | next(); 172 | } else 173 | { 174 | t = "++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<>`/03e<=0f>=/f<@.f>@1f==&g!=\'g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b"; 175 | while (l = *(char *)t++) { 176 | a = *(char *)t++; 177 | tokc = 0; 178 | while ((tokl = *(char *)t++ - 'b') < 0) 179 | tokc = tokc * 64 + tokl + 64; 180 | if (l == tok & (a == ch | a == '@')) { 181 | #if 0 182 | printf("%c%c -> tokl=%d tokc=0x%x\n", 183 | l, a, tokl, tokc); 184 | #endif 185 | if (a == ch) { 186 | inp(); 187 | tok = TOK_DUMMY; /* dummy token for double tokens */ 188 | } 189 | break; 190 | } 191 | } 192 | } 193 | } 194 | #if 0 195 | { 196 | int p; 197 | 198 | printf("tok=0x%x ", tok); 199 | if (tok >= TOK_IDENT) { 200 | printf("'"); 201 | if (tok > TOK_DEFINE) 202 | p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8; 203 | else 204 | p = sym_stk + 1 + (tok - TOK_IDENT) / 8; 205 | while (*(char *)p != TAG_TOK && *(char *)p) 206 | printf("%c", *(char *)p++); 207 | printf("'\n"); 208 | } else if (tok == TOK_NUM) { 209 | printf("%d\n", tokc); 210 | } else { 211 | printf("'%c'\n", tok); 212 | } 213 | } 214 | #endif 215 | } 216 | 217 | #ifdef TINY 218 | #define skip(c) next() 219 | #else 220 | 221 | void error(char *fmt,...) 222 | { 223 | va_list ap; 224 | 225 | va_start(ap, fmt); 226 | fprintf(stderr, "%d: ", ftell((FILE *)file)); 227 | vfprintf(stderr, fmt, ap); 228 | fprintf(stderr, "\n"); 229 | exit(1); 230 | va_end(ap); 231 | } 232 | 233 | void skip(c) 234 | { 235 | if (tok != c) { 236 | error("'%c' expected", c); 237 | } 238 | next(); 239 | } 240 | 241 | #endif 242 | 243 | o(n) 244 | { 245 | /* cannot use unsigned, so we must do a hack */ 246 | while (n && n != -1) { 247 | *(char *)ind++ = n; 248 | n = n >> 8; 249 | } 250 | } 251 | 252 | /* output a symbol and patch all calls to it */ 253 | gsym(t) 254 | { 255 | int n; 256 | while (t) { 257 | n = *(int *)t; /* next value */ 258 | *(int *)t = ind - t - 4; 259 | t = n; 260 | } 261 | } 262 | 263 | /* psym is used to put an instruction with a data field which is a 264 | reference to a symbol. It is in fact the same as oad ! */ 265 | #define psym oad 266 | 267 | /* instruction + address */ 268 | oad(n, t) 269 | { 270 | o(n); 271 | *(int *)ind = t; 272 | t = ind; 273 | ind = ind + 4; 274 | return t; 275 | } 276 | 277 | /* load immediate value */ 278 | li(t) 279 | { 280 | oad(0xb8, t); /* mov $xx, %eax */ 281 | } 282 | 283 | gjmp(t) 284 | { 285 | return psym(0xe9, t); 286 | } 287 | 288 | /* l = 0: je, l == 1: jne */ 289 | gtst(l, t) 290 | { 291 | o(0x0fc085); /* test %eax, %eax, je/jne xxx */ 292 | return psym(0x84 + l, t); 293 | } 294 | 295 | gcmp(t) 296 | { 297 | o(0xc139); /* cmp %eax,%ecx */ 298 | li(0); 299 | o(0x0f); /* setxx %al */ 300 | o(t + 0x90); 301 | o(0xc0); 302 | } 303 | 304 | gmov(l, t) 305 | { 306 | o(l + 0x83); 307 | oad((t < LOCAL) << 7 | 5, t); 308 | } 309 | 310 | /* l is one if '=' parsing wanted (quick hack) */ 311 | unary(l) 312 | { 313 | int n, t, a, c; 314 | 315 | n = 1; /* type of expression 0 = forward, 1 = value, other = 316 | lvalue */ 317 | if (tok == '\"') { 318 | li(glo); 319 | while (ch != '\"') { 320 | getq(); 321 | *(char *)glo++ = ch; 322 | inp(); 323 | } 324 | *(char *)glo = 0; 325 | glo = glo + 4 & -4; /* align heap */ 326 | inp(); 327 | next(); 328 | } else { 329 | c = tokl; 330 | a = tokc; 331 | t = tok; 332 | next(); 333 | if (t == TOK_NUM) { 334 | li(a); 335 | } else if (c == 2) { 336 | /* -, +, !, ~ */ 337 | unary(0); 338 | oad(0xb9, 0); /* movl $0, %ecx */ 339 | if (t == '!') 340 | gcmp(a); 341 | else 342 | o(a); 343 | } else if (t == '(') { 344 | expr(); 345 | skip(')'); 346 | } else if (t == '*') { 347 | /* parse cast */ 348 | skip('('); 349 | t = tok; /* get type */ 350 | next(); /* skip int/char/void */ 351 | next(); /* skip '*' or '(' */ 352 | if (tok == '*') { 353 | /* function type */ 354 | skip('*'); 355 | skip(')'); 356 | skip('('); 357 | skip(')'); 358 | t = 0; 359 | } 360 | skip(')'); 361 | unary(0); 362 | if (tok == '=') { 363 | next(); 364 | o(0x50); /* push %eax */ 365 | expr(); 366 | o(0x59); /* pop %ecx */ 367 | o(0x0188 + (t == TOK_INT)); /* movl %eax/%al, (%ecx) */ 368 | } else if (t) { 369 | if (t == TOK_INT) 370 | o(0x8b); /* mov (%eax), %eax */ 371 | else 372 | o(0xbe0f); /* movsbl (%eax), %eax */ 373 | ind++; /* add zero in code */ 374 | } 375 | } else if (t == '&') { 376 | gmov(10, *(int *)tok); /* leal EA, %eax */ 377 | next(); 378 | } else { 379 | n = *(int *)t; 380 | /* forward reference: try dlsym */ 381 | /*if (!n) 382 | n = dlsym(0, last_id);*/ 383 | if (tok == '=' & l) { 384 | /* assignment */ 385 | next(); 386 | expr(); 387 | gmov(6, n); /* mov %eax, EA */ 388 | } else if (tok != '(') { 389 | /* variable */ 390 | gmov(8, n); /* mov EA, %eax */ 391 | if (tokl == 11) { 392 | gmov(0, n); 393 | o(tokc); 394 | next(); 395 | } 396 | } 397 | } 398 | } 399 | 400 | /* function call */ 401 | if (tok == '(') { 402 | if (n == 1) 403 | o(0x50); /* push %eax */ 404 | 405 | /* push args and invert order */ 406 | a = oad(0xec81, 0); /* sub $xxx, %esp */ 407 | next(); 408 | l = 0; 409 | while(tok != ')') { 410 | expr(); 411 | oad(0x248489, l); /* movl %eax, xxx(%esp) */ 412 | if (tok == ',') 413 | next(); 414 | l = l + 4; 415 | } 416 | *(int *)a = l; 417 | next(); 418 | if (!n) { 419 | /* forward reference */ 420 | t = t + 4; 421 | *(int *)t = psym(0xe8, *(int *)t); 422 | } else if (n == 1) { 423 | oad(0x2494ff, l); /* call *xxx(%esp) */ 424 | l = l + 4; 425 | } else { 426 | oad(0xe8, n - ind - 5); /* call xxx */ 427 | } 428 | if (l) 429 | oad(0xc481, l); /* add $xxx, %esp */ 430 | } 431 | } 432 | 433 | sum(l) 434 | { 435 | int t, n, a; 436 | 437 | if (l-- == 1) 438 | unary(1); 439 | else { 440 | sum(l); 441 | a = 0; 442 | while (l == tokl) { 443 | n = tok; 444 | t = tokc; 445 | next(); 446 | 447 | if (l > 8) { 448 | a = gtst(t, a); /* && and || output code generation */ 449 | sum(l); 450 | } else { 451 | o(0x50); /* push %eax */ 452 | sum(l); 453 | o(0x59); /* pop %ecx */ 454 | 455 | if (l == 4 | l == 5) { 456 | gcmp(t); 457 | } else { 458 | o(t); 459 | if (n == '%') 460 | o(0x92); /* xchg %edx, %eax */ 461 | } 462 | } 463 | } 464 | /* && and || output code generation */ 465 | if (a && l > 8) { 466 | a = gtst(t, a); 467 | li(t ^ 1); 468 | gjmp(5); /* jmp $ + 5 */ 469 | gsym(a); 470 | li(t); 471 | } 472 | } 473 | } 474 | 475 | expr() 476 | { 477 | sum(11); 478 | } 479 | 480 | 481 | test_expr() 482 | { 483 | expr(); 484 | return gtst(0, 0); 485 | } 486 | 487 | block(l) 488 | { 489 | int a, n, t; 490 | 491 | if (tok == TOK_IF) { 492 | next(); 493 | skip('('); 494 | a = test_expr(); 495 | skip(')'); 496 | block(l); 497 | if (tok == TOK_ELSE) { 498 | next(); 499 | n = gjmp(0); /* jmp */ 500 | gsym(a); 501 | block(l); 502 | gsym(n); /* patch else jmp */ 503 | } else { 504 | gsym(a); /* patch if test */ 505 | } 506 | } else if (tok == TOK_WHILE | tok == TOK_FOR) { 507 | t = tok; 508 | next(); 509 | skip('('); 510 | if (t == TOK_WHILE) { 511 | n = ind; 512 | a = test_expr(); 513 | } else { 514 | if (tok != ';') 515 | expr(); 516 | skip(';'); 517 | n = ind; 518 | a = 0; 519 | if (tok != ';') 520 | a = test_expr(); 521 | skip(';'); 522 | if (tok != ')') { 523 | t = gjmp(0); 524 | expr(); 525 | gjmp(n - ind - 5); 526 | gsym(t); 527 | n = t + 4; 528 | } 529 | } 530 | skip(')'); 531 | block(&a); 532 | gjmp(n - ind - 5); /* jmp */ 533 | gsym(a); 534 | } else if (tok == '{') { 535 | next(); 536 | /* declarations */ 537 | decl(1); 538 | while(tok != '}') 539 | block(l); 540 | next(); 541 | } else { 542 | if (tok == TOK_RETURN) { 543 | next(); 544 | if (tok != ';') 545 | expr(); 546 | rsym = gjmp(rsym); /* jmp */ 547 | } else if (tok == TOK_BREAK) { 548 | next(); 549 | *(int *)l = gjmp(*(int *)l); 550 | } else if (tok != ';') 551 | expr(); 552 | skip(';'); 553 | } 554 | } 555 | 556 | /* 'l' is true if local declarations */ 557 | decl(l) 558 | { 559 | int a; 560 | 561 | while (tok == TOK_INT | tok != -1 & !l) { 562 | if (tok == TOK_INT) { 563 | next(); 564 | while (tok != ';') { 565 | if (l) { 566 | loc = loc + 4; 567 | *(int *)tok = -loc; 568 | } else { 569 | *(int *)tok = glo; 570 | glo = glo + 4; 571 | } 572 | next(); 573 | if (tok == ',') 574 | next(); 575 | } 576 | skip(';'); 577 | } else { 578 | /* patch forward references (XXX: do not work for function 579 | pointers) */ 580 | gsym(*(int *)(tok + 4)); 581 | /* put function address */ 582 | *(int *)tok = ind; 583 | next(); 584 | skip('('); 585 | a = 8; 586 | while (tok != ')') { 587 | /* read param name and compute offset */ 588 | *(int *)tok = a; 589 | a = a + 4; 590 | next(); 591 | if (tok == ',') 592 | next(); 593 | } 594 | next(); /* skip ')' */ 595 | rsym = loc = 0; 596 | o(0xe58955); /* push %ebp, mov %esp, %ebp */ 597 | a = oad(0xec81, 0); /* sub $xxx, %esp */ 598 | block(0); 599 | gsym(rsym); 600 | o(0xc3c9); /* leave, ret */ 601 | *(int *)a = loc; /* save local variables */ 602 | } 603 | } 604 | } 605 | 606 | main(n, t) 607 | { 608 | file = stdin; 609 | if (n-- > 1) { 610 | t = t + 4; 611 | file = fopen(*(int *)t, "r"); 612 | } 613 | dstk = strcpy(sym_stk = calloc(1, ALLOC_SIZE), 614 | " int if else while break return for define main ") + TOK_STR_SIZE; 615 | glo = calloc(1, ALLOC_SIZE); 616 | ind = prog = calloc(1, ALLOC_SIZE); 617 | vars = calloc(1, ALLOC_SIZE); 618 | inp(); 619 | next(); 620 | decl(0); 621 | #ifdef TEST 622 | { 623 | FILE *f; 624 | f = fopen(*(char **)(t + 4), "w"); 625 | fwrite((void *)prog, 1, ind - prog, f); 626 | fclose(f); 627 | return 0; 628 | } 629 | #else 630 | return (*(int (*)())*(int *)(vars + TOK_MAIN)) (n, t); 631 | #endif 632 | } -------------------------------------------------------------------------------- /test/Form1.frm: -------------------------------------------------------------------------------- 1 | VERSION 5.00 2 | Begin VB.Form Form1 3 | AutoRedraw = -1 'True 4 | Caption = "Form1" 5 | ClientHeight = 2592 6 | ClientLeft = 108 7 | ClientTop = 456 8 | ClientWidth = 6732 9 | LinkTopic = "Form1" 10 | ScaleHeight = 2592 11 | ScaleWidth = 6732 12 | StartUpPosition = 3 'Windows Default 13 | Begin VB.CommandButton Command3 14 | Caption = "Command3" 15 | Height = 516 16 | Left = 4536 17 | TabIndex = 2 18 | Top = 1848 19 | Width = 1860 20 | End 21 | Begin VB.CommandButton Command2 22 | Caption = "Command2" 23 | Height = 516 24 | Left = 4536 25 | TabIndex = 1 26 | Top = 1176 27 | Width = 1860 28 | End 29 | Begin VB.CommandButton Command1 30 | Caption = "Command1" 31 | Height = 516 32 | Left = 4536 33 | TabIndex = 0 34 | Top = 504 35 | Width = 1860 36 | End 37 | End 38 | Attribute VB_Name = "Form1" 39 | Attribute VB_GlobalNameSpace = False 40 | Attribute VB_Creatable = False 41 | Attribute VB_PredeclaredId = True 42 | Attribute VB_Exposed = False 43 | '========================================================================= 44 | ' 45 | ' Runtime Tiny C Compiler for VB6 46 | ' 47 | ' Copyright (c) 2018 by wqweto@gmail.com 48 | ' 49 | ' Thunks based on Obfuscated Tiny C Compiler 50 | ' Copyright (C) 2001-2003 Fabrice Bellard 51 | ' 52 | '========================================================================= 53 | Option Explicit 54 | DefObj A-Z 55 | 56 | Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, Optional ByVal hWnd As Long, Optional ByVal Msg As Long, Optional ByVal wParam As Long, Optional ByVal lParam As Long) As Long 57 | 58 | Private m_ctx As UcsRtccContextType 59 | 60 | Private Sub Command1_Click() 61 | Dim pfn As Long 62 | 63 | pfn = RtccCompile(m_ctx, _ 64 | "main(n, t, wParam, lParam) {" & vbCrLf & _ 65 | " int v; " & vbCrLf & _ 66 | " v = GlobalAlloc(0x40, 148); " & vbCrLf & _ 67 | " *(int *)v = 148; " & vbCrLf & _ 68 | " GetVersionExA(v); " & vbCrLf & _ 69 | " return *(int *)(v + 4) * 100 + *(int *)(v + 8); " & vbCrLf & _ 70 | "}") 71 | Debug.Assert RtccGetSymbol(m_ctx, "main") = pfn 72 | 73 | Print CallWindowProc(pfn), "&H" & Hex(pfn) 74 | 75 | pfn = RtccCompile(m_ctx, _ 76 | "mul(a, b) {" & vbCrLf & _ 77 | " return a*b;" & vbCrLf & _ 78 | "}") 79 | Debug.Assert RtccGetSymbol(m_ctx, "mul") = pfn 80 | 81 | Print CallMul(pfn, 13, 20), "&H" & Hex(pfn) 82 | End Sub 83 | 84 | Private Sub Command2_Click() 85 | RtccFree m_ctx 86 | End Sub 87 | 88 | Private Sub Command3_Click() 89 | Dim lIdx As Long 90 | Dim sExpr As String 91 | Dim dblTimer As Double 92 | Dim dblResult As Double 93 | 94 | sExpr = "(3.5) + 2.9*(2+(1+2))" 95 | dblTimer = Timer 96 | For lIdx = 1 To 1000000 97 | dblResult = SimpleEval(sExpr) 98 | Next 99 | Print "SimpleEval: " & dblResult, Format(Timer - dblTimer, "0.000") 100 | End Sub 101 | 102 | Private Function SimpleEval(sText As String) As Double 103 | Dim src As String 104 | 105 | If m_ctx.m_state(31) = 0 Then 106 | src = src & _ 107 | "#define TOK_FINAL 0" & vbCrLf & _ 108 | "#define TOK_RPAREN 1" & vbCrLf & _ 109 | "#define TOK_ADD 2" & vbCrLf & _ 110 | "#define TOK_MOD 3" & vbCrLf & _ 111 | "#define TOK_IDIV 4" & vbCrLf & _ 112 | "#define TOK_MUL 5" & vbCrLf & _ 113 | "#define TOK_UNARY 6" & vbCrLf & _ 114 | "#define TOK_POWER 7" & vbCrLf & _ 115 | "#define TOK_LPAREN 8" & vbCrLf & _ 116 | "#define TOK_NUM 9" & vbCrLf & _ 117 | "#define TOK_WHITE 10" & vbCrLf & _ 118 | "" & vbCrLf & _ 119 | "int lookup[256];" & vbCrLf & _ 120 | "" & vbCrLf & _ 121 | "simple_eval(s, pdbl, wParam, lParam)" & vbCrLf & _ 122 | "{" & vbCrLf & _ 123 | " int i, p, l, ch, prec, prev_pr;" & vbCrLf & _ 124 | " int op_stack, op_idx;" & vbCrLf & _ 125 | " int val_stack, val_idx;" & vbCrLf 126 | src = src & _ 127 | " int num_size;" & vbCrLf & _ 128 | "" & vbCrLf & _ 129 | " op_idx = op_stack = alloca(4000);" & vbCrLf & _ 130 | " val_idx = val_stack = alloca(8000);" & vbCrLf & _ 131 | " l = &lookup;" & vbCrLf & _ 132 | " if (*(char *)(l + 32) == 0) {" & vbCrLf & _ 133 | " p = l;" & vbCrLf & _ 134 | " i = 0;" & vbCrLf & _ 135 | " while (i < 256) {" & vbCrLf & _ 136 | " *(char *)p++ = TOK_WHITE;" & vbCrLf & _ 137 | " i++;" & vbCrLf & _ 138 | " }" & vbCrLf & _ 139 | " *(char *)(l + '(') = TOK_LPAREN;" & vbCrLf & _ 140 | " *(char *)(l + ')') = TOK_RPAREN;" & vbCrLf & _ 141 | " *(char *)(l + '+') = TOK_ADD;" & vbCrLf & _ 142 | " *(char *)(l + '-') = TOK_ADD;" & vbCrLf & _ 143 | " *(char *)(l + '*') = TOK_MUL;" & vbCrLf & _ 144 | " *(char *)(l + '/') = TOK_MUL;" & vbCrLf & _ 145 | " *(char *)(l + '^') = TOK_POWER;" & vbCrLf & _ 146 | " *(char *)(l + '\\') = TOK_IDIV;" & vbCrLf & _ 147 | " *(char *)(l + '%') = TOK_MOD;" & vbCrLf & _ 148 | " *(char *)(l + '.') = TOK_NUM;" & vbCrLf 149 | src = src & _ 150 | " p = l + '0';" & vbCrLf & _ 151 | " i = '0';" & vbCrLf & _ 152 | " while (i <= '9') {" & vbCrLf & _ 153 | " *(char *)p++ = TOK_NUM;" & vbCrLf & _ 154 | " i++;" & vbCrLf & _ 155 | " }" & vbCrLf & _ 156 | " }" & vbCrLf & _ 157 | " prev_pr = 0;" & vbCrLf & _ 158 | " p = s;" & vbCrLf & _ 159 | " while ((ch = *(short *)p)) {" & vbCrLf & _ 160 | " if (!(ch >> 8)) {" & vbCrLf & _ 161 | " prec = *(char *)(l + ch);" & vbCrLf & _ 162 | " if (prec != TOK_WHITE) {" & vbCrLf & _ 163 | " if (prec == TOK_NUM) {" & vbCrLf & _ 164 | " val_idx = val_idx + 8;" & vbCrLf & _ 165 | " parse_num(p, val_idx, &num_size);" & vbCrLf & _ 166 | " p = p + ((num_size-1) << 1);" & vbCrLf & _ 167 | " } else if (prec == TOK_ADD) {" & vbCrLf & _ 168 | " if (prev_pr >= TOK_ADD && prev_pr < TOK_NUM)" & vbCrLf & _ 169 | " prec = TOK_UNARY;" & vbCrLf 170 | src = src & _ 171 | " }" & vbCrLf & _ 172 | " if (prec >= TOK_ADD && prec < TOK_NUM) {" & vbCrLf & _ 173 | " if(prec != TOK_UNARY)" & vbCrLf & _ 174 | " eval_stack(prec, op_stack, &op_idx, val_stack, &val_idx);" & vbCrLf & _ 175 | " op_idx = op_idx + 4;" & vbCrLf & _ 176 | " *(int *)op_idx = (prec << 16) + ch;" & vbCrLf & _ 177 | " }" & vbCrLf & _ 178 | " prev_pr = prec;" & vbCrLf & _ 179 | " }" & vbCrLf & _ 180 | " }" & vbCrLf & _ 181 | " p++; p++;" & vbCrLf & _ 182 | " }" & vbCrLf & _ 183 | " eval_stack(TOK_FINAL, op_stack, &op_idx, val_stack, &val_idx);" & vbCrLf & _ 184 | " *(int *)pdbl = *(int *)val_idx;" & vbCrLf & _ 185 | " *(int *)(pdbl + 4) = *(int *)(val_idx + 4);" & vbCrLf & _ 186 | "}" & vbCrLf & _ 187 | "" & vbCrLf 188 | src = src & _ 189 | "#define ASM_MOV_EAX_ _asm mov eax," & vbCrLf & _ 190 | "#define ASM_ADD_EAX_ _asm _emit 0x83 _asm _emit 0xc0 _asm _emit" & vbCrLf & _ 191 | "#define ASM_SUB_EAX_ _asm _emit 0x83 _asm _emit 0xe8 _asm _emit" & vbCrLf & _ 192 | "#define ASM_FSTP_EAX _asm _emit 0xdd _asm _emit 0x18" & vbCrLf & _ 193 | "#define ASM_FLD_EAX _asm _emit 0xdd _asm _emit 0x00" & vbCrLf & _ 194 | "#define ASM_FLD_EAX_ _asm _emit 0xdd _asm _emit 0x40 _asm _emit" & vbCrLf & _ 195 | "#define ASM_FADD_EAX_ _asm _emit 0xdc _asm _emit 0x40 _asm _emit" & vbCrLf & _ 196 | "#define ASM_FSUB_EAX_ _asm _emit 0xdc _asm _emit 0x60 _asm _emit" & vbCrLf & _ 197 | "#define ASM_FMUL_EAX_ _asm _emit 0xdc _asm _emit 0x48 _asm _emit" & vbCrLf & _ 198 | "#define ASM_FDIV_EAX_ _asm _emit 0xdc _asm _emit 0x70 _asm _emit" & vbCrLf & _ 199 | "#define ASM_FCHS _asm _emit 0xd9 _asm _emit 0xe0" & vbCrLf & _ 200 | "#define ASM_FILD_EAX _asm _emit 0xdb _asm _emit 0x00" & vbCrLf & _ 201 | "#define ASM_FISTP_EAX _asm _emit 0xdb _asm _emit 0x18" & vbCrLf & _ 202 | "#define ASM_FYL2X _asm _emit 0xd9 _asm _emit 0xf1" & vbCrLf & _ 203 | "#define ASM_FLD1 _asm _emit 0xd9 _asm _emit 0xe8" & vbCrLf & _ 204 | "#define ASM_FLD_ST1 _asm _emit 0xd9 _asm _emit 0xc1" & vbCrLf & _ 205 | "#define ASM_FPREM _asm _emit 0xd9 _asm _emit 0xf8" & vbCrLf & _ 206 | "#define ASM_F2XM1 _asm _emit 0xd9 _asm _emit 0xf0" & vbCrLf & _ 207 | "#define ASM_FADDP_ST1 _asm _emit 0xde _asm _emit 0xc1" & vbCrLf & _ 208 | "#define ASM_FSCALE _asm _emit 0xd9 _asm _emit 0xfd" & vbCrLf 209 | src = src & _ 210 | "" & vbCrLf & _ 211 | "eval_stack(prec, op_stack, pop_idx, val_stack, pval_idx)" & vbCrLf & _ 212 | "{" & vbCrLf & _ 213 | " int op_idx, val_idx, op, t1, pt1, t2, pt2;" & vbCrLf & _ 214 | "" & vbCrLf & _ 215 | " op_idx = *(int *)pop_idx;" & vbCrLf & _ 216 | " val_idx = *(int *)pval_idx;" & vbCrLf & _ 217 | " while (op_idx > op_stack) {" & vbCrLf & _ 218 | " if (*(int *)(op_idx) < (prec << 16))" & vbCrLf & _ 219 | " break;" & vbCrLf & _ 220 | " val_idx = val_idx - 8;" & vbCrLf & _ 221 | " op = *(short *)op_idx;" & vbCrLf & _ 222 | " if (op == '+') {" & vbCrLf & _ 223 | " if (*(int *)(op_idx) > (TOK_UNARY << 16)) {" & vbCrLf & _ 224 | " val_idx = val_idx + 8;" & vbCrLf & _ 225 | " } else {" & vbCrLf & _ 226 | " /* *(double *)val_idx = *(double *)val_idx + *(double *)(val_idx + 8); */" & vbCrLf & _ 227 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 228 | " ASM_FLD_EAX;" & vbCrLf & _ 229 | " ASM_FADD_EAX_(8);" & vbCrLf & _ 230 | " ASM_FSTP_EAX;" & vbCrLf & _ 231 | " }" & vbCrLf 232 | src = src & _ 233 | " } else if (op == '-') {" & vbCrLf & _ 234 | " if (*(int *)(op_idx) > (TOK_UNARY << 16)) {" & vbCrLf & _ 235 | " val_idx = val_idx + 8;" & vbCrLf & _ 236 | " /* *(double *)val_idx = -*(double *)val_idx; */" & vbCrLf & _ 237 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 238 | " ASM_FLD_EAX;" & vbCrLf & _ 239 | " ASM_FCHS;" & vbCrLf & _ 240 | " ASM_FSTP_EAX;" & vbCrLf & _ 241 | " } else {" & vbCrLf & _ 242 | " /* *(double *)val_idx = *(double *)val_idx - *(double *)(val_idx + 8); */" & vbCrLf & _ 243 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 244 | " ASM_FLD_EAX;" & vbCrLf & _ 245 | " ASM_FSUB_EAX_(8);" & vbCrLf & _ 246 | " ASM_FSTP_EAX;" & vbCrLf & _ 247 | " }" & vbCrLf & _ 248 | " } else if (op == '*') {" & vbCrLf & _ 249 | " /* *(double *)val_idx = *(double *)val_idx * *(double *)(val_idx + 8); */" & vbCrLf & _ 250 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 251 | " ASM_FLD_EAX;" & vbCrLf 252 | src = src & _ 253 | " ASM_FMUL_EAX_(8);" & vbCrLf & _ 254 | " ASM_FSTP_EAX;" & vbCrLf & _ 255 | " } else if (op == '/') {" & vbCrLf & _ 256 | " /* *(double *)val_idx = *(double *)val_idx / *(double *)(val_idx + 8); */" & vbCrLf & _ 257 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 258 | " ASM_FLD_EAX;" & vbCrLf & _ 259 | " ASM_FDIV_EAX_(8);" & vbCrLf & _ 260 | " ASM_FSTP_EAX;" & vbCrLf & _ 261 | " } else if (op == '^') {" & vbCrLf & _ 262 | " /* *(double *)val_idx = pow(*(double *)val_idx, *(double *)(val_idx + 8)); */" & vbCrLf & _ 263 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 264 | " ASM_ADD_EAX_(8);" & vbCrLf & _ 265 | " ASM_FLD_EAX;" & vbCrLf & _ 266 | " ASM_SUB_EAX_(8);" & vbCrLf & _ 267 | " ASM_FLD_EAX;" & vbCrLf & _ 268 | " ASM_FYL2X;" & vbCrLf & _ 269 | " ASM_FLD1;" & vbCrLf & _ 270 | " ASM_FLD_ST1;" & vbCrLf & _ 271 | " ASM_FPREM;" & vbCrLf & _ 272 | " ASM_F2XM1;" & vbCrLf & _ 273 | " ASM_FADDP_ST1;" & vbCrLf & _ 274 | " ASM_FSCALE;" & vbCrLf & _ 275 | " ASM_FSTP_EAX;" & vbCrLf 276 | src = src & _ 277 | " } else if (op == '\\') {" & vbCrLf & _ 278 | " pt1 = &t1;" & vbCrLf & _ 279 | " /* *(double *)val_idx = (int)(*(double *)val_idx / *(double *)(val_idx + 8)); */" & vbCrLf & _ 280 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 281 | " ASM_FLD_EAX;" & vbCrLf & _ 282 | " ASM_FDIV_EAX_(8);" & vbCrLf & _ 283 | " ASM_MOV_EAX_(pt1);" & vbCrLf & _ 284 | " ASM_FISTP_EAX;" & vbCrLf & _ 285 | " ASM_FILD_EAX;" & vbCrLf & _ 286 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 287 | " ASM_FSTP_EAX;" & vbCrLf & _ 288 | " } else if (op == '%') {" & vbCrLf & _ 289 | " pt1 = &t1;" & vbCrLf & _ 290 | " pt2 = &t2;" & vbCrLf & _ 291 | " /* *(double *)val_idx = (int)*(double *)val_idx % (int)*(double *)(val_idx + 8); */" & vbCrLf & _ 292 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 293 | " ASM_FLD_EAX;" & vbCrLf & _ 294 | " ASM_MOV_EAX_(pt1);" & vbCrLf & _ 295 | " ASM_FISTP_EAX;" & vbCrLf & _ 296 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 297 | " ASM_ADD_EAX_(8);" & vbCrLf 298 | src = src & _ 299 | " ASM_FLD_EAX;" & vbCrLf & _ 300 | " ASM_MOV_EAX_(pt2);" & vbCrLf & _ 301 | " ASM_FISTP_EAX;" & vbCrLf & _ 302 | " t1 = t1 % t2;" & vbCrLf & _ 303 | " ASM_MOV_EAX_(pt1);" & vbCrLf & _ 304 | " ASM_FILD_EAX;" & vbCrLf & _ 305 | " ASM_MOV_EAX_(val_idx);" & vbCrLf & _ 306 | " ASM_FSTP_EAX;" & vbCrLf & _ 307 | " } else if (op == '(') {" & vbCrLf & _ 308 | " val_idx = val_idx + 8;" & vbCrLf & _ 309 | " if (prec == TOK_RPAREN) {" & vbCrLf & _ 310 | " op_idx = op_idx - 4;" & vbCrLf & _ 311 | " break;" & vbCrLf & _ 312 | " } else if (prec > TOK_RPAREN)" & vbCrLf & _ 313 | " break;" & vbCrLf & _ 314 | " }" & vbCrLf & _ 315 | " op_idx = op_idx - 4;" & vbCrLf & _ 316 | " }" & vbCrLf & _ 317 | " *(int *)pval_idx = val_idx;" & vbCrLf & _ 318 | " *(int *)pop_idx = op_idx;" & vbCrLf & _ 319 | "}" & vbCrLf & _ 320 | "" & vbCrLf 321 | src = src & _ 322 | "#define PARSE_FLAGS_DEFAULT 0xB14" & vbCrLf & _ 323 | "#define VTBIT_R8 0x20" & vbCrLf & _ 324 | "" & vbCrLf & _ 325 | "parse_num(s, pdbl, psize)" & vbCrLf & _ 326 | "{" & vbCrLf & _ 327 | " int numparse, dig, variant_res;" & vbCrLf & _ 328 | "" & vbCrLf & _ 329 | " numparse = alloca(24);" & vbCrLf & _ 330 | " dig = alloca(30);" & vbCrLf & _ 331 | " variant_res = alloca(16);" & vbCrLf & _ 332 | " *(int *)numparse = 30;" & vbCrLf & _ 333 | " *(int *)(numparse + 4) = PARSE_FLAGS_DEFAULT;" & vbCrLf & _ 334 | " if (!VarParseNumFromStr(s, 0, 0, numparse, dig)) {" & vbCrLf & _ 335 | " if (!VarNumFromParseNum(numparse, dig, VTBIT_R8, variant_res)) {" & vbCrLf & _ 336 | " *(int *)pdbl = *(int *)(variant_res + 8);" & vbCrLf & _ 337 | " *(int *)(pdbl + 4) = *(int *)(variant_res + 12);" & vbCrLf & _ 338 | " *(int *)psize = *(int *)(numparse + 12); /* cchUsed */" & vbCrLf & _ 339 | " return;" & vbCrLf & _ 340 | " }" & vbCrLf & _ 341 | " }" & vbCrLf & _ 342 | " *(int *)pdbl = 0;" & vbCrLf & _ 343 | " *(int *)(pdbl + 4) = 0;" & vbCrLf & _ 344 | " *(int *)psize = 1;" & vbCrLf & _ 345 | "}" 346 | m_ctx.m_state(31) = RtccCompile(m_ctx, src) 347 | End If 348 | CallWindowProc m_ctx.m_state(31), StrPtr(sText), VarPtr(SimpleEval) 349 | End Function 350 | 351 | -------------------------------------------------------------------------------- /lib/otcc/test.c: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | char m_sym_stk[ALLOC_SIZE] = { 0 }; 8 | char m_glo[ALLOC_SIZE] = { 0 }; 9 | char m_vars[ALLOC_SIZE] = { 0 }; 10 | char m_mods[1000] = { 0 }; 11 | 12 | #pragma comment(lib, "ole32") 13 | int __stdcall CoInitialize(int); 14 | #pragma comment(lib, "oleaut32") 15 | int __stdcall VarParseNumFromStr(int, int, int, int, int); 16 | int __stdcall VarNumFromParseNum(int, int, int, int); 17 | 18 | test(n, t) { 19 | struct ctx_t _ctx = { 0 }, *ctx = &_ctx; 20 | int pinp, pfn; 21 | 22 | EnumProcessModules(GetCurrentProcess(), m_mods, sizeof(m_mods) / sizeof(int), 0); 23 | ctx->prog = VirtualAlloc(0, ALLOC_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 24 | ctx->sym_stk = m_sym_stk; 25 | ctx->glo = m_glo; 26 | ctx->vars = m_vars; 27 | ctx->mods = m_mods; 28 | //pinp = L"main2(n, t) { int v, c; c = L\"\\x12\\x34AAtest\"; v = GlobalAlloc(0x40, 148); *(int *)v = 148; GetVersionExA(v); return *(int *)(v + 4) * 100 + *(int *)(v + 8); }"; 29 | //pfn = compile(ctx, pinp, 0, 0); 30 | //pinp = L"main(n, t) { int v; v = GlobalAlloc(0x40, 148); *(int *)v = 148; GetVersionExA(v); return *(int *)(v + 4) * 100 + *(int *)(v + 8); }"; 31 | //pfn = compile(ctx, pinp, 0, 0); 32 | //return (*(int (__stdcall *)())pfn)(n, t); 33 | //pinp = L"int a, b[100]; main(n, t) { int v, c; v = alloca(550); emit 0x90 0x90; *(int *)v = 55; c = L\"\\x12AF\\x34AAtest\"; eax = *(short *)c; if((eax & 2) != 2) eax = eax + eax; return eax; }"; 34 | pinp = 35 | L"#define TOK_FINAL 0\n" 36 | L"#define TOK_RPAREN 1\n" 37 | L"#define TOK_ADD 2\n" 38 | L"#define TOK_MOD 3\n" 39 | L"#define TOK_IDIV 4\n" 40 | L"#define TOK_MUL 5\n" 41 | L"#define TOK_UNARY 6\n" 42 | L"#define TOK_POWER 7\n" 43 | L"#define TOK_LPAREN 8\n" 44 | L"#define TOK_NUM 9\n" 45 | L"#define TOK_WHITE 10\n" 46 | L"\n" 47 | L"int lookup[256];\n" 48 | L"\n" 49 | L"simple_eval(s, pdbl)\n" 50 | L"{\n" 51 | L" int i, p, l, ch, prec, prev_pr;\n" 52 | L" int op_stack, op_idx;\n" 53 | L" int val_stack, val_idx;\n" 54 | L"\n" 55 | L" op_idx = op_stack = alloca(4000);\n" 56 | L" val_idx = val_stack = alloca(8000);\n" 57 | L" l = &lookup;\n" 58 | L" if (*(char *)(l + 32) == 0) {\n" 59 | L" p = l;\n" 60 | L" i = 0;\n" 61 | L" while (i < 256) {\n" 62 | L" *(char *)p++ = TOK_WHITE;\n" 63 | L" i++;\n" 64 | L" }\n" 65 | L" *(char *)(l + '(') = TOK_LPAREN;\n" 66 | L" *(char *)(l + ')') = TOK_RPAREN;\n" 67 | L" *(char *)(l + '+') = TOK_ADD;\n" 68 | L" *(char *)(l + '-') = TOK_ADD;\n" 69 | L" *(char *)(l + '*') = TOK_MUL;\n" 70 | L" *(char *)(l + '/') = TOK_MUL;\n" 71 | L" *(char *)(l + '^') = TOK_POWER;\n" 72 | L" *(char *)(l + '\\\\') = TOK_IDIV;\n" 73 | L" *(char *)(l + '%') = TOK_MOD;\n" 74 | L" *(char *)(l + '.') = TOK_NUM;\n" 75 | L" p = l + '0';\n" 76 | L" i = '0';\n" 77 | L" while (i <= '9') {\n" 78 | L" *(char *)p++ = TOK_NUM;\n" 79 | L" i++;\n" 80 | L" }\n" 81 | L" }\n" 82 | L" prev_pr = 0;\n" 83 | L" p = s;\n" 84 | L" while ((ch = *(short *)p)) {\n" 85 | L" if (!(ch >> 8)) {\n" 86 | L" prec = *(char *)(l + ch);\n" 87 | L" if (prec != TOK_WHITE) {\n" 88 | L" if (prec == TOK_NUM) {\n" 89 | L" val_idx = val_idx + 8;\n" 90 | L" p = fast_val(p, val_idx);\n" 91 | L" } else if (prec == TOK_ADD) {\n" 92 | L" if (prev_pr >= TOK_ADD && prev_pr < TOK_NUM)\n" 93 | L" prec = TOK_UNARY;\n" 94 | L" }\n" 95 | L" if (prec >= TOK_ADD && prec < TOK_NUM) {\n" 96 | L" if(prec != TOK_UNARY)\n" 97 | L" eval_stack(prec, op_stack, &op_idx, val_stack, &val_idx);\n" 98 | L" op_idx = op_idx + 4;\n" 99 | L" *(int *)op_idx = (prec << 16) + ch;\n" 100 | L" }\n" 101 | L" prev_pr = prec;\n" 102 | L" }\n" 103 | L" }\n" 104 | L" p++; p++;\n" 105 | L" }\n" 106 | L" eval_stack(TOK_FINAL, op_stack, &op_idx, val_stack, &val_idx);\n" 107 | L" *(int *)pdbl = *(int *)val_idx;\n" 108 | L" *(int *)(pdbl + 4) = *(int *)(val_idx + 4);\n" 109 | L"}\n" 110 | L"\n" 111 | L"#define ASM_MOV_EAX_ _asm mov eax,\n" 112 | L"#define ASM_ADD_EAX_ _asm _emit 0x83 _asm _emit 0xc0 _asm _emit\n" 113 | L"#define ASM_SUB_EAX_ _asm _emit 0x83 _asm _emit 0xe8 _asm _emit\n" 114 | L"#define ASM_FSTP_EAX _asm _emit 0xdd _asm _emit 0x18\n" 115 | L"#define ASM_FLD_EAX _asm _emit 0xdd _asm _emit 0x00\n" 116 | L"#define ASM_FLD_EAX_ _asm _emit 0xdd _asm _emit 0x40 _asm _emit\n" 117 | L"#define ASM_FADD_EAX _asm _emit 0xdc _asm _emit 0x00\n" 118 | L"#define ASM_FADD_EAX_ _asm _emit 0xdc _asm _emit 0x40 _asm _emit\n" 119 | L"#define ASM_FADDP_ST1 _asm _emit 0xde _asm _emit 0xc1\n" 120 | L"#define ASM_FSUB_EAX_ _asm _emit 0xdc _asm _emit 0x60 _asm _emit\n" 121 | L"#define ASM_FMUL_EAX _asm _emit 0xdc _asm _emit 0x08\n" 122 | L"#define ASM_FMUL_EAX_ _asm _emit 0xdc _asm _emit 0x48 _asm _emit\n" 123 | L"#define ASM_FMULP_ST1 _asm _emit 0xde _asm _emit 0xc9\n" 124 | L"#define ASM_FDIV_EAX _asm _emit 0xdc _asm _emit 0x30\n" 125 | L"#define ASM_FDIV_EAX_ _asm _emit 0xdc _asm _emit 0x70 _asm _emit\n" 126 | L"#define ASM_FCHS _asm _emit 0xd9 _asm _emit 0xe0\n" 127 | L"#define ASM_FILD_EAX _asm _emit 0xdb _asm _emit 0x00\n" 128 | L"#define ASM_FISTP_EAX _asm _emit 0xdb _asm _emit 0x18\n" 129 | L"#define ASM_FYL2X _asm _emit 0xd9 _asm _emit 0xf1\n" 130 | L"#define ASM_FLD1 _asm _emit 0xd9 _asm _emit 0xe8\n" 131 | L"#define ASM_FLD_ST1 _asm _emit 0xd9 _asm _emit 0xc1\n" 132 | L"#define ASM_FPREM _asm _emit 0xd9 _asm _emit 0xf8\n" 133 | L"#define ASM_F2XM1 _asm _emit 0xd9 _asm _emit 0xf0\n" 134 | L"#define ASM_FSCALE _asm _emit 0xd9 _asm _emit 0xfd\n" 135 | L"#define ASM_FLDZ _asm _emit 0xd9 _asm _emit 0xee\n" 136 | L"\n" 137 | L"eval_stack(prec, op_stack, pop_idx, val_stack, pval_idx)\n" 138 | L"{\n" 139 | L" int op_idx, val_idx, op, t1, pt1, t2, pt2;\n" 140 | L"\n" 141 | L" op_idx = *(int *)pop_idx;\n" 142 | L" val_idx = *(int *)pval_idx;\n" 143 | L" while (op_idx > op_stack) {\n" 144 | L" if (*(int *)(op_idx) < (prec << 16))\n" 145 | L" break;\n" 146 | L" val_idx = val_idx - 8;\n" 147 | L" op = *(short *)op_idx;\n" 148 | L" if (op == '+') {\n" 149 | L" if (*(int *)(op_idx) > (TOK_UNARY << 16)) {\n" 150 | L" val_idx = val_idx + 8;\n" 151 | L" } else {\n" 152 | L" /* *(double *)val_idx = *(double *)val_idx + *(double *)(val_idx + 8); */\n" 153 | L" ASM_MOV_EAX_(val_idx);\n" 154 | L" ASM_FLD_EAX;\n" 155 | L" ASM_FADD_EAX_(8);\n" 156 | L" ASM_FSTP_EAX;\n" 157 | L" }\n" 158 | L" } else if (op == '-') {\n" 159 | L" if (*(int *)(op_idx) > (TOK_UNARY << 16)) {\n" 160 | L" val_idx = val_idx + 8;\n" 161 | L" /* *(double *)val_idx = -*(double *)val_idx; */\n" 162 | L" ASM_MOV_EAX_(val_idx);\n" 163 | L" ASM_FLD_EAX;\n" 164 | L" ASM_FCHS;\n" 165 | L" ASM_FSTP_EAX;\n" 166 | L" } else {\n" 167 | L" /* *(double *)val_idx = *(double *)val_idx - *(double *)(val_idx + 8); */\n" 168 | L" ASM_MOV_EAX_(val_idx);\n" 169 | L" ASM_FLD_EAX;\n" 170 | L" ASM_FSUB_EAX_(8);\n" 171 | L" ASM_FSTP_EAX;\n" 172 | L" }\n" 173 | L" } else if (op == '*') {\n" 174 | L" /* *(double *)val_idx = *(double *)val_idx * *(double *)(val_idx + 8); */\n" 175 | L" ASM_MOV_EAX_(val_idx);\n" 176 | L" ASM_FLD_EAX;\n" 177 | L" ASM_FMUL_EAX_(8);\n" 178 | L" ASM_FSTP_EAX;\n" 179 | L" } else if (op == '/') {\n" 180 | L" /* *(double *)val_idx = *(double *)val_idx / *(double *)(val_idx + 8); */\n" 181 | L" ASM_MOV_EAX_(val_idx);\n" 182 | L" ASM_FLD_EAX;\n" 183 | L" ASM_FDIV_EAX_(8);\n" 184 | L" ASM_FSTP_EAX;\n" 185 | L" } else if (op == '^') {\n" 186 | L" /* *(double *)val_idx = pow(*(double *)val_idx, *(double *)(val_idx + 8)); */\n" 187 | L" ASM_MOV_EAX_(val_idx);\n" 188 | L" ASM_ADD_EAX_(8);\n" 189 | L" ASM_FLD_EAX;\n" 190 | L" ASM_SUB_EAX_(8);\n" 191 | L" ASM_FLD_EAX;\n" 192 | L" ASM_FYL2X;\n" 193 | L" ASM_FLD1;\n" 194 | L" ASM_FLD_ST1;\n" 195 | L" ASM_FPREM;\n" 196 | L" ASM_F2XM1;\n" 197 | L" ASM_FADDP_ST1;\n" 198 | L" ASM_FSCALE;\n" 199 | L" ASM_FSTP_EAX;\n" 200 | L" } else if (op == '\\\\') {\n" 201 | L" pt1 = &t1;\n" 202 | L" /* *(double *)val_idx = (int)(*(double *)val_idx / *(double *)(val_idx + 8)); */\n" 203 | L" ASM_MOV_EAX_(val_idx);\n" 204 | L" ASM_FLD_EAX;\n" 205 | L" ASM_FDIV_EAX_(8);\n" 206 | L" ASM_MOV_EAX_(pt1);\n" 207 | L" ASM_FISTP_EAX;\n" 208 | L" ASM_FILD_EAX;\n" 209 | L" ASM_MOV_EAX_(val_idx);\n" 210 | L" ASM_FSTP_EAX;\n" 211 | L" } else if (op == '%') {\n" 212 | L" pt1 = &t1;\n" 213 | L" pt2 = &t2;\n" 214 | L" /* *(double *)val_idx = (int)*(double *)val_idx % (int)*(double *)(val_idx + 8); */\n" 215 | L" ASM_MOV_EAX_(val_idx);\n" 216 | L" ASM_FLD_EAX;\n" 217 | L" ASM_MOV_EAX_(pt1);\n" 218 | L" ASM_FISTP_EAX;\n" 219 | L" ASM_MOV_EAX_(val_idx);\n" 220 | L" ASM_ADD_EAX_(8);\n" 221 | L" ASM_FLD_EAX;\n" 222 | L" ASM_MOV_EAX_(pt2);\n" 223 | L" ASM_FISTP_EAX;\n" 224 | L" t1 = t1 % t2;\n" 225 | L" ASM_MOV_EAX_(pt1);\n" 226 | L" ASM_FILD_EAX;\n" 227 | L" ASM_MOV_EAX_(val_idx);\n" 228 | L" ASM_FSTP_EAX;\n" 229 | L" } else if (op == '(') {\n" 230 | L" val_idx = val_idx + 8;\n" 231 | L" if (prec == TOK_RPAREN) {\n" 232 | L" op_idx = op_idx - 4;\n" 233 | L" break;\n" 234 | L" } else if (prec > TOK_RPAREN)\n" 235 | L" break;\n" 236 | L" }\n" 237 | L" op_idx = op_idx - 4;\n" 238 | L" }\n" 239 | L" *(int *)pval_idx = val_idx;\n" 240 | L" *(int *)pop_idx = op_idx;\n" 241 | L"}\n" 242 | L"\n" 243 | L"fast_val(p, pdbl)\n" 244 | L"{\n" 245 | L" int ch, addr;\n" 246 | L" int newval, esgn, eint, hasfrac;\n" 247 | L" int intpart, fracpart, fracdiv, dbl10; /* doubles */\n" 248 | L"\n" 249 | L" intpart = alloca(8);\n" 250 | L" fracpart = alloca(8);\n" 251 | L" fracdiv = alloca(8);\n" 252 | L" dbl10 = alloca(8);\n" 253 | L" newval = esgn = hasfrac = 0;\n" 254 | L" /* *(double *)intpart = *(double *)fracpart = 0 */\n" 255 | L" ASM_FLDZ;\n" 256 | L" ASM_MOV_EAX_(intpart);\n" 257 | L" ASM_FSTP_EAX;\n" 258 | L" ASM_FLDZ;\n" 259 | L" ASM_MOV_EAX_(fracpart);\n" 260 | L" ASM_FSTP_EAX;\n" 261 | L" /* *(double *)fracdiv = 1 */\n" 262 | L" ASM_FLD1;\n" 263 | L" ASM_MOV_EAX_(fracdiv);\n" 264 | L" ASM_FSTP_EAX;\n" 265 | L" /* *(double *)dbl10 = 10 */\n" 266 | L" ch = 10;\n" 267 | L" addr = &ch;\n" 268 | L" ASM_MOV_EAX_(addr);\n" 269 | L" ASM_FILD_EAX;\n" 270 | L" ASM_MOV_EAX_(dbl10);\n" 271 | L" ASM_FSTP_EAX;\n" 272 | L" while ((ch = *(short *)p)) {\n" 273 | L" if (ch >= '0' && ch <= '9') {\n" 274 | L" newval = 1;\n" 275 | L" if (esgn) {\n" 276 | L" eint = eint * 10 + ch - '0';\n" 277 | L" } else {\n" 278 | L" ch = ch - '0';\n" 279 | L" if(!hasfrac) {\n" 280 | L" /* *(double *)intpart = *(double *)intpart * *(double*)dbl10 + ch; */\n" 281 | L" ASM_MOV_EAX_(intpart);\n" 282 | L" ASM_FLD_EAX;\n" 283 | L" ASM_MOV_EAX_(dbl10);\n" 284 | L" ASM_FMUL_EAX;\n" 285 | L" addr = &ch;\n" 286 | L" ASM_MOV_EAX_(addr);\n" 287 | L" ASM_FILD_EAX;\n" 288 | L" ASM_FADDP_ST1;\n" 289 | L" ASM_MOV_EAX_(intpart);\n" 290 | L" ASM_FSTP_EAX\n" 291 | L" } else {\n" 292 | L" /* *(double *)fracpart = *(double *)fracpart * *(double*)dbl10 + ch; */\n" 293 | L" ASM_MOV_EAX_(fracpart);\n" 294 | L" ASM_FLD_EAX;\n" 295 | L" ASM_MOV_EAX_(dbl10);\n" 296 | L" ASM_FMUL_EAX;\n" 297 | L" addr = &ch;\n" 298 | L" ASM_MOV_EAX_(addr);\n" 299 | L" ASM_FILD_EAX;\n" 300 | L" ASM_FADDP_ST1;\n" 301 | L" ASM_MOV_EAX_(fracpart);\n" 302 | L" ASM_FSTP_EAX\n" 303 | L" /* *(double *)fracdiv = *(double *)fracdiv * *(double*)dbl10; */\n" 304 | L" ASM_MOV_EAX_(fracdiv);\n" 305 | L" ASM_FLD_EAX;\n" 306 | L" ASM_MOV_EAX_(dbl10);\n" 307 | L" ASM_FMUL_EAX;\n" 308 | L" ASM_MOV_EAX_(fracdiv);\n" 309 | L" ASM_FSTP_EAX\n" 310 | L" }\n" 311 | L" }\n" 312 | L" } else if (ch == '.') {\n" 313 | L" if (hasfrac)\n" 314 | L" break;\n" 315 | L" newval = 1;\n" 316 | L" hasfrac = 1;\n" 317 | L" } else if (ch == 'e' || ch == 'E') {\n" 318 | L" if (esgn)\n" 319 | L" break;\n" 320 | L" esgn = newval;\n" 321 | L" eint = 0;\n" 322 | L" } else if (ch == '-') {\n" 323 | L" if (esgn > 0)\n" 324 | L" esgn = -1;\n" 325 | L" else\n" 326 | L" break;\n" 327 | L" } else\n" 328 | L" break;\n" 329 | L" p++; p++;\n" 330 | L" }\n" 331 | L" /* *(double *)pdbl = newval * *(double *)intpart; */\n" 332 | L" addr = &newval;\n" 333 | L" ASM_MOV_EAX_(addr);\n" 334 | L" ASM_FILD_EAX;\n" 335 | L" ASM_MOV_EAX_(intpart);\n" 336 | L" ASM_FMUL_EAX;\n" 337 | L" ASM_MOV_EAX_(pdbl);\n" 338 | L" ASM_FSTP_EAX\n" 339 | L" if (hasfrac) {\n" 340 | L" /* *(double *)pdbl = *(double *)pdbl + newval * *(double *)fracpart / *(double *)fracdiv; */\n" 341 | L" addr = &newval;\n" 342 | L" ASM_MOV_EAX_(addr);\n" 343 | L" ASM_FILD_EAX;\n" 344 | L" ASM_MOV_EAX_(fracpart);\n" 345 | L" ASM_FMUL_EAX;\n" 346 | L" ASM_MOV_EAX_(fracdiv);\n" 347 | L" ASM_FDIV_EAX;\n" 348 | L" ASM_MOV_EAX_(pdbl);\n" 349 | L" ASM_FADD_EAX;\n" 350 | L" ASM_FSTP_EAX\n" 351 | L" }\n" 352 | L" if (esgn) {\n" 353 | L" /* *(double *)pdbl = *(double *)pdbl * pow(dbl10, esgn * eint); */\n" 354 | L" addr = &esgn;\n" 355 | L" ASM_MOV_EAX_(addr);\n" 356 | L" ASM_FILD_EAX;\n" 357 | L" addr = &eint;\n" 358 | L" ASM_MOV_EAX_(addr);\n" 359 | L" ASM_FILD_EAX;\n" 360 | L" ASM_FMULP_ST1;\n" 361 | L" ASM_MOV_EAX_(dbl10);\n" 362 | L" ASM_FLD_EAX;\n" 363 | L" ASM_FYL2X;\n" 364 | L" ASM_FLD1;\n" 365 | L" ASM_FLD_ST1;\n" 366 | L" ASM_FPREM;\n" 367 | L" ASM_F2XM1;\n" 368 | L" ASM_FADDP_ST1;\n" 369 | L" ASM_FSCALE;\n" 370 | L" ASM_MOV_EAX_(pdbl);\n" 371 | L" ASM_FMUL_EAX;\n" 372 | L" ASM_FSTP_EAX;\n" 373 | L" }\n" 374 | L" return p;\n" 375 | L"}"; 376 | pfn = compile(ctx, pinp, 0, 0); 377 | 378 | double dbl1, dbl2; 379 | wchar_t *expr; 380 | 381 | CoInitialize(0); 382 | expr = L"(3.5) + 2.9 * (2 + -(1 + 2))"; 383 | simple_eval(expr, &dbl1); 384 | (*(int (__stdcall *)())pfn)(expr, &dbl2); 385 | assert(dbl1 == dbl2); 386 | } 387 | 388 | 389 | #define TOK_FINAL 0 390 | #define TOK_RPAREN 1 391 | #define TOK_ADD 2 392 | #define TOK_MOD 3 393 | #define TOK_IDIV 4 394 | #define TOK_MUL 5 395 | #define TOK_UNARY 6 396 | #define TOK_POWER 7 397 | #define TOK_LPAREN 8 398 | #define TOK_NUM 9 399 | #define TOK_WHITE 10 400 | 401 | int lookup[256]; 402 | 403 | simple_eval(s, pdbl) 404 | { 405 | int i, p, l, ch, prec, prev_pr; 406 | int op_stack, op_idx; 407 | int val_stack, val_idx; 408 | 409 | op_idx = op_stack = alloca(4000); 410 | val_idx = val_stack = alloca(8000); 411 | l = &lookup; 412 | if (*(char *)(l + 32) == 0) { 413 | p = l; 414 | i = 0; 415 | while (i < 256) { 416 | *(char *)p++ = TOK_WHITE; 417 | i++; 418 | } 419 | *(char *)(l + '(') = TOK_LPAREN; 420 | *(char *)(l + ')') = TOK_RPAREN; 421 | *(char *)(l + '+') = TOK_ADD; 422 | *(char *)(l + '-') = TOK_ADD; 423 | *(char *)(l + '*') = TOK_MUL; 424 | *(char *)(l + '/') = TOK_MUL; 425 | *(char *)(l + '^') = TOK_POWER; 426 | *(char *)(l + '\\') = TOK_IDIV; 427 | *(char *)(l + '%') = TOK_MOD; 428 | *(char *)(l + '.') = TOK_NUM; 429 | p = l + '0'; 430 | i = '0'; 431 | while (i <= '9') { 432 | *(char *)p++ = TOK_NUM; 433 | i++; 434 | } 435 | } 436 | prev_pr = 0; 437 | p = s; 438 | while ((ch = *(short *)p)) { 439 | if (!(ch >> 8)) { 440 | prec = *(char *)(l + ch); 441 | if (prec != TOK_WHITE) { 442 | if (prec == TOK_NUM) { 443 | val_idx = val_idx + 8; 444 | p = fast_val(p, val_idx); 445 | } else if (prec == TOK_ADD) { 446 | if (prev_pr >= TOK_ADD && prev_pr < TOK_NUM) 447 | prec = TOK_UNARY; 448 | } 449 | if (prec >= TOK_ADD && prec < TOK_NUM) { 450 | if(prec != TOK_UNARY) 451 | eval_stack(prec, op_stack, &op_idx, val_stack, &val_idx); 452 | op_idx = op_idx + 4; 453 | *(int *)op_idx = (prec << 16) + ch; 454 | } 455 | prev_pr = prec; 456 | } 457 | } 458 | p++; p++; 459 | } 460 | eval_stack(TOK_FINAL, op_stack, &op_idx, val_stack, &val_idx); 461 | *(int *)pdbl = *(int *)val_idx; 462 | *(int *)(pdbl + 4) = *(int *)(val_idx + 4); 463 | } 464 | 465 | #define ASM_MOV_EAX_ _asm mov eax, 466 | #define ASM_ADD_EAX_ _asm _emit 0x83 _asm _emit 0xc0 _asm _emit 467 | #define ASM_SUB_EAX_ _asm _emit 0x83 _asm _emit 0xe8 _asm _emit 468 | #define ASM_FSTP_EAX _asm _emit 0xdd _asm _emit 0x18 469 | #define ASM_FLD_EAX _asm _emit 0xdd _asm _emit 0x00 470 | #define ASM_FLD_EAX_ _asm _emit 0xdd _asm _emit 0x40 _asm _emit 471 | #define ASM_FADD_EAX _asm _emit 0xdc _asm _emit 0x00 472 | #define ASM_FADD_EAX_ _asm _emit 0xdc _asm _emit 0x40 _asm _emit 473 | #define ASM_FADDP_ST1 _asm _emit 0xde _asm _emit 0xc1 474 | #define ASM_FSUB_EAX_ _asm _emit 0xdc _asm _emit 0x60 _asm _emit 475 | #define ASM_FMUL_EAX _asm _emit 0xdc _asm _emit 0x08 476 | #define ASM_FMUL_EAX_ _asm _emit 0xdc _asm _emit 0x48 _asm _emit 477 | #define ASM_FMULP_ST1 _asm _emit 0xde _asm _emit 0xc9 478 | #define ASM_FDIV_EAX _asm _emit 0xdc _asm _emit 0x30 479 | #define ASM_FDIV_EAX_ _asm _emit 0xdc _asm _emit 0x70 _asm _emit 480 | #define ASM_FCHS _asm _emit 0xd9 _asm _emit 0xe0 481 | #define ASM_FILD_EAX _asm _emit 0xdb _asm _emit 0x00 482 | #define ASM_FISTP_EAX _asm _emit 0xdb _asm _emit 0x18 483 | #define ASM_FYL2X _asm _emit 0xd9 _asm _emit 0xf1 484 | #define ASM_FLD1 _asm _emit 0xd9 _asm _emit 0xe8 485 | #define ASM_FLD_ST1 _asm _emit 0xd9 _asm _emit 0xc1 486 | #define ASM_FPREM _asm _emit 0xd9 _asm _emit 0xf8 487 | #define ASM_F2XM1 _asm _emit 0xd9 _asm _emit 0xf0 488 | #define ASM_FSCALE _asm _emit 0xd9 _asm _emit 0xfd 489 | #define ASM_FLDZ _asm _emit 0xd9 _asm _emit 0xee 490 | 491 | eval_stack(prec, op_stack, pop_idx, val_stack, pval_idx) 492 | { 493 | int op_idx, val_idx, op, t1, pt1, t2, pt2; 494 | 495 | op_idx = *(int *)pop_idx; 496 | val_idx = *(int *)pval_idx; 497 | while (op_idx > op_stack) { 498 | if (*(int *)(op_idx) < (prec << 16)) 499 | break; 500 | val_idx = val_idx - 8; 501 | op = *(short *)op_idx; 502 | if (op == '+') { 503 | if (*(int *)(op_idx) > (TOK_UNARY << 16)) { 504 | val_idx = val_idx + 8; 505 | } else { 506 | /* *(double *)val_idx = *(double *)val_idx + *(double *)(val_idx + 8); */ 507 | ASM_MOV_EAX_(val_idx); 508 | ASM_FLD_EAX; 509 | ASM_FADD_EAX_(8); 510 | ASM_FSTP_EAX; 511 | } 512 | } else if (op == '-') { 513 | if (*(int *)(op_idx) > (TOK_UNARY << 16)) { 514 | val_idx = val_idx + 8; 515 | /* *(double *)val_idx = -*(double *)val_idx; */ 516 | ASM_MOV_EAX_(val_idx); 517 | ASM_FLD_EAX; 518 | ASM_FCHS; 519 | ASM_FSTP_EAX; 520 | } else { 521 | /* *(double *)val_idx = *(double *)val_idx - *(double *)(val_idx + 8); */ 522 | ASM_MOV_EAX_(val_idx); 523 | ASM_FLD_EAX; 524 | ASM_FSUB_EAX_(8); 525 | ASM_FSTP_EAX; 526 | } 527 | } else if (op == '*') { 528 | /* *(double *)val_idx = *(double *)val_idx * *(double *)(val_idx + 8); */ 529 | ASM_MOV_EAX_(val_idx); 530 | ASM_FLD_EAX; 531 | ASM_FMUL_EAX_(8); 532 | ASM_FSTP_EAX; 533 | } else if (op == '/') { 534 | /* *(double *)val_idx = *(double *)val_idx / *(double *)(val_idx + 8); */ 535 | ASM_MOV_EAX_(val_idx); 536 | ASM_FLD_EAX; 537 | ASM_FDIV_EAX_(8); 538 | ASM_FSTP_EAX; 539 | } else if (op == '^') { 540 | /* *(double *)val_idx = pow(*(double *)val_idx, *(double *)(val_idx + 8)); */ 541 | ASM_MOV_EAX_(val_idx); 542 | ASM_ADD_EAX_(8); 543 | ASM_FLD_EAX; 544 | ASM_SUB_EAX_(8); 545 | ASM_FLD_EAX; 546 | ASM_FYL2X; 547 | ASM_FLD1; 548 | ASM_FLD_ST1; 549 | ASM_FPREM; 550 | ASM_F2XM1; 551 | ASM_FADDP_ST1; 552 | ASM_FSCALE; 553 | ASM_FSTP_EAX; 554 | } else if (op == '\\') { 555 | pt1 = &t1; 556 | /* *(double *)val_idx = (int)(*(double *)val_idx / *(double *)(val_idx + 8)); */ 557 | ASM_MOV_EAX_(val_idx); 558 | ASM_FLD_EAX; 559 | ASM_FDIV_EAX_(8); 560 | ASM_MOV_EAX_(pt1); 561 | ASM_FISTP_EAX; 562 | ASM_FILD_EAX; 563 | ASM_MOV_EAX_(val_idx); 564 | ASM_FSTP_EAX; 565 | } else if (op == '%') { 566 | pt1 = &t1; 567 | pt2 = &t2; 568 | /* *(double *)val_idx = (int)*(double *)val_idx % (int)*(double *)(val_idx + 8); */ 569 | ASM_MOV_EAX_(val_idx); 570 | ASM_FLD_EAX; 571 | ASM_MOV_EAX_(pt1); 572 | ASM_FISTP_EAX; 573 | ASM_MOV_EAX_(val_idx); 574 | ASM_ADD_EAX_(8); 575 | ASM_FLD_EAX; 576 | ASM_MOV_EAX_(pt2); 577 | ASM_FISTP_EAX; 578 | t1 = t1 % t2; 579 | ASM_MOV_EAX_(pt1); 580 | ASM_FILD_EAX; 581 | ASM_MOV_EAX_(val_idx); 582 | ASM_FSTP_EAX; 583 | } else if (op == '(') { 584 | val_idx = val_idx + 8; 585 | if (prec == TOK_RPAREN) { 586 | op_idx = op_idx - 4; 587 | break; 588 | } else if (prec > TOK_RPAREN) 589 | break; 590 | } 591 | op_idx = op_idx - 4; 592 | } 593 | *(int *)pval_idx = val_idx; 594 | *(int *)pop_idx = op_idx; 595 | } 596 | 597 | fast_val(p, pdbl) 598 | { 599 | int ch, addr; 600 | int newval, esgn, eint, hasfrac; 601 | int intpart, fracpart, fracdiv, dbl10; /* doubles */ 602 | 603 | intpart = alloca(8); 604 | fracpart = alloca(8); 605 | fracdiv = alloca(8); 606 | dbl10 = alloca(8); 607 | newval = esgn = hasfrac = 0; 608 | /* *(double *)intpart = *(double *)fracpart = 0 */ 609 | ASM_FLDZ; 610 | ASM_MOV_EAX_(intpart); 611 | ASM_FSTP_EAX; 612 | ASM_FLDZ; 613 | ASM_MOV_EAX_(fracpart); 614 | ASM_FSTP_EAX; 615 | /* *(double *)fracdiv = 1 */ 616 | ASM_FLD1; 617 | ASM_MOV_EAX_(fracdiv); 618 | ASM_FSTP_EAX; 619 | /* *(double *)dbl10 = 10 */ 620 | ch = 10; 621 | addr = &ch; 622 | ASM_MOV_EAX_(addr); 623 | ASM_FILD_EAX; 624 | ASM_MOV_EAX_(dbl10); 625 | ASM_FSTP_EAX; 626 | while ((ch = *(short *)p)) { 627 | if (ch >= '0' && ch <= '9') { 628 | newval = 1; 629 | if (esgn) { 630 | eint = eint * 10 + ch - '0'; 631 | } else { 632 | ch = ch - '0'; 633 | if(!hasfrac) { 634 | /* *(double *)intpart = *(double *)intpart * *(double*)dbl10 + ch; */ 635 | ASM_MOV_EAX_(intpart); 636 | ASM_FLD_EAX; 637 | ASM_MOV_EAX_(dbl10); 638 | ASM_FMUL_EAX; 639 | addr = &ch; 640 | ASM_MOV_EAX_(addr); 641 | ASM_FILD_EAX; 642 | ASM_FADDP_ST1; 643 | ASM_MOV_EAX_(intpart); 644 | ASM_FSTP_EAX 645 | } else { 646 | /* *(double *)fracpart = *(double *)fracpart * *(double*)dbl10 + ch; */ 647 | ASM_MOV_EAX_(fracpart); 648 | ASM_FLD_EAX; 649 | ASM_MOV_EAX_(dbl10); 650 | ASM_FMUL_EAX; 651 | addr = &ch; 652 | ASM_MOV_EAX_(addr); 653 | ASM_FILD_EAX; 654 | ASM_FADDP_ST1; 655 | ASM_MOV_EAX_(fracpart); 656 | ASM_FSTP_EAX 657 | /* *(double *)fracdiv = *(double *)fracdiv * *(double*)dbl10; */ 658 | ASM_MOV_EAX_(fracdiv); 659 | ASM_FLD_EAX; 660 | ASM_MOV_EAX_(dbl10); 661 | ASM_FMUL_EAX; 662 | ASM_MOV_EAX_(fracdiv); 663 | ASM_FSTP_EAX 664 | } 665 | } 666 | } else if (ch == '.') { 667 | if (hasfrac) 668 | break; 669 | newval = 1; 670 | hasfrac = 1; 671 | } else if (ch == 'e' || ch == 'E') { 672 | if (esgn) 673 | break; 674 | esgn = newval; 675 | eint = 0; 676 | } else if (ch == '-') { 677 | if (esgn > 0) 678 | esgn = -1; 679 | else 680 | break; 681 | } else 682 | break; 683 | p++; p++; 684 | } 685 | /* *(double *)pdbl = newval * *(double *)intpart; */ 686 | addr = &newval; 687 | ASM_MOV_EAX_(addr); 688 | ASM_FILD_EAX; 689 | ASM_MOV_EAX_(intpart); 690 | ASM_FMUL_EAX; 691 | ASM_MOV_EAX_(pdbl); 692 | ASM_FSTP_EAX 693 | if (hasfrac) { 694 | /* *(double *)pdbl = *(double *)pdbl + newval * *(double *)fracpart / *(double *)fracdiv; */ 695 | addr = &newval; 696 | ASM_MOV_EAX_(addr); 697 | ASM_FILD_EAX; 698 | ASM_MOV_EAX_(fracpart); 699 | ASM_FMUL_EAX; 700 | ASM_MOV_EAX_(fracdiv); 701 | ASM_FDIV_EAX; 702 | ASM_MOV_EAX_(pdbl); 703 | ASM_FADD_EAX; 704 | ASM_FSTP_EAX 705 | } 706 | if (esgn) { 707 | /* *(double *)pdbl = *(double *)pdbl * pow(dbl10, esgn * eint); */ 708 | addr = &esgn; 709 | ASM_MOV_EAX_(addr); 710 | ASM_FILD_EAX; 711 | addr = &eint; 712 | ASM_MOV_EAX_(addr); 713 | ASM_FILD_EAX; 714 | ASM_FMULP_ST1; 715 | ASM_MOV_EAX_(dbl10); 716 | ASM_FLD_EAX; 717 | ASM_FYL2X; 718 | ASM_FLD1; 719 | ASM_FLD_ST1; 720 | ASM_FPREM; 721 | ASM_F2XM1; 722 | ASM_FADDP_ST1; 723 | ASM_FSCALE; 724 | ASM_MOV_EAX_(pdbl); 725 | ASM_FMUL_EAX; 726 | ASM_FSTP_EAX; 727 | } 728 | return p; 729 | } 730 | 731 | #if 0 732 | #define PARSE_FLAGS_DEFAULT 0xB14 733 | #define VTBIT_R8 0x20 734 | 735 | parse_num(s, pdbl, psize) 736 | { 737 | int numparse, dig, variant_res; 738 | 739 | numparse = alloca(24); 740 | dig = alloca(30); 741 | variant_res = alloca(16); 742 | *(int *)numparse = 30; 743 | *(int *)(numparse + 4) = PARSE_FLAGS_DEFAULT; 744 | if (!VarParseNumFromStr(s, 0, 0, numparse, dig)) { 745 | if (!VarNumFromParseNum(numparse, dig, VTBIT_R8, variant_res)) { 746 | *(int *)pdbl = *(int *)(variant_res + 8); 747 | *(int *)(pdbl + 4) = *(int *)(variant_res + 12); 748 | *(int *)psize = *(int *)(numparse + 12); /* cchUsed */ 749 | return; 750 | } 751 | } 752 | *(int *)pdbl = 0; 753 | *(int *)(pdbl + 4) = 0; 754 | *(int *)psize = 1; 755 | } 756 | #endif 757 | -------------------------------------------------------------------------------- /lib/otcc/otccn.c: -------------------------------------------------------------------------------- 1 | /* 2 | Obfuscated Tiny C Compiler 3 | 4 | Copyright (C) 2001-2003 Fabrice Bellard 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product and its documentation 17 | *is* required. 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 3. This notice may not be removed or altered from any source distribution. 21 | */ 22 | #ifndef TINY 23 | #include 24 | #endif 25 | #include 26 | 27 | #ifdef _DEBUG 28 | void error(char *fmt,...); 29 | #define assert(expr) { if (!(expr)) error("assert failed: %s", #expr); } 30 | //#define tok_error(tok, tokn, str) error("%s defined 0x%x (should be 0x%x)", tokn, tok, c); 31 | #define tok_assert(tok, str) { int c = (mystrstr(ctx->sym_stk, (str)) - ctx->sym_stk) * 8 + TOK_IDENT; if((tok) != c) error("%s defined 0x%x (should be 0x%x)", #tok, (tok), c); } 32 | #else 33 | #define assert(expr) 34 | #define tok_assert(tok, str) 35 | #endif 36 | 37 | void __cdecl exit(int); 38 | void * __cdecl memcpy(void *d, const void *s, int n); 39 | void * __cdecl memset(void *p, int v, int n); 40 | int __cdecl strcmp(const char *s1, const char *s2); 41 | int __cdecl strlen(const char *s); 42 | #pragma intrinsic(memcpy, memset, strcmp, strlen) 43 | 44 | 45 | /* vars: value of variables 46 | loc : local variable index 47 | glo : global variable index 48 | ind : output code ptr 49 | rsym: return symbol 50 | prog: output code 51 | dstk: define stack 52 | dptr, dch: macro state 53 | */ 54 | typedef struct ctx_t { 55 | // input params 56 | int prog, sym_stk, mods; 57 | // in/out params 58 | int glo, vars; 59 | // preserved state 60 | int ind, dstk, t0; 61 | // local state (discarded after compile) 62 | int tok, tokc, tokl, tokw, ch, rsym, loc, dptr, dch, last_id; 63 | int pinp0, pinp; 64 | } *pctx_t; 65 | 66 | #define ALLOC_SIZE 99999 67 | 68 | /* depends on the init string */ 69 | #define TOK_STR_SIZE 83 70 | #define TOK_IDENT 0x100 71 | #define TOK_INT 0x100 72 | #define TOK_IF 0x120 73 | #define TOK_ELSE 0x138 74 | #define TOK_WHILE 0x160 75 | #define TOK_BREAK 0x190 76 | #define TOK_RETURN 0x1c0 77 | #define TOK_FOR 0x1f8 78 | #define TOK_SHORT 0x218 79 | #define TOK_ALLOCA 0x248 80 | #define TOK_ASM 0x280 81 | #define TOK_ASM_EMIT 0x2b0 82 | #define TOK_ASM_MOV 0x2e8 83 | #define TOK_ASM_EAX 0x310 84 | #define TOK_DEFINE 0x330 85 | #define TOK_MAIN 0x368 86 | #define IDX_ASM_EMIT 54 87 | #define IDX_ASM_MOV 61 88 | #define IDX_ASM_EAX 66 89 | 90 | #define TOK_DUMMY 1 91 | #define TOK_NUM 2 92 | 93 | #define LOCAL 0x200 94 | 95 | #define SYM_FORWARD 0 96 | #define SYM_DEFINE 1 97 | 98 | /* tokens in string heap */ 99 | #define TAG_TOK ' ' 100 | #define TAG_MACRO 2 101 | 102 | #define CONST_T0_SIZE 126 103 | 104 | 105 | compile(pctx_t ctx, int pinp, int wParam, int lParam) 106 | { 107 | int r; 108 | 109 | if (!ctx->ind) { 110 | char t0[] = { '+', '+', '#', 'm', '-', '-', '%', 'a', 'm', '*', '@', 'R', '<', '^', '1', 'c', '/', '@', '%', '[', '_', '[', 'H', '3', 111 | 'c', '%', '@', '%', '[', '_', '[', 'H', '3', 'c', '+', '@', '.', 'B', '#', 'd', '-', '@', '%', ':', '_', '^', 'B', 'K', 'd', '<', 112 | '<', 'Z', '/', '0', '3', 'e', '>', '>', '`', '/', '0', '3', 'e', '<', '=', '0', 'f', '>', '=', '/', 'f', '<', '@', '.', 'f', '>', 113 | '@', '1', 'f', '=', '=', '&', 'g', '!', '=', '\'', 'g', '&', '&', 'k', '|', '|', '#', 'l', '&', '@', '.', 'B', 'C', 'h', '^', 114 | '@', '.', 'B', 'S', 'i', '|', '@', '.', 'B', '+', 'j', '~', '@', '/', '%', 'Y', 'd', '!', '@', '&', 'd', '*', '@', 'b', 0 }; 115 | ctx->t0 = ctx->glo; 116 | memcpy(ctx->t0, t0, CONST_T0_SIZE); 117 | ctx->glo = ctx->t0 + CONST_T0_SIZE; 118 | char stk0[] = { ' ', 'i', 'n', 't', ' ', 'i', 'f', ' ', 'e', 'l', 's', 'e', ' ', 'w', 'h', 'i', 'l', 'e', ' ', 'b', 'r', 'e', 'a', 'k', ' ', 119 | 'r', 'e', 't', 'u', 'r', 'n', ' ', 'f', 'o', 'r', ' ', 's', 'h', 'o', 'r', 't', ' ', 'a', 'l', 'l', 'o', 'c', 'a', ' ', 120 | '_', 'a', 's', 'm', ' ', '!', '_', 'e', 'm', 'i', 't', ' ', '!', 'm', 'o', 'v', ' ', '!', 'e', 'a', 'x', ' ', 121 | 'd', 'e', 'f', 'i', 'n', 'e', ' ', 'm', 'a', 'i', 'n', ' ' }; 122 | assert(TOK_STR_SIZE == sizeof(stk0)); 123 | memcpy(ctx->sym_stk, stk0, TOK_STR_SIZE); 124 | tok_assert(TOK_INT, " int "); 125 | tok_assert(TOK_IF, " if "); 126 | tok_assert(TOK_ELSE, " else "); 127 | tok_assert(TOK_WHILE, " while "); 128 | tok_assert(TOK_BREAK, " break "); 129 | tok_assert(TOK_RETURN, " return "); 130 | tok_assert(TOK_FOR, " for "); 131 | tok_assert(TOK_SHORT, " short "); 132 | tok_assert(TOK_ASM, " _asm "); 133 | tok_assert(TOK_ASM_EMIT, "!_emit "); 134 | tok_assert(TOK_ASM_MOV, "!mov "); 135 | tok_assert(TOK_ASM_EAX, "!eax "); 136 | tok_assert(TOK_ALLOCA, " alloca "); 137 | tok_assert(TOK_DEFINE, " define "); 138 | tok_assert(TOK_MAIN, " main "); 139 | assert(*(char *)(ctx->sym_stk + IDX_ASM_EMIT) == '!'); 140 | assert(*(char *)(ctx->sym_stk + IDX_ASM_MOV) == '!'); 141 | assert(*(char *)(ctx->sym_stk + IDX_ASM_EAX) == '!'); 142 | ctx->dstk = ctx->sym_stk + TOK_STR_SIZE; 143 | ctx->ind = ctx->prog; 144 | } 145 | ctx->pinp0 = ctx->pinp = pinp; 146 | r = ctx->ind; 147 | inpu(ctx); 148 | next(ctx); 149 | decl(ctx, 0); 150 | return r; 151 | } 152 | 153 | pdef(pctx_t ctx, int t) 154 | { 155 | *(char *)ctx->dstk++ = t; 156 | } 157 | 158 | inpu(pctx_t ctx) 159 | { 160 | if (ctx->dptr) { 161 | ctx->ch = *(char *)ctx->dptr++; 162 | if (ctx->ch == TAG_MACRO) { 163 | ctx->dptr = 0; 164 | ctx->ch = ctx->dch; 165 | } 166 | } else { 167 | ctx->ch = *(char *)ctx->pinp; 168 | ctx->ch = ctx->ch + (*(char *)(ctx->pinp + 1) << 8); 169 | if (ctx->ch != 0) 170 | ctx->pinp = ctx->pinp + 2; 171 | else 172 | ctx->ch = -1; 173 | } 174 | /* printf("ch=%c 0x%x\n", ch, ch); */ 175 | return ctx->ch; 176 | } 177 | 178 | peek(pctx_t ctx) 179 | { 180 | return *(char *)ctx->pinp + (*(char *)(ctx->pinp + 1) << 8); 181 | } 182 | 183 | isid(ch) 184 | { 185 | return myisalnum(ch) | ch == '_'; 186 | } 187 | 188 | /* read a character constant */ 189 | getq(pctx_t ctx) 190 | { 191 | int c, v; 192 | if (ctx->ch == '\\') { 193 | inpu(ctx); 194 | if (ctx->ch == 'n') 195 | ctx->ch = '\n'; 196 | else if (ctx->ch == 'r') 197 | ctx->ch = '\r'; 198 | else if (ctx->ch == 't') 199 | ctx->ch = '\t'; 200 | else if (ctx->ch == '\\') 201 | ctx->ch = '\\'; 202 | else if (ctx->ch == 'x') { 203 | if ((c = inpu(ctx)) > '9') 204 | c = (c | 0x20) - 39; 205 | v = (c - '0'); 206 | if ((c = inpu(ctx)) > '9') 207 | c = (c | 0x20) - 39; 208 | v = v * 16 + (c - '0'); 209 | if (ctx->tokw && ((c = peek(ctx)) >= '0' && c <= '9' || (c | 0x20) >= 'a' && (c | 0x20) <= 'f')) 210 | { 211 | if ((c = inpu(ctx)) > '9') 212 | c = (c | 0x20) - 39; 213 | v = v * 16 + (c - '0'); 214 | if ((c = inpu(ctx)) > '9') 215 | c = (c | 0x20) - 39; 216 | v = v * 16 + (c - '0'); 217 | } 218 | ctx->ch = v; 219 | } 220 | } 221 | } 222 | 223 | next(pctx_t ctx) 224 | { 225 | int t, l, a; 226 | 227 | while (myisspace(ctx->ch) | ctx->ch == '#') { 228 | if (ctx->ch == '#') { 229 | inpu(ctx); 230 | next(ctx); 231 | if (ctx->tok == TOK_DEFINE) { 232 | next(ctx); 233 | pdef(ctx, TAG_TOK); /* fill last ident tag */ 234 | *(int *)ctx->tok = SYM_DEFINE; 235 | *(int *)(ctx->tok + 4) = ctx->dstk; /* define stack */ 236 | } 237 | /* well we always save the values ! */ 238 | while (ctx->ch != '\n') { 239 | pdef(ctx, ctx->ch); 240 | inpu(ctx); 241 | } 242 | pdef(ctx, ctx->ch); 243 | pdef(ctx, TAG_MACRO); 244 | } 245 | inpu(ctx); 246 | } 247 | ctx->tokw = (ctx->ch == 'L' && (peek(ctx) == '\"' || peek(ctx) == '\'')); 248 | if (ctx->tokw) 249 | inpu(ctx); 250 | ctx->tokl = 0; 251 | ctx->tok = ctx->ch; 252 | /* encode identifiers & numbers */ 253 | if (isid(ctx->ch)) { 254 | pdef(ctx, TAG_TOK); 255 | ctx->last_id = ctx->dstk; 256 | while (isid(ctx->ch)) { 257 | pdef(ctx, ctx->ch); 258 | inpu(ctx); 259 | } 260 | if (myisdigit(ctx->tok)) { 261 | ctx->tokc = mystrtol(ctx->last_id); 262 | ctx->tok = TOK_NUM; 263 | } else { 264 | *(char *)ctx->dstk = TAG_TOK; /* no need to mark end of string (we 265 | suppose data is initied to zero */ 266 | ctx->tok = mystrstr(ctx->sym_stk, ctx->last_id - 1) - ctx->sym_stk; 267 | *(char *)ctx->dstk = 0; /* mark real end of ident for dlsym() */ 268 | ctx->tok = ctx->tok * 8 + TOK_IDENT; 269 | if (ctx->tok > TOK_DEFINE) { 270 | ctx->tok = ctx->vars + ctx->tok; 271 | /* printf("tok=%s %x\n", last_id, tok); */ 272 | /* define handling */ 273 | if (*(int *)ctx->tok == SYM_DEFINE) { 274 | ctx->dptr = *(int *)(ctx->tok + 4); 275 | ctx->dch = ctx->ch; 276 | inpu(ctx); 277 | next(ctx); 278 | } 279 | } 280 | } 281 | } else { 282 | inpu(ctx); 283 | if (ctx->tok == '\'') { 284 | ctx->tok = TOK_NUM; 285 | getq(ctx); 286 | ctx->tokc = ctx->ch; 287 | inpu(ctx); 288 | inpu(ctx); 289 | } else if (ctx->tok == '/' & ctx->ch == '*') { 290 | inpu(ctx); 291 | while (ctx->ch) { 292 | while (ctx->ch != '*') 293 | inpu(ctx); 294 | inpu(ctx); 295 | if (ctx->ch == '/') 296 | ctx->ch = 0; 297 | } 298 | inpu(ctx); 299 | next(ctx); 300 | } else 301 | { 302 | t = ctx->t0; 303 | while (l = *(char *)t++) { 304 | a = *(char *)t++; 305 | ctx->tokc = 0; 306 | while ((ctx->tokl = *(char *)t++ - 'b') < 0) 307 | ctx->tokc = ctx->tokc * 64 + ctx->tokl + 64; 308 | if (l == ctx->tok & (a == ctx->ch | a == '@')) { 309 | #if 0 310 | printf("%c%c -> tokl=%d tokc=0x%x\n", 311 | l, a, tokl, tokc); 312 | #endif 313 | if (a == ctx->ch) { 314 | inpu(ctx); 315 | ctx->tok = TOK_DUMMY; /* dummy token for double tokens */ 316 | } 317 | break; 318 | } 319 | } 320 | } 321 | } 322 | #if 0 323 | { 324 | int p; 325 | 326 | printf("tok=0x%x ", tok); 327 | if (tok >= TOK_IDENT) { 328 | printf("'"); 329 | if (tok > TOK_DEFINE) 330 | p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8; 331 | else 332 | p = sym_stk + 1 + (tok - TOK_IDENT) / 8; 333 | while (*(char *)p != TAG_TOK && *(char *)p) 334 | printf("%c", *(char *)p++); 335 | printf("'\n"); 336 | } else if (tok == TOK_NUM) { 337 | printf("%d\n", tokc); 338 | } else { 339 | printf("'%c'\n", tok); 340 | } 341 | } 342 | #endif 343 | } 344 | 345 | #ifdef TINY 346 | #define skip(ctx, c) next(ctx) 347 | #else 348 | 349 | void error(char *fmt,...) 350 | { 351 | va_list ap; 352 | 353 | va_start(ap, fmt); 354 | vfprintf(stderr, fmt, ap); 355 | fprintf(stderr, "\n"); 356 | getchar(); 357 | exit(1); 358 | va_end(ap); 359 | } 360 | 361 | void skip(pctx_t ctx, int c) 362 | { 363 | if (ctx->tok != c) { 364 | error("'%c' expected (found '%c') at position %d\n%.40ws", c, ctx->tok, 365 | (ctx->pinp - ctx->pinp0 - 4) / 2, ctx->pinp - 4); 366 | } 367 | next(ctx); 368 | } 369 | 370 | #endif 371 | 372 | o(pctx_t ctx, int n) 373 | { 374 | /* cannot use unsigned, so we must do a hack */ 375 | while (n && n != -1) { 376 | *(char *)ctx->ind++ = n; 377 | n = n >> 8; 378 | } 379 | } 380 | 381 | /* output a symbol and patch all calls to it */ 382 | gsym(pctx_t ctx, int t) 383 | { 384 | int n; 385 | while (t) { 386 | n = *(int *)t; /* next value */ 387 | *(int *)t = ctx->ind - t - 4; 388 | t = n; 389 | } 390 | } 391 | 392 | /* psym is used to put an instruction with a data field which is a 393 | reference to a symbol. It is in fact the same as oad ! */ 394 | #define psym oad 395 | 396 | /* instruction + address */ 397 | oad(pctx_t ctx, int n, int t) 398 | { 399 | o(ctx, n); 400 | *(int *)ctx->ind = t; 401 | t = ctx->ind; 402 | ctx->ind = ctx->ind + 4; 403 | return t; 404 | } 405 | 406 | /* load immediate value */ 407 | li(pctx_t ctx, int t) 408 | { 409 | oad(ctx, 0xb8, t); /* mov $xx, %eax */ 410 | } 411 | 412 | gjmp(pctx_t ctx, int t) 413 | { 414 | return psym(ctx, 0xe9, t); 415 | } 416 | 417 | /* l = 0: je, l == 1: jne */ 418 | gtst(pctx_t ctx, int l, int t) 419 | { 420 | o(ctx, 0x0fc085); /* test %eax, %eax, je/jne xxx */ 421 | return psym(ctx, 0x84 + l, t); 422 | } 423 | 424 | gcmp(pctx_t ctx, int t) 425 | { 426 | o(ctx, 0xc139); /* cmp %eax,%ecx */ 427 | li(ctx, 0); 428 | o(ctx, 0x0f); /* setxx %al */ 429 | o(ctx, t + 0x90); 430 | o(ctx, 0xc0); 431 | } 432 | 433 | gmov(pctx_t ctx, int l, int t) 434 | { 435 | o(ctx, l + 0x83); 436 | oad(ctx, (t < LOCAL) << 7 | 5, t); 437 | } 438 | 439 | /* l is one if '=' parsing wanted (quick hack) */ 440 | unary(register pctx_t ctx, int l) 441 | { 442 | int n, t, a, c; 443 | 444 | n = 1; /* type of expression 0 = forward, 1 = value, other = 445 | lvalue */ 446 | if (ctx->tok == '\"') { 447 | li(ctx, ctx->glo); 448 | while (ctx->ch != '\"') { 449 | getq(ctx); 450 | *(char *)ctx->glo++ = ctx->ch; 451 | if (ctx->tokw) 452 | *(char *)ctx->glo++ = ctx->ch >> 8; 453 | inpu(ctx); 454 | } 455 | if (ctx->tokw) 456 | *(char *)ctx->glo++ = 0; 457 | *(char *)ctx->glo = 0; 458 | ctx->glo = ctx->glo + 3 & -4; /* align heap */ 459 | inpu(ctx); 460 | next(ctx); 461 | } else { 462 | c = ctx->tokl; 463 | a = ctx->tokc; 464 | t = ctx->tok; 465 | next(ctx); 466 | if (t == TOK_NUM) { 467 | li(ctx, a); 468 | } else if (t == TOK_ALLOCA) { 469 | expr(ctx); 470 | o(ctx, 0x03c083); // add 3, %eax 471 | o(ctx, 0xfce083); // and -4, %eax 472 | o(ctx, 0xc429); // sub %eax, %esp 473 | o(ctx, 0xe089); // mov %esp, %eax 474 | } else if (c == 2) { 475 | /* -, +, !, ~ */ 476 | unary(ctx, 0); 477 | oad(ctx, 0xb9, 0); /* movl $0, %ecx */ 478 | if (t == '!') 479 | gcmp(ctx, a); 480 | else 481 | o(ctx, a); 482 | } else if (t == '(') { 483 | expr(ctx); 484 | skip(ctx, ')'); 485 | } else if (t == '*') { 486 | /* parse cast */ 487 | skip(ctx, '('); 488 | t = ctx->tok; /* get type */ 489 | next(ctx); /* skip int/char/void */ 490 | next(ctx); /* skip '*' or '(' */ 491 | if (ctx->tok == '*') { 492 | /* function type */ 493 | skip(ctx, '*'); 494 | skip(ctx, ')'); 495 | skip(ctx, '('); 496 | skip(ctx, ')'); 497 | t = 0; 498 | } 499 | skip(ctx, ')'); 500 | unary(ctx, 0); 501 | if (ctx->tok == '=') { 502 | next(ctx); 503 | o(ctx, 0x50); /* push %eax */ 504 | expr(ctx); 505 | o(ctx, 0x59); /* pop %ecx */ 506 | if (t == TOK_SHORT) 507 | o(ctx, 0x018966); // movw %ax, (%ecx) 508 | else 509 | o(ctx, 0x0188 + (t == TOK_INT)); /* movl %eax/%al, (%ecx) */ 510 | } else if (t) { 511 | if (t == TOK_INT) 512 | o(ctx, 0x8b); /* mov (%eax), %eax */ 513 | else 514 | o(ctx, 0xbe0f + ((t == TOK_SHORT)<<8)); // movswl/movsbl (%eax), %eax 515 | ctx->ind++; /* add zero in code */ 516 | } 517 | } else if (t == '&') { 518 | gmov(ctx, 10, *(int *)ctx->tok); /* leal EA, %eax */ 519 | next(ctx); 520 | } else { 521 | if (t == TOK_ASM_EAX) { 522 | n = 0; 523 | } else { 524 | n = *(int *)t; 525 | /* forward reference: try dlsym */ 526 | if (!n) 527 | n = dlsym(ctx, 0, ctx->last_id); 528 | } 529 | if (ctx->tok == '=' & l) { 530 | /* assignment */ 531 | next(ctx); 532 | expr(ctx); 533 | if (n) 534 | gmov(ctx, 6, n); /* mov %eax, EA */ 535 | } else if (ctx->tok != '(') { 536 | if (n) /* variable */ 537 | gmov(ctx, 8, n); /* mov EA, %eax */ 538 | if (ctx->tokl == 11) { // `++` -> ctx->tokc=1, `--` -> ctx->tokc=0xFF 539 | if (n) { 540 | gmov(ctx, 0, n); // add $ctx->tokc, EA 541 | } else { 542 | o(ctx, 0xc083); // add $ctx->tokc, %eax 543 | } 544 | o(ctx, ctx->tokc); 545 | next(ctx); 546 | } 547 | } 548 | } 549 | } 550 | 551 | /* function call */ 552 | if (ctx->tok == '(') { 553 | if (n == 1) 554 | o(ctx, 0x50); /* push %eax */ 555 | 556 | /* push args and invert order */ 557 | a = oad(ctx, 0xec81, 0); /* sub $xxx, %esp */ 558 | next(ctx); 559 | l = 0; 560 | while(ctx->tok != ')') { 561 | expr(ctx); 562 | oad(ctx, 0x248489, l); /* movl %eax, xxx(%esp) */ 563 | if (ctx->tok == ',') 564 | next(ctx); 565 | l = l + 4; 566 | } 567 | *(int *)a = l; 568 | next(ctx); 569 | if (!n) { 570 | /* forward reference */ 571 | t = t + 4; 572 | *(int *)t = psym(ctx, 0xe8, *(int *)t); 573 | } else if (n == 1) { 574 | oad(ctx, 0x2494ff, l); /* call *xxx(%esp) */ 575 | oad(ctx, 0xc481, 4); /* add $xxx, %esp */ 576 | } else { 577 | oad(ctx, 0xe8, n - ctx->ind - 5); /* call xxx */ 578 | } 579 | } 580 | } 581 | 582 | sum(pctx_t ctx, int l) 583 | { 584 | int t, n, a; 585 | 586 | if (l-- == 1) 587 | unary(ctx, 1); 588 | else { 589 | sum(ctx, l); 590 | a = 0; 591 | while (l == ctx->tokl) { 592 | n = ctx->tok; 593 | t = ctx->tokc; 594 | next(ctx); 595 | 596 | if (l > 8) { 597 | a = gtst(ctx, t, a); /* && and || output code generation */ 598 | sum(ctx, l); 599 | } else { 600 | o(ctx, 0x50); /* push %eax */ 601 | sum(ctx, l); 602 | o(ctx, 0x59); /* pop %ecx */ 603 | if (l == 4 | l == 5) { 604 | gcmp(ctx, t); 605 | } else { 606 | o(ctx, t); 607 | if (n == '%') 608 | o(ctx, 0x92); /* xchg %edx, %eax */ 609 | } 610 | } 611 | } 612 | /* && and || output code generation */ 613 | if (a && l > 8) { 614 | a = gtst(ctx, t, a); 615 | li(ctx, t ^ 1); 616 | gjmp(ctx, 5); /* jmp $ + 5 */ 617 | gsym(ctx, a); 618 | li(ctx, t); 619 | } 620 | } 621 | } 622 | 623 | expr(pctx_t ctx) 624 | { 625 | sum(ctx, 11); 626 | } 627 | 628 | test_expr(pctx_t ctx) 629 | { 630 | expr(ctx); 631 | return gtst(ctx, 0, 0); 632 | } 633 | 634 | block(pctx_t ctx, int l) 635 | { 636 | int a, n, t; 637 | 638 | if (ctx->tok == TOK_IF) { 639 | next(ctx); 640 | skip(ctx, '('); 641 | a = test_expr(ctx); 642 | skip(ctx, ')'); 643 | block(ctx, l); 644 | if (ctx->tok == TOK_ELSE) { 645 | next(ctx); 646 | n = gjmp(ctx, 0); /* jmp */ 647 | gsym(ctx, a); 648 | block(ctx, l); 649 | gsym(ctx, n); /* patch else jmp */ 650 | } else { 651 | gsym(ctx, a); /* patch if test */ 652 | } 653 | } else if (ctx->tok == TOK_WHILE | ctx->tok == TOK_FOR) { 654 | t = ctx->tok; 655 | next(ctx); 656 | skip(ctx, '('); 657 | if (t == TOK_WHILE) { 658 | n = ctx->ind; 659 | a = test_expr(ctx); 660 | } else { 661 | if (ctx->tok != ';') 662 | expr(ctx); 663 | skip(ctx, ';'); 664 | n = ctx->ind; 665 | a = 0; 666 | if (ctx->tok != ';') 667 | a = test_expr(ctx); 668 | skip(ctx, ';'); 669 | if (ctx->tok != ')') { 670 | t = gjmp(ctx, 0); 671 | expr(ctx); 672 | gjmp(ctx, n - ctx->ind - 5); 673 | gsym(ctx, t); 674 | n = t + 4; 675 | } 676 | } 677 | skip(ctx, ')'); 678 | block(ctx, &a); 679 | gjmp(ctx, n - ctx->ind - 5); /* jmp */ 680 | gsym(ctx, a); 681 | } else if (ctx->tok == TOK_ASM) { 682 | *(char *)(ctx->sym_stk + IDX_ASM_EMIT) = ' '; 683 | *(char *)(ctx->sym_stk + IDX_ASM_MOV) = ' '; 684 | *(char *)(ctx->sym_stk + IDX_ASM_EAX) = ' '; 685 | while (ctx->tok == TOK_ASM) { 686 | next(ctx); 687 | if (ctx->tok == TOK_ASM_EMIT) { 688 | next(ctx); 689 | if (ctx->tok == '(') 690 | next(ctx); 691 | if (ctx->tok == TOK_NUM) { 692 | if(ctx->tokc == 0) 693 | ctx->ind++; 694 | else 695 | o(ctx, ctx->tokc); 696 | next(ctx); 697 | } 698 | if (ctx->tok == ')') 699 | next(ctx); 700 | } else if (ctx->tok == TOK_ASM_MOV) { 701 | next(ctx); 702 | skip(ctx, TOK_ASM_EAX); 703 | skip(ctx, ','); 704 | expr(ctx); 705 | } 706 | } 707 | *(char *)(ctx->sym_stk + IDX_ASM_EMIT) = '!'; 708 | *(char *)(ctx->sym_stk + IDX_ASM_MOV) = '!'; 709 | *(char *)(ctx->sym_stk + IDX_ASM_EAX) = '!'; 710 | } else if (ctx->tok == '{') { 711 | next(ctx); 712 | /* declarations */ 713 | decl(ctx, 1); 714 | while(ctx->tok != '}') 715 | block(ctx, l); 716 | next(ctx); 717 | } else { 718 | if (ctx->tok == TOK_RETURN) { 719 | next(ctx); 720 | if (ctx->tok != ';') 721 | expr(ctx); 722 | ctx->rsym = gjmp(ctx, ctx->rsym); /* jmp */ 723 | } else if (ctx->tok == TOK_BREAK) { 724 | next(ctx); 725 | *(int *)l = gjmp(ctx, *(int *)l); 726 | } else if (ctx->tok != ';') 727 | expr(ctx); 728 | skip(ctx, ';'); 729 | } 730 | } 731 | 732 | /* 'l' is true if local declarations */ 733 | decl(pctx_t ctx, int l) 734 | { 735 | int a, sa; 736 | 737 | while (ctx->tok == TOK_INT | ctx->tok != -1 & !l) { 738 | if (ctx->tok == TOK_INT) { 739 | next(ctx); 740 | while (ctx->tok != ';') { 741 | if (l) { 742 | ctx->loc = ctx->loc + 4; 743 | *(int *)ctx->tok = -ctx->loc; 744 | next(ctx); 745 | } else { 746 | *(int *)ctx->tok = ctx->glo; 747 | next(ctx); 748 | if (ctx->tok == '[') { 749 | next(ctx); 750 | ctx->glo = ctx->glo + ctx->tokc + 3 & -4; /* align heap */ 751 | next(ctx); 752 | skip(ctx, ']'); 753 | } 754 | else { 755 | ctx->glo = ctx->glo + 4; 756 | } 757 | } 758 | if (ctx->tok == ',') 759 | next(ctx); 760 | } 761 | skip(ctx, ';'); 762 | } else { 763 | /* patch forward references (XXX: do not work for function 764 | pointers) */ 765 | gsym(ctx, *(int *)(ctx->tok + 4)); 766 | /* put function address */ 767 | *(int *)ctx->tok = ctx->ind; 768 | next(ctx); 769 | skip(ctx, '('); 770 | a = 8; 771 | while (ctx->tok != ')') { 772 | /* read param name and compute offset */ 773 | *(int *)ctx->tok = a; 774 | a = a + 4; 775 | next(ctx); 776 | if (ctx->tok == ',') 777 | next(ctx); 778 | } 779 | next(ctx); /* skip ')' */ 780 | ctx->rsym = ctx->loc = 0; 781 | o(ctx, 0xe58955); /* push %ebp, mov %esp, %ebp */ 782 | sa = oad(ctx, 0xec81, 0); /* sub $xxx, %esp */ 783 | block(ctx, 0); 784 | gsym(ctx, ctx->rsym); 785 | o(ctx, 0xc9); // leave 786 | oad(ctx, 0xc2, a - 8); // ret $xx 787 | ctx->ind = ctx->ind - 2; 788 | *(int *)sa = ctx->loc; /* save local variables */ 789 | } 790 | } 791 | } 792 | 793 | findsym(module, name) 794 | { 795 | int i, n; 796 | int nt_headers, export_dir; 797 | int names, funcs, nameords; 798 | int string, nameord, funcrva; 799 | 800 | nt_headers = module + *(int *)(module + 60); 801 | export_dir = module + *(int *)(nt_headers + 120); 802 | if (*(int *)(export_dir + 32) == 0) 803 | return 0; 804 | names = module + *(int *)(export_dir + 32); // export_dir->AddressOfNames 805 | funcs = module + *(int *)(export_dir + 28); // export_dir->AddressOfFunctions 806 | nameords = module + *(int *)(export_dir + 36); // export_dir->AddressOfNameOrdinals 807 | n = *(int *)(export_dir + 24); // export_dir->NumberOfNames 808 | for (i = 0; i < n; i++) { 809 | string = module + *(int *)(names + i*4); 810 | if (!strcmp(name, string)) { 811 | nameord = *(short *)(nameords + i*2); 812 | funcrva = *(int *)(funcs + nameord*4); 813 | return module + funcrva; 814 | } 815 | } 816 | return 0; 817 | } 818 | 819 | dlsym(pctx_t ctx, int m, int n) 820 | { 821 | int p, r; 822 | 823 | if (m) 824 | return findsym(m, n); 825 | p = ctx->mods; 826 | while (*(int *)p) { 827 | if ((r = findsym(*(int *)p, n)) != 0) 828 | return r; 829 | p = p + 4; 830 | } 831 | return 0; 832 | } 833 | 834 | myisalnum(c) { 835 | return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9'; 836 | } 837 | 838 | myisspace(c) { 839 | return c == ' ' || c == '\t' || c == '\r' || c == '\n'; 840 | } 841 | 842 | myisdigit(c) { 843 | return c >= '0' && c <= '9'; 844 | } 845 | 846 | mystrncmp(s1, s2, len) 847 | { 848 | int c; 849 | 850 | while(len--) { 851 | if ((c = *(char *)s1 - *(char *)s2) != 0 || !*(char *)s1) 852 | return c; 853 | s1++; s2++; 854 | } 855 | return 0; 856 | } 857 | 858 | mystrstr(s1, s2) 859 | { 860 | int len; 861 | 862 | len = strlen(s2); 863 | while (*(char *)s1) { 864 | if (*(char *)s1 == *(char *)s2) { 865 | if (!mystrncmp(s1, s2, len)) 866 | return s1; 867 | } 868 | s1++; 869 | } 870 | return 0; 871 | } 872 | 873 | mystrtol(s) 874 | { 875 | int v, c; 876 | 877 | while (myisspace(*(char *)s)) 878 | s++; 879 | v = 0; 880 | if (*(char *)s == '0' && *(char *)(s + 1) == 'x') { 881 | s++; s++; 882 | while ((c = *(char *)s++) >= '0' && c <= '9' || (c | 0x20) >= 'a' && (c | 0x20) <= 'f') { 883 | if (c > '9') 884 | c = (c | 0x20) - 39; 885 | v = v * 16 + c - '0'; 886 | } 887 | } 888 | else { 889 | while ((c = *(char *)s++) >= '0' && c <= '9') { 890 | v = v * 10 + c - '0'; 891 | } 892 | } 893 | return v; 894 | } 895 | 896 | __declspec(naked) void end_of_code(void) {} 897 | 898 | #pragma comment(lib, "crypt32") 899 | __declspec(dllimport) int __stdcall CryptBinaryToStringA (int, int, int, int, int); 900 | #define CRYPT_STRING_BASE64 1 901 | 902 | output_thunks(code, codesize, name) 903 | { 904 | int i, j; 905 | char m_buffer[20000] = { 0 }; 906 | char *m_thunks[100]; 907 | 908 | int buflen = sizeof(m_buffer) / sizeof(*m_buffer); 909 | CryptBinaryToStringA(code, codesize, CRYPT_STRING_BASE64, m_buffer, &buflen); 910 | char *src = m_buffer, *p = m_buffer; 911 | for (j = 0; *src; j++) { 912 | m_thunks[j] = p; 913 | for(i = 0; i < 512 && *src; i++) { 914 | while (*src == '\r' || *src == '\n') 915 | src++; 916 | *p++ = *src++; 917 | } 918 | *p++ = 0; 919 | } 920 | 921 | printf("' Size=%d\n", codesize); 922 | for(i = 0; i < j; i++) { 923 | if (i % 10 == 0) 924 | printf("Private Const %s%d = _\n", name, i / 10 + 1); 925 | printf(" \"%s\"%s\n", m_thunks[i], i % 10 < 9 && i < j-1 ? " & _" : ""); 926 | } 927 | } 928 | 929 | main(n, t) 930 | { 931 | output_thunks(compile, (int)end_of_code - (int)compile, "STR_THUNK"); 932 | 933 | #ifdef _DEBUG 934 | return test(n, t); 935 | #endif 936 | } 937 | 938 | #ifdef _DEBUG 939 | #include "test.c" 940 | #endif 941 | --------------------------------------------------------------------------------