My compiled TCL library (Tcl8.6.7, win7) didn't export the functions in tclOODecls.h. I exported the functions by putting: #define TCLAPI extern DLLEXPORT in tclOODecls.h before the auto generated section.
I would like to know why the functions were not exported by default and the preferred way of enabling the export.
The symbols have been defined to use MODULE_SCOPE. See issue 3010352 which mentions this a while ago. The idea is that if you want to use these symbols you should be using the Tcl stubs linking mechanism and define the USE_TCLOO_STUBS macro and link with the stubs library (tclstub86). The functions are in there - just not exported on the DLL exports.
From tcl.h:
/*
* Include platform specific public function declarations that are accessible
* via the stubs table. Make all TclOO symbols MODULE_SCOPE (which only
* has effect on building it as a shared library). See ticket [3010352].
*/
Example of static embedding Tcl with TclOO API usage
The following code will build an executable that works like the standard Tcl shell but includes an additional command that accesses the TclOO API as a demonstration.
/* Demonstrate embedding Tcl and using the TclOO API.
*
* Build with MSVC (adjust paths for local setup):
*
* cl -nologo -W3 -MT -Zi -GL -DSTATIC_BUILD -Ic:\opt\tcl\include test_embed_oo.c \
* -Fe:test_embed_oo.exe -link -debug -subsystem:console -ltcg -libpath:C:\src\tcl\kitgen\8.6\tcl\win\Release_VC13 \
* tcl86ts.lib user32.lib ws2_32.lib netapi32.lib
*
* Requires a static libary if Tcl (tcl86ts.lib on windows)
*/
#include <tcl.h>
#include <tclOO.h>
#include <locale.h>
static int
GetObjectNameCmd(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[])
{
int r = TCL_ERROR;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "object");
return r;
}
Tcl_Object object = Tcl_GetObjectFromObj(interp, objv[1]);
if (object != NULL) {
Tcl_Obj *resultObj = Tcl_GetObjectName(interp, object);
if (resultObj != NULL) {
Tcl_SetObjResult(interp, resultObj);
r = TCL_OK;
}
}
return r;
}
#define TCL_LOCAL_APPINIT Custom_AppInit
int
Custom_AppInit(Tcl_Interp *interp)
{
Tcl_CreateObjCommand(interp, "getobjectname", GetObjectNameCmd, NULL, NULL);
return Tcl_Eval(interp, "source test_embed_oo.tcl");
}
#include "c:/src/tcl/kitgen/8.6/tcl/win/tclAppInit.c"
Embed Tcl using dynamic loading
Tcl can be linked to an application dynamically using the Tcl stubs linkage mechanism. This requires loading two functions from the DLL and then initializing the stubs table. The following shows this with TclOO access enabled.
/* Demonstrate embedding Tcl and using the TclOO API via stubs
*
* Build with MSVC (adjust paths for local setup):
*
* cl -nologo -W3 -MD -Zi -GL -Ic:\opt\tcl\include test_embed_oo_ex.c \
* -Fe:test_embed_oo_ex.exe -link -debug -ltcg -subsystem:console \
* -libpath:C:\opt\tcl\lib tclstub86.lib user32.lib
*
* Dynamically loads Tcl and then uses stubs for API access.
*/
#define WIN32_LEAN_AND_MEAN
#define STRICT
#include <windows.h>
#include <locale.h>
#define USE_TCL_STUBS
#define USE_TCLOO_STUBS
#include <tcl.h>
#include <tclOO.h>
static int
GetObjectNameCmd(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[])
{
int r = TCL_ERROR;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "object");
return r;
}
Tcl_Object object = Tcl_GetObjectFromObj(interp, objv[1]);
if (object != NULL) {
Tcl_Obj *resultObj = Tcl_GetObjectName(interp, object);
if (resultObj != NULL) {
Tcl_SetObjResult(interp, resultObj);
r = TCL_OK;
}
}
return r;
}
typedef Tcl_Interp *(*LPFNTCLCREATEINTERP)();
typedef void *(*LPFNTCLFINDEXECUTABLE)(const char *);
static Tcl_Interp *
InitializeTcl(int argc, char *argv[])
{
Tcl_Interp *interp = NULL;
//Tcl_DString dString;
char szLibrary[16];
int nMinor;
HINSTANCE hTcl = NULL;
for (nMinor = 6; hTcl == NULL && nMinor > 4; nMinor--) {
wsprintfA(szLibrary, "tcl8%d.dll", nMinor);
hTcl = LoadLibraryA(szLibrary);
}
if (hTcl != NULL) {
LPFNTCLCREATEINTERP lpfnTcl_CreateInterp;
LPFNTCLFINDEXECUTABLE lpfnTcl_FindExecutable;
lpfnTcl_CreateInterp = (LPFNTCLCREATEINTERP)
GetProcAddress(hTcl, "Tcl_CreateInterp");
lpfnTcl_FindExecutable = (LPFNTCLFINDEXECUTABLE)
GetProcAddress(hTcl, "Tcl_FindExecutable");
if (lpfnTcl_CreateInterp != NULL) {
interp = lpfnTcl_CreateInterp();
if (interp != NULL) {
Tcl_InitStubs(interp, "8.6", 0);
#ifdef USE_TCLOO_STUBS
Tcl_OOInitStubs(interp);
#endif
lpfnTcl_FindExecutable(argv[0]);
Tcl_InitMemory(interp);
Tcl_Init(interp);
}
}
}
return interp;
}
/*
* Embed tcl interpreter into a C program.
*/
int
main(int argc, char *argv[])
{
Tcl_Interp *interp = NULL;
int r = TCL_ERROR;
setlocale(LC_ALL, "C");
interp = InitializeTcl(argc, argv);
if (interp == NULL) {
fprintf(stderr, "error: failed to initialize Tcl runtime\n");
} else {
Tcl_CreateObjCommand(interp, "getobjectname", GetObjectNameCmd, NULL, NULL);
if (argc > 1) {
r = Tcl_EvalFile(interp, argv[1]);
printf(Tcl_GetStringResult(interp));
}
Tcl_DeleteInterp(interp);
}
return r;
}
To test this you want a file that contains some tcl code that can call getobjectname and run the executable with the path to this file as the only argument.
Related
I have a neural network trained in Matlab. Now, I want to use this network in Fortran. So, I followed the instructions given here: https://www.mathworks.com/help/deeplearning/ref/network.genfunction.html:
%% First, train a static network and calculate its outputs for the training data.
[x,t] = bodyfat_dataset;
bodyfatNet = feedforwardnet(10);
bodyfatNet = train(bodyfatNet,x,t);
y = bodyfatNet(x);
%% Next, generate and test a MATLAB function. Then the new function is compiled to a shared/dynamically linked library with mcc.
genFunction(bodyfatNet,'bodyfatFcn');
y2 = bodyfatFcn(x);
accuracy2 = max(abs(y-y2))
mcc -W lib:libBodyfat -T link:lib bodyfatFcn
This leads to the generation of files with extensions .c, .h and .so
In the Fortran code test.F90, I want to be able to compute y_test for a given x_test:
y_test = bodyfatNet(x_test); Could you please tell me how this can be done/written?
Here below is my Makefile. I can make an executable from object file test.o and the shared object .so:
FORTRAN_COMPILER=gfortran
#FORTRAN_FLAGS=-O3 -Wall -Wextra -std=f2008
FORTRAN_FLAGS=-ffree-line-length-none
OBJ2 = libBodyfat.so
SRC1= test.F90
OBJ1 = $(SRC1:.F90=.o)
LIBS = $(OBJ1) $(OBJ2)
%.o: %.F90
#echo 'converting .F90 files to .o'
$(FORTRAN_COMPILER) $(FORTRAN_FLAGS) -o $# -c $<
binary: $(LIBS)
#echo 'make an executable from objet files (.o) and the shared object (.so)'
$(FORTRAN_COMPILER) $(FORTRAN_FLAGS) -o $# $(LIBS)
clean:
#echo 'cleaning'
#rm -f *.mod *.o binary
I am not certain if utilizing only ‘.so’ would suffice. But the more general question is how from test.F90 I can use the network.
UPDATE:
As suggested by PierU, the problem is more of "how to call C routines from Fortran?". Below, you find the content of the generated .h file and .c file:
/*
* MATLAB Compiler: 8.2 (R2021a)
* Date: Wed Feb 8 15:21:13 2023
* Arguments: "-B""macro_default""-W""lib:libBodyfat""-T""link:lib""bodyfatFcn"
*/
#ifndef libBodyfat_h
#define libBodyfat_h 1
#if defined(__cplusplus) && !defined(mclmcrrt_h) && defined(__linux__)
# pragma implementation "mclmcrrt.h"
#endif
#include "mclmcrrt.h"
#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif
/* This symbol is defined in shared libraries. Define it here
* (to nothing) in case this isn't a shared library.
*/
#ifndef LIB_libBodyfat_C_API
#define LIB_libBodyfat_C_API /* No special import/export declaration */
#endif
/* GENERAL LIBRARY FUNCTIONS -- START */
extern LIB_libBodyfat_C_API
bool MW_CALL_CONV libBodyfatInitializeWithHandlers(
mclOutputHandlerFcn error_handler,
mclOutputHandlerFcn print_handler);
extern LIB_libBodyfat_C_API
bool MW_CALL_CONV libBodyfatInitialize(void);
extern LIB_libBodyfat_C_API
void MW_CALL_CONV libBodyfatTerminate(void);
extern LIB_libBodyfat_C_API
void MW_CALL_CONV libBodyfatPrintStackTrace(void);
/* GENERAL LIBRARY FUNCTIONS -- END */
/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */
extern LIB_libBodyfat_C_API
bool MW_CALL_CONV mlxBodyfatFcn(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);
/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */
/* C INTERFACE -- MLF WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */
extern LIB_libBodyfat_C_API bool MW_CALL_CONV mlfBodyfatFcn(int nargout, mxArray** Y, mxArray** Xf, mxArray** Af, mxArray* X, mxArray* _U4b, mxArray* _U4c);
#ifdef __cplusplus
}
#endif
/* C INTERFACE -- MLF WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */
#endif
This is the content of .c file:
/*
* MATLAB Compiler: 8.2 (R2021a)
* Date: Wed Feb 8 15:21:13 2023
* Arguments: "-B""macro_default""-W""lib:libBodyfat""-T""link:lib""bodyfatFcn"
*/
#define EXPORTING_libBodyfat 1
#include "libBodyfat.h"
static HMCRINSTANCE _mcr_inst = NULL; /* don't use nullptr; this may be either C or C++ */
#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif
static int mclDefaultPrintHandler(const char *s)
{
return mclWrite(1 /* stdout */, s, sizeof(char)*strlen(s));
}
#ifdef __cplusplus
} /* End extern C block */
#endif
#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif
static int mclDefaultErrorHandler(const char *s)
{
int written = 0;
size_t len = 0;
len = strlen(s);
written = mclWrite(2 /* stderr */, s, sizeof(char)*len);
if (len > 0 && s[ len-1 ] != '\n')
written += mclWrite(2 /* stderr */, "\n", sizeof(char));
return written;
}
#ifdef __cplusplus
} /* End extern C block */
#endif
/* This symbol is defined in shared libraries. Define it here
* (to nothing) in case this isn't a shared library.
*/
#ifndef LIB_libBodyfat_C_API
#define LIB_libBodyfat_C_API /* No special import/export declaration */
#endif
LIB_libBodyfat_C_API
bool MW_CALL_CONV libBodyfatInitializeWithHandlers(
mclOutputHandlerFcn error_handler,
mclOutputHandlerFcn print_handler)
{
int bResult = 0;
if (_mcr_inst)
return true;
if (!mclmcrInitialize())
return false;
{
mclCtfStream ctfStream =
mclGetEmbeddedCtfStream((void *)(libBodyfatInitializeWithHandlers));
if (ctfStream) {
bResult = mclInitializeComponentInstanceEmbedded(&_mcr_inst,
error_handler,
print_handler,
ctfStream);
mclDestroyStream(ctfStream);
} else {
bResult = 0;
}
}
if (!bResult)
return false;
return true;
}
LIB_libBodyfat_C_API
bool MW_CALL_CONV libBodyfatInitialize(void)
{
return libBodyfatInitializeWithHandlers(mclDefaultErrorHandler,
mclDefaultPrintHandler);
}
LIB_libBodyfat_C_API
void MW_CALL_CONV libBodyfatTerminate(void)
{
if (_mcr_inst)
mclTerminateInstance(&_mcr_inst);
}
LIB_libBodyfat_C_API
void MW_CALL_CONV libBodyfatPrintStackTrace(void)
{
char** stackTrace;
int stackDepth = mclGetStackTrace(&stackTrace);
int i;
for(i=0; i<stackDepth; i++)
{
mclWrite(2 /* stderr */, stackTrace[i], sizeof(char)*strlen(stackTrace[i]));
mclWrite(2 /* stderr */, "\n", sizeof(char)*strlen("\n"));
}
mclFreeStackTrace(&stackTrace, stackDepth);
}
LIB_libBodyfat_C_API
bool MW_CALL_CONV mlxBodyfatFcn(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
return mclFeval(_mcr_inst, "bodyfatFcn", nlhs, plhs, nrhs, prhs);
}
LIB_libBodyfat_C_API
bool MW_CALL_CONV mlfBodyfatFcn(int nargout, mxArray** Y, mxArray** Xf, mxArray** Af,
mxArray* X, mxArray* _U4b, mxArray* _U4c)
{
return mclMlfFeval(_mcr_inst, "bodyfatFcn", nargout, 3, 3, Y, Xf, Af, X, _U4b, _U4c);
}
I'm working on embedding a TCL interpreter in my app and if I add a Tcl script to the command line, my command gets executed and works. So if I have a *.tcl script with a command like my_command 1, then the myCmd procedure is executed in the library. Then the Tcl prompt appears (%) so I can enter more commands interactively. If I then enter the command again, command is not recognized even though the command has already been created.
The structure of my code is the following. In a library named My.so, I have these functions.
int myCmd(ClientData store, Tcl_Interp *interp, int objc, Tcl_Obj * CONST *objv) {
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "my");
return TCL_ERROR;
}
val = Tcl_GetStringFromObj(objv[0], &valLen);
// ...
return TCL_OK;
}
int My_Init(Tcl_Interp *interp) {
Tcl_CreateObjCommand(interp, "my_command", myCmd, (ClientData) NULL, NULL);
// ...
if (inFile != NULL)
Tcl_EvalFile(interp, inFile);
// ...
return TCL_OK;
}
And in main.cpp I have ...
int Tcl_AppInit(Tcl_Interp *interp)
{
// ...
interp = Tcl_CreateInterp();
if (interp == NULL)
return TCL_ERROR;
if (Tcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
if (My_Init(interp) == TCL_ERROR)
return TCL_ERROR;
return TCL_OK;
}
int main(int argc, char* argv[]) {
Tcl_FindExecutable(argv[0]);
Tcl_Main(argc, argv, Tcl_AppInit);
}
You shouldn't create an interpreter in the Tcl_AppInit() function; you're given one that's already been made for you by Tcl_Main(). (You also don't need to call Tcl_FindExecutable() if you're calling Tcl_Main(); that does it for you. OTOH, that's pretty much harmless when called twice.)
I want to experiment with the programs that write programs in C code, and i want to use construction like following:
int main() {
char* srcCode="int f(int x) { return x+42; }";
int (*compiledFun)(int) = compile(srcCode);
printf("result=%d", (*compiledFun)(123));
return 0;
}
Desired output should be printed "result=165".
My question is about compile() function. I may try to put srcCode in a file, then invoke external compiler, like gcc, then try to read produced binary, probably fix some addresses, and so to fill the compiledFun memory. But I feel like that would be a very inefficient stub. Is there any way to compile a program from within a program, directly from memory to memory? Maybe some library or a subset that can be ripped off gcc sources, responsible for producting binary code from source text?
That may be important addition, all source code that should be compiled is a function that takes arguments and returns. It will not call any external libraries and function like printf, but only do some calculations and return.
Use libtcc an in-memory C compiler from TinyC.
A complete example from here https://github.com/TinyCC/tinycc/blob/mob/tests/libtcc_test.c
/*
* 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 b)
{
return a + b;
}
/* this strinc is referenced by the generated code */
const char hello[] = "Hello World!";
char my_program[] =
"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */
"extern int add(int a, int b);\n"
"#ifdef _WIN32\n" /* dynamically linked data needs 'dllimport' */
" __attribute__((dllimport))\n"
"#endif\n"
"extern const char hello[];\n"
"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(\"%s\\n\", hello);\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 i;
int (*func)(int);
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 */
for (i = 1; i < argc; ++i) {
char *a = argv[i];
if (a[0] == '-') {
if (a[1] == 'B')
tcc_set_lib_path(s, a+2);
else if (a[1] == 'I')
tcc_add_include_path(s, a+2);
else if (a[1] == 'L')
tcc_add_library_path(s, a+2);
}
}
/* 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 symbols 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);
tcc_add_symbol(s, "hello", hello);
/* relocate the code */
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0)
return 1;
/* get entry symbol */
func = tcc_get_symbol(s, "foo");
if (!func)
return 1;
/* run the code */
func(32);
/* delete the state */
tcc_delete(s);
return 0;
}
My aim is to call some function via its address. How can I do it?
I have done the next work for such aim, but at first(1) - I've got access violation ( don't know why ) and with the second I have some problems with calling function is ASM with ESP value...
The first (the problem with access violation):
#include <iostream>
#include <Windows.h>
const DWORD_PTR offset = 0x00001a90;
typedef void (__stdcall *uef)(int);
int main(void)
{
HMODULE hModule = LoadLibrary(L"C:\\Windows\\system32\\OpenAL32.dll");
DWORD_PTR addr = (DWORD_PTR)hModule + offset;
uef func = (uef)offset;
func(0);
return 0;
}
The second (problems at runtime with ESP value):
#include <iostream>
#include <Windows.h>
typedef void (__stdcall *uef)(int);
int main(void)
{
HMODULE hModule = LoadLibrary(L"C:\\Windows\\system32\\OpenAL32.dll");
uef obj = NULL;
if(hModule != NULL)
{
obj = reinterpret_cast<uef>(GetProcAddress(hModule, "alEnable"));
}
if(obj != NULL)
{
(*obj)(0);
}
if(hModule != NULL)
{
FreeLibrary(hModule);
}
return 0;
}
How could I solve this problem?
PS
And the another main question is:
How can I dynamically calculate the function address in runtime for next calling?
Thanks,
Best Regards!
First, there is a major issue (hence the access violation) with the hardcoded address offset (const DWORD_PTR offset = 0x00001a90). Don't do that! How can you know that the offsett will not be changed because of ASLR?
I want to call MessageBox() function in such way:
1). load needed library
2). get the function address
3). call it
So, for such aim as I understand, I should define new type with all types of arguments in MessageBox function.
It returnes INT and accepts: HWND, LPCSTR, LPCSTR, UNIT.
So I registred new type:
typedef int(__stdcall *msgbox)(HWND, LPCSTR, LPCSTR, UINT);
I have problems with calling such function. Does such way work for all functions or only for exported?
How can I call MessageBox exactly in such way?
Full code:
#include <iostream>
#include <windows.h>
using namespace std;
typedef int(__stdcall *msgbox)(HWND, LPCSTR, LPCSTR, UINT);
int main(void)
{
HINSTANCE__ *hModule = LoadLibrary(L"\\Windows\\System32\\User32.dll");
msgbox *me = 0;
if(hModule != 0)
{
me = (msgbox*)GetProcAddress(hModule, "MessageBox");
}
return 0;
}
Why are you declaring everything as a pointer?
LoadLibrary returns an HMODULE, not an HINSTANCE__ * (it will work with the latter but it's always better to adhere to the documentation).
Similarly, msgbox is typedef'd to a function pointer type, so me is a msgbox, not a msgbox *.
The reason why GetProcAddress fails is because user32.dll exports 2 functions, MessageBoxA and MessageBoxW. When you simply call MessageBox in your code, macros defined in Windows.h replace it with one of the 2 actual function names depending on whether you're compiling for UNICODE or not. But when you're trying to directly access the exported function as you are doing, you need to explicitly specify which one you're trying to get a pointer to.
#include <iostream>
#include <windows.h>
typedef int(__stdcall *msgbox)(HWND, LPCSTR, LPCSTR, UINT);
int main(void)
{
HMODULE hModule = ::LoadLibrary(L"User32.dll");
msgbox me = NULL;
if( hModule != NULL ) {
me = reinterpret_cast<msgbox>( ::GetProcAddress(hModule, "MessageBoxA") );
}
if( me != NULL ) {
(*me)( NULL, "I'm a MessageBox", "Hello", MB_OK );
}
if( hModule != NULL ) {
::FreeLibrary( hModule );
}
}