Loading dll in windows C for cross-platform design - c

I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.
void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");
From what I found, I need to use LoadLibrary & GetProcAddress instead of dlopen & dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.

Once in my youth I created something like this:
/* dlfcn.h */
#ifndef DLFCN_H
#define DLFCN_H
#define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
#define RTLD_LOCAL 0x000 /* hide entries in this module */
#define RTLD_LAZY 0x000 /* accept unresolved externs */
#define RTLD_NOW 0x001 /* abort if module has unresolved externs */
/*
How to call in Windows:
void *h = dlopen ("path\\library.dll", flags)
void (*fun)() = dlsym (h, "entry")
*/
#ifdef __cplusplus
extern "C" {
#endif
void *dlopen (const char *filename, int flag);
int dlclose (void *handle);
void *dlsym (void *handle, const char *name);
const char *dlerror (void);
#ifdef __cplusplus
}
#endif
#endif
and dlfcn.c:
/* dlfcn.c */
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
static struct {
long lasterror;
const char *err_rutin;
} var = {
0,
NULL
};
void *dlopen (const char *filename, int flags)
{
HINSTANCE hInst;
hInst= LoadLibrary (filename);
if (hInst==NULL) {
var.lasterror = GetLastError ();
var.err_rutin = "dlopen";
}
return hInst;
}
int dlclose (void *handle)
{
BOOL ok;
int rc= 0;
ok= FreeLibrary ((HINSTANCE)handle);
if (! ok) {
var.lasterror = GetLastError ();
var.err_rutin = "dlclose";
rc= -1;
}
return rc;
}
void *dlsym (void *handle, const char *name)
{
FARPROC fp;
fp= GetProcAddress ((HINSTANCE)handle, name);
if (!fp) {
var.lasterror = GetLastError ();
var.err_rutin = "dlsym";
}
return (void *)(intptr_t)fp;
}
const char *dlerror (void)
{
static char errstr [88];
if (var.lasterror) {
sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
return errstr;
} else {
return NULL;
}
}

You could use a set of macros that change depending on the OS you're on:
#ifdef __linux__
#define LIBTYPE void*
#define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
#define LIBFUNC(lib, fn) dlsym((lib), (fn))
#elif defined(WINVER)
#define LIBTYPE HINSTANCE
#define OPENLIB(libname) LoadLibraryW(L ## libname)
#define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
#endif

Related

Can I know the file and function names from where my function is called if it's from another .c?

I'm developing a library and I would like to know some data about the caller of one of the functions I'm offering. In particular, I would need to know the file name, function name and line where my function (a redefined malloc) is being called.
EDIT: Here's a minimum working example where I can detect when a user calls malloc and "redirect" him to my own malloc function:
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "myLib.h"
int main(){
printf("Inside main, asking for memory\n");
int *p = malloc(sizeof(int));
*p = 3;
free(p);
return 0;
}
myLib.c:
#include "myLib.h"
void * myAlloc (size_t size){
void * p = NULL;
fprintf(stderr, "Inside my own malloc\n");
p = (malloc)(size);
return p;
}
#undef malloc
#define malloc(size) myAlloc(size)
myLib.h:
#ifndef MYLIB_H
#define MYLIB_H
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define malloc(size) myAlloc(size)
void * myAlloc(size_t size);
#endif
I've tried using _FILE_ _func_ and _LINE_ keywords, but I can't make it work since it's in a different module.
You could:
//mylib.h
#ifndef MYLIB_H
#define MYLIB_H
#include <stdlib.h>
// replace malloc in case it's already a macro
#ifdef malloc
#undef malloc
#endif
// I believe that from the standards point of view, this is undefined behavior
#define malloc(size) my_alloc(size, __FILE__, __LINE__, __func__)
#ifdef __GNUC__
// Allow compiler to do static checking.
__attribute__((__alloc_size__(1), __malloc__))
#endif
void *my_alloc(size_t size, const char *file, int line, const char *func);
// ^^^^^^^^ I do not like camelCase case - one snake case to rule them all.
#endif
// mylib.c
#include "mylib.h" // do not ever mix uppercase and lowercase in filenames
#undef malloc // undef malloc so we don't call ourselves recursively
#include <stdio.h>
void *my_alloc(size_t size, const char *file, int line, const char *func){
fprintf(stderr, "Och my god, you wouldn't believe it!\n"
"A function %s in file %s at line %d called malloc!\n",
func, file, line);
return malloc(size);
}
You might also see how assert does it. If you are aiming at glibc, read glibc docs replacing malloc.
Still as you discovered a user may do (malloc)(size) cicumvent macro expansion. You could do:
void *my_alloc(size_t size, const char *file, int line, const char *func);
static inline void *MY_ALLOC(size_t size) {
return my_alloc(size, NULL, 0, NULL);
}
#define MY_ALLOC(size) my_alloc(size, __FILE__, __LINE__, __func__)
// if called with `malloc()` then MY_ALLOC is expanded
// if called as `(malloc)`, then just expands to MY_ALLOC.
#define malloc MY_ALLOC
int main() {
malloc(10); // calls my_alloc(10, "main.c", 62, "main");
(malloc)(20); // calls my_alloc(20, NULL, 0, NULL);
}
GLIBC defines hidden symbols for malloc(), free()... which are called __libc_malloc(), __libc_free()...
So, you can tremendously simplify your debug macros.
In m.h, just define the following:
#if DEBUG_LEVEL > 0
extern void *__libc_malloc (size_t bytes);
extern void *myMalloc(size_t size, const char *filename, const char *funcname, int line);
#define malloc(size) myMalloc(size, __FILE__, __FUNCTION__, __LINE__)
#endif
Then you can write a program defining myMalloc() as follow (e.g. file name is m.c):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "m.h"
#if DEBUG_LEVEL > 0
void *myMalloc(
size_t size,
const char *filename,
const char *funcname,
int line
) {
fprintf(stderr, "malloc(%zu) called from %s/%s()#%d\n", size, filename, funcname, line);
return __libc_malloc(size);
}
#endif
char *dup_str(char *string) {
char *str = malloc(strlen(string) + 1);
strcpy(str, string);
return str;
}
int main(int ac, char *av[]) {
char *str;
if (av[1]) {
str = dup_str(av[1]);
} else {
str = dup_str("NULL");
}
printf("String = '%s'\n", str);
free(str);
return 0;
}
When you compile this example program in non debug mode:
$ gcc m.c -DDEBUG_LEVEL=0
$ ./a.out azerty
String = 'azerty'
When you compile your program in debug mode:
$ gcc m.c -DDEBUG_LEVEL=1
$ ./a.out azerty
malloc(7) called from m.c/dup_str()#27
String = 'azerty'

