I have a written code for Windows, and now am trying to port to Linux, but not sure if it is possible or not.
My Question: I am trying to callback to a function that is in the executable from the shared library. How do I do that?
This is the compilation output:
Output:
build/release-linux-ppc64/ioq3ded.ppc64
build/release-linux-ppc64/ioquake3.ppc64
build/release-linux-ppc64/baseq3/cgameppc64.so
build/release-linux-ppc64/baseq3/qagameppc64.so
build/release-linux-ppc64/baseq3/uippc64.so
build/release-linux-ppc64/missionpack/cgameppc64.so
build/release-linux-ppc64/missionpack/qagameppc64.so
build/release-linux-ppc64/missionpack/uippc64.so
make[2]: Entering directory `/r/home7/XXX/ioquake3'
make[2]: `build/release-linux-ppc64/ioq3ded.ppc64' is up to date.
make[2]: `build/release-linux-ppc64/ioquake3.ppc64' is up to date.
LD build/release-linux-ppc64/baseq3/cgameppc64.so
LD build/release-linux-ppc64/baseq3/qagameppc64.so
LD build/release-linux-ppc64/baseq3/uippc64.so
LD build/release-linux-ppc64/missionpack/cgameppc64.so
LD build/release-linux-ppc64/missionpack/qagameppc64.so
LD build/release-linux-ppc64/missionpack/uippc64.so
This is the command that I run to execute my program, that is why I figured "ioq3ded.ppc64" to be my EXECUTABLE.
./ioq3ded.ppc64 +set fs_game Mod +set sv_pure 0 +set vm_game 0 +set vm_cgame 0 +set vm_ui 0 +set dedicated 1 +exec something_117.cfg
This is the code for Windows:
//Called function
__declspec(dllexport) void UnLinkLinkroutingcache( void )
{
//code
}
//Callback location
#include<windows.h>
typedef void (* fUnLinkLinkroutingcache_t)( void );
void fUnLinkLinkroutingcache( fUnLinkLinkroutingcache_t pUnLinkLinkroutingcache )
{
pUnLinkLinkroutingcache(); return;
}
fUnLinkLinkroutingcache_t pUnLinkLinkroutingcache;
void callUnlinkLink(void)
{
HMODULE hLib;
//fUnLinkLinkroutingcache_t pUnLinkLinkroutingcache;
hLib = LoadLibrary(TEXT("ioquake3.exe"));
if (hLib == NULL)
{
//Module not found, permission denied, ...
return 0; //inform caller of error
}
pUnLinkLinkroutingcache = (fUnLinkLinkroutingcache_t)GetProcAddress(hLib, TEXT("UnLinkLinkroutingcache"));
if ( pUnLinkLinkroutingcache == NULL)
{
return 0;
}
fUnLinkLinkroutingcache(pUnLinkLinkroutingcache);
}
I tried to port this code to Linux, but I can't seem to load the exe.
//Called function
extern void UnLinkLinkroutingcache( void )
//Callback location
void callUnlinkLink(void)
{
void* handle;
void (*initializer)(void);
FILE *fp;//zgzg2020
fp = fopen("HereIsMe.txt", "a");
if( fp != NULL )
{
fprintf(fp, "%d", 1 );
fprintf(fp, "\n" );
}
fclose(fp);
handle = dlopen("./ioq3ded.ppc64", RTLD_LAZY);
if(handle == NULL) {
// report error ...
fp = fopen("ICantFindFile.txt", "a");
if( fp != NULL )
{
fprintf(fp, "%d", 1 );
fprintf(fp, "\n" );
}
fclose(fp);
exit(1);return;
} else {
initializer = dlsym(handle,"UnLinkLinkroutingcache");
if(initializer == NULL) {
// report error ...
fp = fopen("ICantFindFfunction.txt", "a");
if( fp != NULL )
{
fprintf(fp, "%d", 1 );
fprintf(fp, "\n" );
}
fclose(fp);
exit(1);return;
} else {
// cast initializer to its proper type and use
(*initializer)();
}
// use the result in a call to dlsym
}
}
Unfortunately, dlopen will not suffice for this purpose as many other posters have said. It's only capable of loading shared libraries. If you pass NULL instead of a shared library path, you can look up any symbols that the run-time linker has not stripped from the main executable image (there aren't many).
However, if you want to call functions within an executable compiled without -rdynamic, try LD_PRELOAD'ing your own shared library that (on startup) locates the real path to your executable file via /proc/self/exe, memory maps it, and then reads the symbol table on that mapping (or other executable headers) to locate and interpret symbols within the main executable.
From there, it's just a matter of defining a few function pointers in your shared library that match the prototype of the function you wish to call, assigning them the location of the symbol in the binary, and calling the function pointer as normal.
You can't dlopen executables in Linux -- the function only works on shared libraries (.so, roughly equivalent to .dll on Windows).
What are you trying to accomplish?
If ioq3ded.ppc64 is really a .so (doesn't look like it), have you checked what it exports?
Have you checked errno when you get a null return from dlopen (assuming it is a .so file here, as #duskwuff says, everything else would fail)?
The function dlopen() loads the dynamic library file named by the null-terminated string filename and returns an opaque "handle" for the dynamic library. If filename is NULL, then the returned handle is for the main program. Which does mean it has to be dynamic library.
Related
I created a dll of a simple function in Matlab using this command:
mcc -t -L C -W lib:testfunctionLib -T link:lib testfunction.m libmmfile.mlib
The simple function looks like:
function y = testfunction(x)
y = x + 10;
end
I need to call the dll via c-code. This is what i'm using to get the result of the computation with the dll-function into a textfile:
#include <windows.h>
#include <stdio.h>
int main()
{
int z = 1;
FILE *Testfile;
typedef int(*BinaryFunction_t) (int);
BinaryFunction_t AddNumbers;
int result;
BOOL fFreeResult;
HINSTANCE hinstLib = LoadLibraryA("testfunctionLib.dll");
if (hinstLib != NULL)
{
AddNumbers = (BinaryFunction_t)GetProcAddress(hinstLib, "testfunction");
if (AddNumbers != NULL)
result = (*AddNumbers) (z);
fFreeResult = FreeLibrary(hinstLib);
Testfile = fopen("Testfile.txt", "a");
fprintf(Testfile, "%i\n", result);
fclose(Testfile);
}
else
{
Testfile = fopen("Testfile.txt", "a");
fprintf(Testfile, "NOT");
fclose(Testfile);
}
}
I always get a 'NOT' in my textfile because the c-code can't extract the function out of the dll. Why doesn't this work? The c-code for getting the dll-function should be ok, i tested it with a dll created within visual studio.
I know that the library failed to load, but i don't receive any error message.. I also tried to build the dll by the Matlab Coder. I get i lot of different files (c,h,etc) and a single dll-file called testfunction. But including this dll is still not working..
I tried to list imported DLL of PE file using following code, but it didn't work and windows says that exe has stopped working when I run it. In code, I simply mapped given exe file into memory using CreateFileMapping function and then explorer each section using appropriate structures given in Win32 API. How can I correct it?
#include <stdio.h>
#include <windows.h>
//add Pointer Values
#define MakePtr( cast, ptr, addValue ) (cast)( (unsigned long)(ptr)+(unsigned long)(addValue))
int main(int argc , char ** argv) //main method
{
HANDLE hMapObject, hFile;//File Mapping Object
LPVOID lpBase;//Pointer to the base memory of mapped
PIMAGE_DOS_HEADER dosHeader;//Pointer to DOS Header
PIMAGE_NT_HEADERS ntHeader;//Pointer to NT Header
PIMAGE_IMPORT_DESCRIPTOR importDesc;//Pointer to import descriptor
hFile = CreateFile(argv[1],GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);//Open the Exe File
if(hFile == INVALID_HANDLE_VALUE){
printf("\nERROR : Could not open the file specified\n");
}
hMapObject = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
lpBase = MapViewOfFile(hMapObject,FILE_MAP_READ,0,0,0);//Mapping Given EXE file to Memory
dosHeader = (PIMAGE_DOS_HEADER)lpBase;//Get the DOS Header Base
//verify dos header
if ( dosHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
ntHeader = MakePtr(PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew);//Get the NT Header
//verify NT header
if (ntHeader->Signature == IMAGE_NT_SIGNATURE ){
importDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, dosHeader,ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (importDesc->Name)
{
printf("%s\n",MakePtr(char*, dosHeader,importDesc->Name));
importDesc++;
}
}
}
getchar();
}
The content of the list you are looking for is contained in a section (like almost everything in a PE image). You must access the section where the directory is pointing to. Take a look at the code of Matt Pietrek (PeDump) to see how it works.
I'm building a new 64bit Debian Squeeze server, and Postgres 8.4 reports the well documented 'undefined __gxx_personality_v0' error when I try to restore a database.
The lib builds/installs fine.
However, the source is c, not c++ which seems to be where __gxx_personality_v0 belongs.
The code is from a 32bit Etch/postgres 8.1 environmnet.
I'm kind of stuck - but I bet the solution is very simple!
Test to see whether the issue is actually related to PostgreSQL, or if it is a problem with your library build. Here's a simple program you can use to dlopen() your library and resolve a symbol. Compile it with:
gcc dlopentest.c -o dlopentest -ldl
... and run it as:
./dlopentest /path/to/my/lib.so somesymbol
or for more info prefix LD_DEBUG=symbols (for other options LD_DEBUG=help) eg:
LD_DEBUG=symbols ./dlopentest /path/to/my/lib somesymbol
Which symbol to look for depends on your code and what it's for. You haven't provided enough information to say.
This test program won't work with any library that requires symbols from the postgresql executable in order to load and init, so if your code is (for example) a procedural language it won't load. Most simple modules load fine, though.
You should also examine the output of:
ldd /path/to/your/library.so
to see if it's linking to libstdc++ or anything else you don't expect.
Here's the test program:
// Compile with a c99 compiler; I don't use oldstyle declarations
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char * argv[]) {
if (argc != 3) {
printf("Usage: %s /path/to/lib/to/load symbol_to_resolve\n", argv[0]);
printf(" eg: %s libc.so.6 gettimeofday\n", argv[0]);
return 1;
}
char * err;
const char * const libname = argv[1];
const char * const symname = argv[2];
dlerror(); // clear dl error state before starting work
void * libhandle = dlopen(libname, RTLD_LAZY);
if ( (err = dlerror()) != NULL ) {
printf("Failed to load library: %s\n", err);
return 2;
}
void * symhandle = dlsym(libhandle, symname);
if ( (err = dlerror()) != NULL ) {
printf("Failed to load symbol: %s\n", err);
return 2;
}
printf("Successfully retrieved symbol %s from library %s\n", symname, libname);
// Optional since we're existing, but good for testing:
if ( (err = dlerror()) != NULL ) {
printf("Failed to close lib during exit: %s\n", err);
return 2;
}
return 0;
}
I need to load two dynamic libraries and there is one function name confliction. So I use the the command "objcopy --redefine-sym add=new_add libmy_test.so libmy_test_new.so" to modify the symbol name.
But it still reports "Error: ./libmy_test_new.so: undefined symbol: new_add"
The following are my test codes.
void *lib_handle2 = dlopen("./libmy_test_new.so", RTLD_NOW);
if (NULL == lib_handle2) {
printf("Error: %s\n", dlerror());
goto err1;
}
fp_add f_add2 = dlsym(lib_handle2, "new_add");
if (NULL == f_add2) {
printf("Error: %s\n", dlerror());
goto err2;
}
According to this page, it seems it does not work with dynamic symbol. More explanation are available in the original thread. If you want to use both symbol, then you somehow need to relink one of the libraries. However if you want only one of the symbol, then linking order might help you.
Maybe the solution is creating a wrapper library, in which you dlsopen the two libs, create two new symbol, and assign them using dlsym with the correct handle.
void *lib_handle1 = dlopen("./lib1.so", RTLD_NOW);
void *lib_handle2 = dlopen("./lib2.so", RTLD_NOW);
fp_add f_add1 = dlsym((lib_handle1, "add");
fp_add f_add2 = dlsym(lib_handle2, "add");
Of course it does not solve the problem of call generated inside the libraries.
I'm having trouble getting libsndfile-1.dll to work in my MSVC project. I can load the library and retrieve the version string from the dll by calling sf_command() from my code. However, I can't seem to get sf__open() to return a SNDFILE pointer.
I've also noticed that I can't get fopen() to return a FILE pointer either (maybe this is related, I think sf_open() uses fopen()!?).
I'm pretty new to MSVC, C/C++ and windows in general so I'm probably missing something really obvious.
My main.cpp looks like this:
#include <windows.h>
#include <stdio.h>
#include "sndfile.hh"
// create some function pointers to point to the dll function addresses
// I'm winging this a bit. hopefully it's right!? seems to work!
typedef int (*SF_COMMAND)(SNDFILE*, int, void*, int);
typedef SNDFILE* (*SF_OPEN)(const char*, int, SF_INFO*);
int main()
{
// dll handle
HINSTANCE hDLL = NULL;
// create some vars to store the dll funcs in
SF_COMMAND sf_command;
SF_OPEN sf_open;
// load the dll
hDLL = LoadLibrary(L"libsndfile-1.dll");
// check the dll loaded
if( NULL == hDLL )
{
printf("Error, Could not load library \n");
return 1;
}
// get the dll funcs
sf_command = (SF_COMMAND)GetProcAddress(hDLL, "sf_command");
sf_open = (SF_OPEN)GetProcAddress(hDLL, "sf_open");
// check we got the funcs
if(!(sf_command && sf_open)){
printf("Error exporting dll functions \n");
return 2;
}
// all good so far!
// try the first function
char* version_string[sizeof(char*)*4];
int res = sf_command(NULL, SFC_GET_LIB_VERSION, &version_string, sizeof(version_string));
if(res){
// all good!
printf("Version: %s \n", version_string);
}
// now try and create a SNDFILE pointer
SF_INFO info;
SNDFILE* sfp = sf_open("c:\\Godspeed.aif", SFM_READ, &info);
if(sfp){
printf("Hurray! successfully opened the SNDFILE!! \n");
}else{
printf("Doh! couldn't open the SNDFILE!! \n");
// Grr!!
return 3;
}
return 0;
}
The project builds and exits with code 3 (couldn't open the file! (I'm pretty sure the file is there!!)).
When I run the exe the output is:
Version: libsndfile-1.0.17
Doh! couldn't open the SNDFILE
Does anyone have any suggestions as to where I'm going wrong?
Many thanks,
Josh.
Hmm, I really should learn not to post to forums late at night!
I had another attempt this morning and had the file open within minutes.
I was getting my paths all wrong (not used to these weird windows paths)!
I tried using a relative path and bingo!
Hope that helps someone!