├── 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 |
--------------------------------------------------------------------------------