Why my C function works well, but got something wrong in PHP-Extension?

I need to call a .so shared library in PHP, so I write C code using "dlopen" and "dlsym" to do this, and it works.
sample.h:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
typedef int (*libfunc) (char *msg, int msglen);
int
sfunc(char *msg, int msglen);
sample.c:
#include "sample.h"
int
sfunc(char *msg, int msglen)
{
void *lib;
libfunc lib_func;
int result;
...
lib = dlopen(THE_LIB_PATH, RTLD_NOW);
lib_func = (libfunc) dlsym(lib, THE_LIB_FUNC);
...
result = lib_func(msg, msglen); // return 0 if success
...
dlclose(lib);
return result;
}
It always return 0.
And then I write a PHP extension as a wrapper, it takes PHP arguments and calls the C code before.
php_sample.c:
...
#include "sample.h"
...
PHP_FUNCTION(s_func)
{
char *msg;
long msglen;
int result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &msg, &msglen) == FAILURE) {
RETURN_NULL();
}
result = sfunc(msg, (int) msglen);
RETURN_LONG(result);
}
Then I added the extension(compiled to .so) to PHP and test the PHP function:
php -r "echo s_func("somestring");"
The call always failed, just return something not zero.
Why? Is there any difference?
Note: I tested this on one other computer and it works. So is there any problems about environments or something?

unresolved symbol , first referenced in

I have 4 files (2 headers, 2 source):
lcd.h,
lcd.c,
azt.h and
azt.c
I included lcd inside azt.
In lcd there's a function WriteMsg which is called inside azt,
it works fine.
But when I add a call to this function in lcd.c, I get the following error
Description Resource Path Location Type
unresolved symbol WriteMsg, first referenced in ./Includes/AutoZeroTracking.obj Joe1000 C/C++ Problem
I understand that I referenced it first at azt files, but this function is referenced in other places and I don't have this problem.
Here's the lcd.h:
#ifndef MSP
#define MSP
#include <msp430g2553.h>
#endif
#include "Utilities.h"
#include "Declarations.h"
#ifndef INCLUDES_LCD_H_
#define INCLUDES_LCD_H_
#define LCD_CALL 1
void InitLCD(unsigned char SDA,unsigned char SCL,unsigned char slaveAddress);
void StartLCD();
inline int ReadyToSend();
void SendToLcd(unsigned char* data, int size);
void WriteToLCD(int clearScreen);
void switchFrom8To4Bits();
void write2x4Bits(unsigned char bits, int is_data);
void writeCommand(unsigned char command);
inline void writeData(unsigned char data);
void ClearScreen();
void WriteWeight();
void WriteWeightMode();
inline void WriteMsg(const char* msg, int msgLen,char msgLocation,int maxDigits);
inline void WriteNum(long num,char location,int maxDigits);
void WriteTare(char num);
#endif /* INCLUDES_LCD_H_ */
here's the azt.h:
#ifndef INCLUDES_AUTOZEROTRACKING_H_
#define INCLUDES_AUTOZEROTRACKING_H_
#include "Declarations.h"
#include "LCD.h"
#include "Utilities.h"
void AZTSetup();
void AZTProcess();
void DisplayAZT();
void GetPreviousAZT();
void GetNextAZT();
void KeyPressedAZTMode(char keyPressed);
inline char HasAZTStopped();
#endif /* INCLUDES_AUTOZEROTRACKING_H_ */
the code in azt.c
void DisplayAZT()
{
WriteMsg(AZT[m_curr_azt],AZTLen[m_curr_azt],0x8A,5);
}
the call in lcd.c
void WriteWeight()
{
WriteNum(CountBy[cnt_by_idx],0x80,2);
WriteNum(NOD[n_o_d_idx],0x83,5);
WriteNum(max_weight,0x89,6);
WriteNum(idx_decimal_point,0x90,1);
WriteMsg(AZT[az_tracking_idx],AZTLen[az_tracking_idx],0x9A,3);
WriteNum(BaudRate[baud_rate_idx],0xC0,6);
WriteNum(PP2Z[percent_p2z_idx],0x9E,2);
WriteNum(wt_zero,0x94,10);
WriteNum(wt_slope,0xD4,10);
/*int i = 0;
for(i = 0; i < WEIGHT_ARR_LEN ; i++)
{
if(display_weight[i] != IGNORE_CHAR)
writeData(display_weight[i]);
}*/
}
Thanks in advance.
I removed the inline and it compiles.

