Sign in to follow this  
Followers 0
JRowe

Embedded C redux

11 posts in this topic

#1 ·  Posted (edited)

Python, Perl, Ruby, Free Basic and Java all have it... no reason why AutoIt shouldn't. I revisited some of my old topics, and then dug around a bit after the embedded c topic sparked my interest.

I found TCC, which is a simple to use, small, and fast x86 c compiler. The aforementioned languages use it in libraries to compile c code during runtime, on the fly. There are two methods of using it which could be of interest: 'C Scripting' and using tccLib to generate code. I went with the latter, and compiled a dll per some instructions I found.

I'll post the dll how-to if anyone's interested. You need MingW and the TCC source distribution.

The dll is here. Docs are here.

I don't know enough about how c works to understand how this works, but I'd like to give it a shot. It's my understanding that the following c code uses tcclib to generate/compile a function, then load it into memory, similar to the way a DLL function would be loaded.

/* * Simple Test program for libtcc * * libtcc can be useful to use tcc as a "backend" for a code generator. */#include <stdlib.h>#include <stdio.h>#include <string.h>#include "libtcc.h"/* this function is called by the generated code */int add(int a, int <img src='http://www.autoitscript.com/forum/public/style_emoticons/<#EMO_DIR#>/sad.png' class='bbc_emoticon' alt=':(' />{   return a + b;}char my_program[] ="int fib(int n)\n""{\n""   if (n <= 2)\n""     return 1;\n""   else\n""    return fib(n-1) + fib(n-2);\n""}\n""\n""int foo(int n)\n""{\n"" printf(\"Hello World!\\n\");\n""    printf(\"fib(%d) = %d\\n\", n, fib(n));\n"" printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n""   return 0;\n""}\n";int main(int argc, char **argv){  TCCState *s;    int (*func)(int);   void *mem;  int size;   s = tcc_new();  if (!s) {   fprintf(stderr, "Could not create tcc state\n");    exit(1);    }   /* if tcclib.h and libtcc1.a are not installed, where can we find them */   if (argc == 2 && !memcmp(argv[1], "lib_path=",9))   tcc_set_lib_path(s, argv[1]+9); /* MUST BE CALLED before any compilation */ tcc_set_output_type(s, TCC_OUTPUT_MEMORY);  if (tcc_compile_string(s, my_program) == -1)    return 1;   /* as a test, we add a symbol that the compiled program can use.    You may also open a dll with tcc_add_dll() and use symbols from that */ tcc_add_symbol(s, "add", add);  /* get needed size of the code */   size = tcc_relocate(s, NULL);   if (size == -1)     return 1;   /* allocate memory and copy the code into it */ mem = malloc(size); tcc_relocate(s, mem);   /* get entry symbol */  func = tcc_get_symbol(s, "foo");    if (!func)  return 1;   /* delete the state */  tcc_delete(s);  /* run the code */  func(32);   free(mem);  return 0;}

There is two way communication, where the dynamically compiled code is able to call a predefined function (add). In order to implement this in AutoIt, would I use DllCallbackRegister to intercept calls to add()? Or to register a pointer to the foo/func() symbol?

The reverse also has its challenges.

The order of events goes something like this:

  • tcc_set_lib_path()
  • tcc_set_output_type()
  • tcc_compile_string()
  • tcc_get_symbol()
  • tcc_run(s, param1, param2)
  • tcc_delete(s)
Is there a need for libtcc.h in this setup, or can AutoIt and DllCall handle everything necessary and relevant?

Anyhow, I'd love to get some feedback on how I'd get this working. It's a little over my head (and/or I'm up way too late,) but I see some potential here. It would be an easy, practical method of integrating c code directly into a script. This will be fun.

Edited by JRowe

Share this post


Link to post
Share on other sites



AutoIt and DllCall can do everything as long as you know what you're doing.

Share this post


Link to post
Share on other sites

Can it make me a sandwich?

...

Sorry, I couldn't resist. Posted Image


#fgpkerw4kcmnq2mns1ax7ilndopen (Q, $0); while ($l = <Q>){if ($l =~ m/^#.*/){$l =~ tr/a-z1-9#/Huh, Junketeer's Alternate Pro Ace /; print $l;}}close (Q);[code] tag ninja!

Share this post


Link to post
Share on other sites

#include <Memory.au3>
$dll = DllOpen("libtcc.dll")

Func Add($iA, $iB)
    Return $iA + $iB
EndFunc ;==>Add

$myProgram = 'int fib(int n)' & @CRLF & _
'{'& @CRLF & _
'   if (n <= 2)'& @CRLF & _
'   return 1;'& @CRLF & _
'   else'& @CRLF & _
'   return fib(n-1) + fib(n-2);'& @CRLF & _
'}'& @CRLF & _
''& @CRLF & _
'int foo(int n)'& @CRLF & _
'{'& @CRLF & _
'   printf("Hello World!\n");'& @CRLF & _
'   printf("fib(%d) = %d\n", n, fib(n));'& @CRLF & _
'   printf("add(%d, %d) = %d\n", n, 2 * n, add(n, 2 * n));'& @CRLF & _
'   return 0;'& @CRLF & _
'}'


Global $functionState
Global $howDoIGetAFunctionPointer

$result1 = DllCall($dll, "ptr:cdecl", "tcc_new")
ConsoleWrite("Result 1 :" & @error & $result1[0] & @CRLF)
$functionState = $result1[0]

$result2 = DllCall($dll, "none:cdecl", "tcc_set_output_type", "ptr", $functionState, "int", 0)
ConsoleWrite("Result 2 :" & @error & @CRLF)

$result3 = DllCall($dll, "none:cdecl", "tcc_compile_string", "ptr", $functionState, "str", $myProgram)
ConsoleWrite("Result 3 :" & @error & @CRLF)

