shared library how to link to a symbol? - c

I have:
car.cc
#include "car.h"
#include <iostream>
using namespace std;
extern "C" Car* create_object()
{
return new Car;
}
Car::Car() {
this->maxGear = 2;
this->currentGear = 1;
this->speed = 0;
}
void Car::shift(int gear) {
if (gear < 1 || gear > maxGear) {
return;
}
currentGear = gear;
}
void Car::brake() {
speed -= (5 * this->getCurrentGear());
std::cout<<"THE SPEED IS:" <<speed<<std::endl;
}
extern "C" void destroy_object( Car* object )
{
delete object;
}
car.h
#ifndef VEHICLES_CAR_H
#define VEHICLES_CAR_H
// A very simple car class
class Car {
public:
Car();
void shift(int gear);
void accelerate();
void brake();
private:
int maxGear;
int currentGear;
int speed;
};
#endif /* VEHICLES_CAR_H */
test.cc
#include "/home/car.h"
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int main()
{
/* on Linux, use "./myclass.so" */
void* handle = dlopen("/usr/lib/libCarTest.so", RTLD_LAZY);
int (*result)(int);
if (!handle)
{
}
/*dlsym(handle,"accelerate");
cout<<"IN HERE: "<<endl;
dlsym(handle,"brake");
dlclose(handle);*/
Car* (*create)();
void (*destroy)(Car*);
dlerror();
create = (Car* (*)())dlsym(handle, "create_object");
destroy = (void (*)(Car*))dlsym(handle, "destroy_object");
Car* carr = (Car*)create();
carr->brake();
destroy( carr );
dlclose(handle);
/*
Car carr;
carr.brake();
* compilation g++ test.cpp -o tst /path/libcar.so
*/
return 0;
}
After creating libMyLib.so and install it in /usr/lib i've tried to compile test.cc using: g++ test.cc -o tst -ldl. WHY do i need to include -lMyLib? is there a way to compile the code without libMyLib.so? Secondly why dlsym(handle,"brake") is not working? If i change dlsym (Car* (*).... with dlsym(handle,"brake") i get nothing. why?
Appreciate

WHY do i need to include -lMyLib?
Because you need to link to the Car::brake method.
Secondly why dlsym(handle,"brake") is not working?
Because there is no brake symbol. The method Car::brake has a complicated mangled (implementation-defined) name. You can see this in the output of nm -D.
AFAIK, you can solve it by
making all the methods of Car virtual (they will be called through a pointer, so no linking will be needed)
doing it the old C way, ie. export a free function brake() that would call the Car::brake method from the .so
making all the public methods of Car inline and defining them in the header.
emulating the virtual table approach (as we do it in C)
Combining the last two approaches:
class Car {
public:
void brake() { brake_impl(this); }
private:
void (*brake_impl)(Car*);
void do_brake(); // this would be the actual implementation
Car() : brake_impl([] (Car* c){ c->do_brake(); }) { ... }
};
Of course you could split the implementation and the interface so it's not such a mess.

Related

C - Strange struct behavior in header file

I am newbie in C. I am trying to pack a function say to a struct Person. It seems fine on single c file. (Console will print "Bye.")
// all-in-one-file.c
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
void (*say)(char *sayType);
} Person;
void person_say(char *sayType);
Person initPerson();
int main()
{
Person person = initPerson();
person.say("Bye");
return 0;
}
void person_say(char *sayType)
{
if (sayType == "Hi")
{
printf("Hi.\n");
}
else if (sayType == "Bye")
{
printf("Bye.\n");
}
else
{
printf("...\n");
}
}
Person initPerson()
{
Person per;
per.say = person_say;
return per;
}
However, the console will print "..." when I try to put the struct and function to header file.
// person.h
#ifndef _PERSON_H_
#define _PERSON_H_
typedef struct
{
void (*say)(char *sayType);
} Person;
Person initPerson();
#endif
// person.c
#include <stdio.h>
#include "person.h"
void person_say(char *sayType)
{
if (sayType == "Hi")
{
printf("Hi.\n");
}
else if (sayType == "Bye")
{
printf("Bye.\n");
}
else
{
printf("...\n");
}
}
Person initPerson()
{
Person per;
per.say = person_say;
return per;
}
// main.c
#include <stdio.h>
#include <stdlib.h>
#include "person.h"
int main()
{
Person person = initPerson();
person.say("Bye");
return 0;
}
I think I have some mistakes in header file or person.c. But I cannot find the reason and the solution to fix this problem.
sayType == "Hi" this compares the addresses, not the contents. You should use strcmp (sayType, "Hi") for comparing contents of strings.
The explanation why it looks like working when they are all in one .c file is this:
When all source is in one translation unit (that is one .c file), compiler mapped string literals with identical contents to the same address. (which is implementation defined behavior that you can not depend). Therefore, identical literals have the same address so that address comparison worked.
However, when compiled in distinct translation units, compiler has no knowledge of other translation unit while compiling one, therefore they are mapped to different addresses.

