Runtime Tiny C Compiler for VB6
VbRtcc is a fork of OTCC by Fabrice Bellard with some additional tweaks -- relocatable code, stdcall calling convention, short *
access, _asm
for inline assembly, local and global arrays.
First download and add src\mdRtcc.bas
to your VB6 project so that all Rtcc
prefixed functions are accessible (see API
section below).
Here is a sample form that on button click compiles a C program that calls GetVersionEx
API function and returns current OS version.
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
Private m_ctx As UcsRtccContextType
Private Sub Command1_Click()
Dim pfn As Long
pfn = RtccCompile(m_ctx, _
"main(n, t, wParam, lParam) {" & vbCrLf & _
" int v; " & vbCrLf & _
" v = GlobalAlloc(0x40, 148); " & vbCrLf & _
" *(int *)v = 148; " & vbCrLf & _
" GetVersionExA(v); " & vbCrLf & _
" return *(int *)(v + 4) * 100 + *(int *)(v + 8); " & vbCrLf & _
"}")
Print CallWindowProc(pfn), "&H" & Hex(pfn)
RtccFree m_ctx
End Sub
All functions are compiled with stdcall calling convention and unresolved externals like GlobalAlloc
and GetVersionExA
are searched in currently loaded DLLs.
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.
Returned pfn
are usable until m_ctx
is destroyed with RtccFree
.
-
RtccCompile([in] ctx, [in] source, [in, optional] allocsize)
If
ctx
is new initializes internal buffers according to the optionalallocsize
. Then compiles inline Csource
toctx
, appending generated code to previously compiled code inctx
and returns a callablepfn
pointer to the entry point of the first function insource
. -
RtccFree([in] ctx)
Deallocates
ctx
internal buffers, rendering previously compiledpfn
s inctx
invalid. -
RtccGetSymbol([in] ctx, [in] name)
Searches function
name
inctx
and returns a callablepfn
pointer to its entry point or0
(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
callingg
andg
callingf
in a single source code. -
RtccPatchProto([in] addressof)
Helper function that patches a native VB6 function to become a
pfn
calling trampoline. For instance a VB6 function with declarationFunction MyProto(byval pfn As Long, a1 As Long, a2 As Long, ...) As Long
can be patched with a call toRtccPatchProto AddressOf MyProto
to jump at run-time topfn
with argumentsa1, a2, ...
.This allows calling
RtccCompile
dpfn
without resorting toCallWindowProc
or similar work-arounds that are usually slower that implementing simple trampolines withRtccPatchProto
.
See README
in lib/ottc
for original Bellard's comments.
- All local variables are
signed int
, including pointers. - Array indexing is not supported but global and local arrays declaration is possible.
- Three types of dereferencing are allowed -
*(char *)p
for byte,*(short *)p
for 16-bit word and*(int *)p
for 32-bit dword. - Pointer arithmetic uses byte offset, e.g. use
*(int *)(p + 4)
to get second dword. - Shifts are signed e.g.
i = i >> 8
extends the sign bit. - Function retval/parameters are always
int
(no types allowed) e.g.main(n, t)
returnsint
and has twoint
parameters. - Char literals are cast to dword e.g.
v = 'a'
is sign-extended - Char/strings escape allows hex values e.g.
"\x12\x5f"
and\r
,\n
and\t
- Unicode char/strings allowed with
L"string"
andL'a'
and hex word escapes withL"\x1234\xabff"
- Supported statements:
if
/else
while
for
break
return
- Supported operators:
+
-
*
/
%
!
~
>>
<<
|
&
^
++
--
&&
||
==
!=
<
>
<=
>=
- Not supported operators:
+=
(and family)?:
(ternary),
(comma in for loops too) - Block comments only (no
//
line comments) #define
supports constants only (no macro expansion)- Function
alloca
can be used for stack allocation of local arrays - Only global arrays declaration is supported w/ size in bytes e.g.
int a[100]
reserves 100 bytes (fromctx->glob
) _asm _emit <num>
allows encoding custom instructions in codegen_asm mov eax, <expr>
supported only, where<expr>
can be const/var or complex expression
- Support
short
data type (for Unicode strings) - Support inline
_asm _emit
- Implement get symbol address after compile