rpc remote proceduer compile error

I'm working on a rpc sample program on linux. When I try to compile my remote procedure I get this error :
msg_proc.c:10:7: error: conflicting types for ‘printmessage_1’
In file included from msg_proc.c:8:0:
msg.h:22:15: note: previous declaration of ‘printmessage_1’ was here
This is the command I used to complie :
cc msg_proc.c msg_svc.c -o msg_server -lnsl
And these are my header and procedure files :
/*msg.h
*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _MSG_H_RPCGEN
#define _MSG_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MESSAGEPROG 0x20000001
#define PRINTMESSAGEVERS 1
#if defined(__STDC__) || defined(__cplusplus)
#define PRINTMESSAGE 1
extern int * printmessage_1(char **, CLIENT *);
extern int * printmessage_1_svc(char **, struct svc_req *);
extern int messageprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
#else /* K&R C */
#define PRINTMESSAGE 1
extern int * printmessage_1();
extern int * printmessage_1_svc();
extern int messageprog_1_freeresult ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_MSG_H_RPCGEN */
/*
* msg_proc.c: implementation of the
* remote procedure "printmessage"
*/
#include <stdio.h>
#include <rpc/rpc.h>
#include "msg.h"
int * printmessage_1(char **msg, struct svc_req *req) {
static int result; /* must be static! */
FILE *f;
f = fopen("/dev/console", "w");
if (f == (FILE *) NULL) {
result = 0;
return (&result);
}
fprintf(f, "%s\n", *msg);
fclose(f);
result = 1;
return (&result);
}
What's wrong with my code ?
The argument types in your printmessage_1 function match the declaration of printmessage_1_svc, not printmessage_1. – Barmar

Linux, kprobes/kretprobes: a way to recover [from registers?] probe function's arguments?

/*kprobe_example.c*/
#define FUNCNAME alloc_file /* Find something better. printk() isnt recommended */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
#include <linux/sched.h>
/*For each probe you need to allocate a kprobe structure*/
static struct kprobe kp;
/*kprobe pre_handler: called just before the probed instruction is
executed*/
int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
// dump_stack();
return 0;
}
/*kprobe post_handler: called after the probed instruction is executed*/
void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long
flags)
{
}
/* fault_handler: this is called if an exception is generated for any
* instruction within the pre- or post-handler, or when Kprobes
* single-steps the probed instruction.
*/
int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
/* Return 0 because we don't handle the fault. */
return 0;
}
int init_module(void)
{
int ret;
kp.pre_handler = handler_pre;
kp.post_handler = handler_post;
kp.fault_handler = handler_fault;
kp.addr = (kprobe_opcode_t*) kallsyms_lookup_name(FUNCNAME);
/* register the kprobe now */
if (!kp.addr) {
printk("Couldn't find %s to plant kprobe\n", FUNCNAME);
return -1;
}
if ((ret = register_kprobe(&kp) < 0)) {
printk("register_kprobe failed, returned %d\n", ret);
return -1;
}
printk("kprobe registered\n");
return 0;
}
void cleanup_module(void)
{
unregister_kprobe(&kp);
printk("kprobe unregistered\n");
}
MODULE_LICENSE("GPL");
The question is simple: I need pointers to probed (intercepted) function's arguments. Is there any way to get/recover them from registers?
The answer is jprobes.
Be afraid of redhat's example code missing my_jprobe.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name(FUNCAME);
Another problem is, that to caught and modify a return value, a better place for probing should be found (refer to http://lwn.net/Articles/132196/ for better understanding).

Resources