;/* as a test, we add a symbol that the compiled program can use.
; You may also open a dll with tcc_add_dll() and use symbols from that */
;tcc_add_symbol(s, "add", add);
$result4 = DllCall($dll, "none:cdecl", "tcc_add_symbol", "ptr", $functionState, "str", "add", "ptr", $howDoIGetAFunctionPointer) ;?!
ConsoleWrite("Result 4 :" & @error & @CRLF)

$result5 = DllCall($dll, "int:cdecl", "tcc_relocate", "ptr", $functionState, "int", 0)
ConsoleWrite("Result 5 :" & @error & @CRLF)
$size = $result5[0]
$mem = _MemGlobalAlloc($size)

DllCall($dll, "none:cdecl", "tcc_relocate", "ptr", $functionState, "ptr", $mem)
ConsoleWrite("Result 5.1 :" & @error & @CRLF)
;/* allocate memory and copy the code into it */
;mem = malloc(size);
;tcc_relocate(s, mem);

$result6 = DllCall($dll, "ptr:cdecl", "tcc_get_symbol", "ptr", $functionState, "str", "foo")
ConsoleWrite("Result 6 :" & @error & @CRLF)
$tccFunc = $result6[0]
ConsoleWrite("Result 6.1 :" & $tccFunc & @CRLF)


;/* get entry symbol */
;func = tcc_get_symbol(s, "foo");
;if (!func)
;   return 1;

DllCall($dll, "none:cdecl", "tcc_delete", "ptr", $functionState)
ConsoleWrite("Result 6.5 :" & @error & @CRLF)
;/* run the code */
;func(32);

_MemGlobalFree($mem)

I think I've got it functioning.

It's allocating a new state, setting the output parameter, compiling, assessing the size, allocating the space, and writing the compiled code into the allocated space. All without apparent errors on either side (tcc gives you debug output, as I discovered when i constructed the c code in a string.)

Anyone want to take a stab at how I'd convert the $tccFunc pointer into a usable function?

I'm thinking DllCallbackRegister could be used, but I don't know how.

Share this post


Link to post
Share on other sites

You need to be able to call the function pointer. So look at Ward's MemoryDll UDF, or if you don't need parameters, you might be able to use CallWindowProc to call the function.

(Here's me hoping the AutoIt devs decide to let us call function pointers one day :()

Share this post


Link to post
Share on other sites

I'm trying to get your 'call function by pointer' plugin to work, actually. I'd appreciate any time you spend on this. I'm thinking I need to use a different memory allocation function, and there's probably some more setup needed from the dll side... but I'll have to wait for the weekend to spend more time on this.

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

I used MSYS , per this article, using the following command/s:

gcc -O2 -shared -Wall -Wl,--export-all-symbols \
-mpreferred-stack-boundary=2 \
-march=i386 -falign-functions=0 -fno-strict-aliasing \
-DTCC_TARGET_PE -DLIBTCC -o libtcc.dll tcc.c
Edited by JRowe

Share this post


Link to post
Share on other sites

Could someone tell me how to use this library with Visual C++ 2008?

If I include libtcc.c directly into my project the only error it gives is:

fatal error C1083: Cannot open include file: 'config.h': No such file or directory

Seems simple enough, but I don't know how to fix it.

I found a precompiled static library on the internet: http://sourceforge.net/projects/tinycc-win32/

When I include the header file and add TinyCC-Win32-lib.lib to the linker, I get a bunch of redefinitions:

Error   1   error LNK2005: _malloc already defined in LIBCMTD.lib(dbgmalloc.obj)    MSVCRTD.lib
Error   2   error LNK2005: _exit already defined in LIBCMTD.lib(crt0dat.obj)    MSVCRTD.lib
Error   3   error LNK2005: _sprintf already defined in LIBCMTD.lib(sprintf.obj) MSVCRTD.lib
Error   4   error LNK2005: _free already defined in LIBCMTD.lib(dbgfree.obj)    MSVCRTD.lib
Error   5   error LNK2005: __errno already defined in LIBCMTD.lib(dosmap.obj)   MSVCRTD.lib
Error   6   error LNK2005: _strrchr already defined in LIBCMTD.lib(strrchr.obj) MSVCRTD.lib
Error   7   error LNK2005: _memmove already defined in LIBCMTD.lib(memmove.obj) MSVCRTD.lib
Error   8   error LNK2005: _strtoul already defined in LIBCMTD.lib(strtol.obj)  MSVCRTD.lib
Error   9   error LNK2005: _strchr already defined in LIBCMTD.lib(strchr.obj)   MSVCRTD.lib
Error   10  error LNK2005: _fclose already defined in LIBCMTD.lib(fclose.obj)   MSVCRTD.lib
Error   11  error LNK2005: _fputc already defined in LIBCMTD.lib(fputc.obj) MSVCRTD.lib
Error   12  error LNK2005: _fwrite already defined in LIBCMTD.lib(fwrite.obj)   MSVCRTD.lib
Error   13  error LNK2005: _strncmp already defined in LIBCMTD.lib(strncmp.obj) MSVCRTD.lib
Error   14  error LNK2005: _strtol already defined in LIBCMTD.lib(strtol.obj)   MSVCRTD.lib
Error   15  error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj)  MSVCRTD.lib
Error   16  error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj)    MSVCRTD.lib
Error   18  fatal error LNK1169: one or more multiply defined symbols found C:\Documents and Settings\HP_Administrator\Mijn documenten\Visual Studio 2008\Projects\LibCC\Debug\LibCC.exe    1

Does anyone know how to do this?

Share this post


Link to post
Share on other sites

My first guess when looking at that output would be to specify the /NODEFAULTLIB option.


Broken link? PM me and I'll send you the file!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0