How to get the value of global static variables having same name in 2 separate files in C program

I'm trying to execute a program in C. While executing I'm getting the same value for global static variables(static int data) with the same name declared in 2 separate files program1.c and program2.c where the main() function is in program1.c The actual answer should be apple = 2 and orange = 3 but the static int data variable is getting overridden by oranges_set(3) function call. Could anyone please let me know what could be the issue? Thanks in advance.
program1.c
#include <stdio.h>
#include "program2.c"
void apples_set(int value);
int apples_get();
static int data;
void oranges_set(int value)
{
data = value;
}
int oranges_get()
{
printf("Value of oranges = %d \n",data);
return data;
}
int main(){
apples_set(2);
oranges_set(3);
printf("Apple = %d and Orange = %d",apples_get(),oranges_get());
return 0;
}
========================================================
program2.c
static int data;
void apples_set(int value)
{
data = value;
}
int apples_get()
{
printf("Value of apples = %d \n",data);
return data;
}
These are not separate files, because you include the one in the other. This is equivalent to copying the entire content of program2.c and pasting it place of the #include "program2.c" line in program1.c.
For this to work correctly, you need to compile the files as separate object files and then link those together.

LLVM Pass to insert an external function call to LLVM bitcode

I am writing an LLVM pass to instrument a C source program. I want to insert a function call before each branch instruction which calls an external function like this :
void print(int x){
printf("x = %d\n", x);
return;
}
I want to link this external function to C source code using llvm-link tool and then instrument the code using opt tool.
Ths pass that I have implemented is like this:
#include "llvm/Pass.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/IRBuilder.h"
#include <vector>
using namespace llvm;
namespace{
struct ir_instrumentation : public ModulePass{
static char ID;
Function *monitor;
ir_instrumentation() : ModulePass(ID) {}
virtual bool runOnModule(Module &M)
{
std::vector<Type *> args;
args.push_back(Type::getInt32Ty(M.getContext()));
ArrayRef<Type*> argsRef(args);
FunctionType *FT = FunctionType::get(Type::getVoidTy(M.getContext()), args, false);
Constant* myFunc = M.getOrInsertFunction("print", FT, NULL);
minitor = cast<Function>(myFunc);
for(Module::iterator F = M.begin(), E = M.end(); F!= E; ++F)
{
for(Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
{
for(BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ++BI)
{
if(isa<BranchInst>(&(*BI)) )
{
errs() << "found a branch instruction!\n";
ArrayRef< Value* > arguments(ConstantInt::get(Type::getInt32Ty(M.getContext()), 5, true));
Instruction *newInst = CallInst::Create(monitor, arguments, "");
BB->getInstList().insert(BI, newInst);
errs() << "Inserted the function!\n";
}
}
}
}
return true;
}
};
char ir_instrumentation::ID = 0;
static RegisterPass<ir_instrumentation> X("ir-instrumentation", "LLVM IR Instrumentation Pass");
}
LLVM is configured and built fine with this pass but when I use opt, I get this error :
opt: /llvm/lib/IR/Type.cpp:281:
llvm::FunctionType::FunctionType(llvm::Type*, llvm::ArrayRefllvm::Type*, bool):
Assertion `isValidReturnType(Result) && "invalid return type for function"' failed.
I think the problem is something like mismatching between the function type that I have declared and the external function (like the context).
LLVM version: LLVM version 7.0.0svn
Until now I have not solved the problem.
Thanks
I could finally solve this problem and successfully instrument LLVM bitcode. After a lot of trouble with function getOrInsertFunction, I found out it is not really necessary to use this method in my case. I just simply changed my pass to this:
#include "llvm/Pass.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/IRBuilder.h"
#include <vector>
using namespace llvm;
namespace{
struct ir_instrumentation : public ModulePass{
static char ID;
Function *monitor;
ir_instrumentation() : ModulePass(ID) {}
virtual bool runOnModule(Module &M)
{
errs() << "====----- Entered Module " << M.getName() << ".\n";
int counter = 0;
for(Module::iterator F = M.begin(), E = M.end(); F!= E; ++F)
{
errs() << "Function name: " << F->getName() << ".\n";
if(F->getName() == "print"){
monitor = cast<Function>(F);
continue;
}
for(Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
{
for(BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ++BI)
{
if(isa<BranchInst>(&(*BI)) )
{
errs() << "found a brach instruction!\n";
ArrayRef< Value* > arguments(ConstantInt::get(Type::getInt32Ty(M.getContext()), counter, true));
counter++;
Instruction *newInst = CallInst::Create(monitor, arguments, "");
BB->getInstList().insert(BI, newInst);
errs() << "Inserted the function!\n";
}
}
}
}
return true;
}
};
char ir_instrumentation::ID = 0;
static RegisterPass<ir_instrumentation> X("ir-instrumentation", "LLVM IR Instrumentation Pass");
}
As I know the name of the external function, I can simply find it through iterating over all functions of module and then use it in the desired way.
Obviously the problem was caused by calling module->getOrInsertFunction and the function type. My experience says that this method is more useful when you want to insert a new function and declare the prototype of your own function. Using it to get an existing function is challenging (e.g. setting the right prototype, ...)
Thanks

Multiple definitions and First defined error

I have written a small C program which is assembled of several files.
When I compile, I get an error for "multiple definitions".
My main.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"
#define FOREVER for(;;)
#define INPUT_LEN 30
int main()
{
char command[INPUT_LEN];
char *func;
int i;
int t;
FOREVER
{
if(scanf("%s", command) == 1)
{
func = strtok(command, " ");
for(i=0;cmd[i].func != NULL;i++)
{
if(strcmp(func, cmd[i].name) == 0)
{
(*((cmd[i].func)));
t = 1;
}
}
if(t == 1)
{
printf("No such command");
}
}
}
return 0;
}
My mat.c file:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"
#define LENGTH 100
#define SIXTEEN 16
#define SIZE 4
void read_mat()
{
int i = 0;
int j = 0;
int k = 0;
char tmp_name[LENGTH];
char num_buffer[LENGTH];
char *token;
double num_list[16];
double tmp_num = 0;
scanf("%[^,], %s", tmp_name, num_buffer);
token = strtok(num_buffer, ",");
while(token != NULL)
{
if(strcmp(token, "0") == 0)
{
num_list[i] = 0;
}
else
{
tmp_num = atof(token);
if(tmp_num == 0)
{
printf("Error in parameter: %d\n", (i-1));
break;
}
else
{
num_list[i] = tmp_num;
}
}
i++;
token = strtok(NULL, ",");
}
if(!strcmp(tmp_name, "MAT_A"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[0].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_B"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[1].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_C"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[2].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_D"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[3].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_E"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[4].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_F"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[5].mat[0][i][j] = num_list[k];
k++;
}
}
else
{
printf("No such matrix name.");
}
}
My general_structs.h file:
#define SIZE 4
#define SIZE_NAME 5
#define SIZE_FUNC 10
typedef double matrix[SIZE][SIZE];
matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;
void read_mat(void);
struct
{
char name[SIZE_NAME];
matrix *mat;
} mats[] = {
{"MAT_A", &MAT_A},
{"MAT_B", &MAT_B},
{"MAT_C", &MAT_C},
{"MAT_D", &MAT_D},
{"MAT_E", &MAT_E},
{"MAT_F", &MAT_F},
{"non", NULL}
};
struct
{
char name[SIZE_FUNC];
void (*func)(void);
} cmd[] = {
{"read_mat", read_mat},
{"not_valid", NULL}
};
My make file:
int_loop: my_math.o int_loop.o
gcc -g -ansi -Wall -pedantic my_math.o int_loop.o -o int_loop
int_loop.o : int_loop.c
gcc -c -ansi -Wall -pedantic int_loop.c -o int_loop.o
my_math.o : my_math.c
gcc -c -ansi -Wall -pedantic my_math.c -o my_math.o
I have been trying to solve this issue with various techniques but yet with no success.
The error I recieve is:
gcc -g -Wall -ansi -pedantic main.o mat.o -o mamantest
mat.o:(.data+0x0): multiple definition of `mats'
main.o:(.data+0x0): first defined here
mat.o:(.data+0x70): multiple definition of `cmd'
main.o:(.data+0x70): first defined here
collect2: ld returned 1 exit status
make: *** [mamantest] Error 1
Why does this error occurs? How do I solve this?
Thanks
In the header file you define the variables mats and cmd, meaning both translation units (both source files that includes the header file) will have those defined.
The variables should be defined only in a single place, in a single source file, like
struct mat mats[7] = { ... };
The above defines the array mats, and like I said should be done in only one place.
For the other source file you declare the variables, which can be done in the header file like e.g.
extern struct mat
{
...
} mats[7];
The above declare the variable mats as an array of seven mat structures. It also define the structure so it can be used to e.g. define the array.
After modifications suggested above, the complete header file should look something like
// First header include guards (see https://en.wikipedia.org/wiki/Include_guard)
#ifndef GENERIC_STRUCTS_H
#define GENERIC_STRUCTS_H
#define SIZE 4
#define SIZE_NAME 5
#define SIZE_FUNC 10
typedef double matrix[SIZE][SIZE];
// Declare the variables (note the added use of the extern keyword)
extern matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;
void read_mat(void);
// Define a structure named mat (note added structure tag name)
struct mat
{
char name[SIZE_NAME];
matrix *mat;
};
// Define a structure named command (note added structure tag name)
struct command
{
char name[SIZE_FUNC];
void (*func)(void);
};
// Now declare variables of the previous structures
extern struct mat mats[7];
extern struct command cmd[2];
// End of header include guard
#endif
That header file only declares variables, and can be included in all your source files.
Then in a single source file (for example your main.c file) you do the actual variable definitions:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"
matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;
struct mat mats[7] = {
{"MAT_A", &MAT_A},
{"MAT_B", &MAT_B},
{"MAT_C", &MAT_C},
{"MAT_D", &MAT_D},
{"MAT_E", &MAT_E},
{"MAT_F", &MAT_F},
{"non", NULL}
};
struct command cmd[2] = {
{"read_mat", read_mat},
{"not_valid", NULL}
};
#define FOREVER for(;;)
#define INPUT_LEN 30
int main()
{
...
}
The important thing you need to learn here is that there is a difference between declaring and defining something.
A declaration is basically telling the compiler that "this thing exists somewhere", and a definition is telling the compiler "this is the thing".
The problem is that unless a thing has already been declared, a definition is also a declaration, and many simply call these combined definitions/declarations just declaration, which muddles the whole concept up a bit.

Memory allocation error for structs with members that are function pointers and void pointers

I have written a straightforward C code that uses an engine to run two different algorithms depending on user input. It uses function pointers to the algorithm methods and objects. There is a nasty memory bug somewhere that I can not track down, so maybe I am allocating memory in the wrong way. What is going wrong?
Below is (the relevant parts of) a minimal working example of the code.
main.c
#include "engine.h"
int main()
{
char *id = "one";
Engine_t eng;
Engine_init(&eng);
Engine_select_algorithm(eng, id);
Engine_run(eng);
}
engine.h
typedef struct _Engine *Engine_t;
engine.c
#include "engine.h"
#include "algorithm_one.h"
#include "algorithm_two.h"
typedef struct _Engine
{
void *p_algorithm;
void (*init)(Engine_t);
void (*run)(Engine_t);
} Engine;
void Engine_init(Engine_t *eng)
{
*eng = malloc(sizeof(Engine));
(*eng)->p_algorithm = NULL;
}
void Engine_select_algorithm(Engine_t eng, char *id)
{
if ( strcmp(id, "one") == 0 )
{
eng->init = Algorithm_one_init;
eng->run = Algorithm_one_run;
}
else if ( strcmp(id, "two") == 0 )
{
eng->init = Algorithm_two_init;
eng->run = Algorithm_two_run;
}
else
{
printf("Unknown engine %s.\n", id); exit(0);
}
eng->init(eng);
}
void Engine_run(Engine_t eng)
{
eng->run(eng);
}
void Engine_set_algorithm(Engine_t eng, void *p)
{
eng->p_algorithm = p;
}
void Engine_get_algorithm(Engine_t eng, void *p)
{
p = eng->p_algorithm;
}
algorithm_one.h
typedef struct _A_one *A_one_t;
algorithm_one.c
#include "engine.h"
#include "algorithm_one.h"
typedef struct _A_one
{
float value;
} A_one;
void Algorithm_one_init(Engine_t eng)
{
A_one_t aone;
aone = malloc(sizeof(A_one));
aone->value = 13.0;
//int var = 10;
Engine_set_algorithm(eng, &aone);
}
void Algorithm_one_run(Engine_t eng)
{
A_one_t aone;
Engine_get_algorithm(eng, &aone);
printf("I am running algorithm one with value %f.\n", aone->value);
// The code for algorithm one goes here.
}
The code for algorithm_two.h and algorithm_two.c are identical to the algorithm one files.
There must be a memory bug involved, because the code runs as given, but if I uncomment the
//int var = 10;
line in algoritm_one.c the code crashes with a segmentation fault.
You pass the wrong thing to Engine_set_algorithm. You are passing the address of a local variable rather than the address of the algorithm. You need to write:
Engine_set_algorithm(eng, aone);
And also Engine_get_algorithm is wrong. You are passed a pointer by value and modify that pointer. So the caller cannot see that modification. You need it to be:
void Engine_get_algorithm(Engine_t eng, void **p)
{
*p = eng->p_algorithm;
}
I think your code would be easier if you defined a type to represent an algorithm. That type would be just a void*, but it would make the code much easier to read. What's more, I would make Engine_get_algorithm return the algorithm.
algorithm Engine_get_algorithm(Engine_t eng)
{
return eng->p_algorithm;
}
void Engine_set_algorithm(Engine_t eng, algorithm alg)
{
eng->p_algorithm = alg;
}

Resources