Creating shared library with extern headers in GNU GCC and clang - c

For this question of mine, my goal was to create a software, main, that takes a plugin, libfunc.so, and libfunc.so would modify the value of burger.
main.c :
#include <stdio.h>
#include <stdlib.h> // for exit()
#include <dlfcn.h>
#include "main.h"
int burger = 3;
int main(){
void (*ptr_func)();
void *handle;
handle = dlopen("./libfunc.so", RTLD_NOW);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
*(void**)(&ptr_func) = dlsym(handle, "some_func");
if (!ptr_func){
fprintf(stderr, "%s\n", dlerror());
dlclose(handle);
exit(1);
}
printf("before ptr_func %d\n", burger);
ptr_func();
printf("after %d\n", burger);
return 0;
}
The declaration of burger,
main.h:
#ifndef MAIN_H__
#define MAIN_H__
extern int burger;
#endif
and the plugin [func.c] as this:
#include <stdio.h>
#include "main.h"
void some_func(){
burger += 10;
}
compiled all of these with clang and I got no error:
$ clang -rdynamic main.c -o main
$ clang -shared -fPIC func.c -o libfunc.so
But the problem arises with gcc:
$ gcc -rdynamic main.c -o main
$ gcc -shared -fPIC func.c -o libfunc.so
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/../../../../x86_64-pc-cygwin/bin/ld: /tmp/cc
vgKpEc.o:func.c:(.rdata$.refptr.burger[.refptr.burger]+0x0): undefined reference
to `burger'
Yes, I've tried removing the extern and it compiled successfully but the output was:
$ ./main.exe
before ptr_func 3
after 3
clang on the other hand compiled this successfully and working as I expected:
$ ./main
before ptr_func 3
after 13
The same as without extern compiled in clang
Do this two rivals really don't like to be consistent?
Here's the gist of it https://gist.github.com/harieamjari/8c816f39fe04d38d83022301872272ea
Additional notes:
The clang I have was from Termux. (an android application that simulates linux).
And the gcc I have was from cygwin.
gcc version 9.3.0
clang version 9.0.0
NOTICE
From my Termux, I installed gnu-8 and compiled the MWE above, but I do not experience an error.
Maybe I should use Windows.h for this matter instead of using dlfcn.h in cygwin.

Related

__attribute__((weakref)) not work for external function

Recently I 'm studying the linking process and when it comes to weak symbol, my textbook give a code below to demonstrate how to use __attribute__((weakref)) to declare a weak reference to external function:
//pthread.c
#include <stdio.h>
#include <pthread.h>
int pthread_create(
pthread_t*,
const pthread_attr_t*,
void* (*)(void*),
void*
)__attribute__((weak));
int main()
{
if(pthread_create){
printf("This is multi-thread version\n");
}else{
printf("This is single-thread version!\n");
}
}
Then the author use different ways of linking ,which gives the result:
$ gcc pthread.c -o pt
$ ./pt
This is single-thread version!
$ gcc pthread.c -lpthread -o pt
$ ./pt
This is multi-thread version!
I reproduced the same procedure on my machine, but both results give This is single-thread version!
I tried to find out what 's going on here, but I quickly stuck into two problem :
I think it might be that the author mistakenly write __attribute((weak))__instead of __attribute__((weakref))__ here. Because if one module declare a weak symbol, the linker would not find the definition of the symbol in the library during the static linking process. Considering that GCC use dynamic linking by default, I use static linking to verify that :
$ gcc -c pthread.c
$ nm pthread.o
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T main
w pthread_create
U puts
$ gcc -static pthread.c -lpthread -o pt
$ nm pt | grep 'pthread_create'
$
the symbol 'pthread_create' do not appear in the symbol table.
Now I use __attribute((weakref))__ to reproduce the procedures.
//pthread.c modified
#include <stdio.h>
#include <pthread.h>
static int pthread_create_dup(
pthread_t*,
const pthread_attr_t*,
void* (*)(void*),
void*
)__attribute__((weakref,alias("pthread_create")));
int main()
{
if(pthread_create_dup){
printf("This is multi-thread version!\n");
}else{
printf("This is single-thread version!\n");
}
}
still, after compiling and linking, the result is This is single-thread version!
$ gcc -static pthread.c -lpthread -o pt
$ nm pt | grep 'pthread_create'
$
I make another sample to simulate above:
test.c:
extern int foo(int a,int b);
static int foo_dup(int a,int b) __attribute__((weakref,alias("foo")));
int main(){
if(foo_dup){
printf("foo is linked\n");
}else{
printf("foo isn't linked\n");
}
}
ref_foo.c
int foo(int a ,int b){
return a+b;
}
Then compile those two:
$ gcc -c ref_foo.c test.c
$ ar rcs libfoo.a ref_foo.o
$ gcc -static test.o libfoo.a -o test_withlib
$ ./test_withlib
foo isn't linked
$ gcc -static test.o ref_foo.o -o test_withoutlib
$ ./test_withoutlib
foo is linked
So why would this happen? It's apparently I cannot extract pthread_create.o from libpthread.o and simply gcc pthread.c pthread_create.o -o pt.How to correctly implement pthread.c so it will print This is multi-thread version! when linking to the libpthread ?

Linux, C - Is it possible to link against 2 dynamic librraries with equal functions names

I am forced to link two version of the same third party dynamic library (Linux .so, C language) into the same executable to support old and new functionality in the same process. Having two executables or remote services are undesirable.
I made the assumption that this must be a doable task. I tried to experiment with the naive approach of creating 2 proxy dynamic libraries each linked against one of the real libraries and have function renamed.
Unfortunately, this attempt failed – both new functions call the same target function.
I still want to believe that the problem is in the lack of my knowledge as there are plenty of compiler and linker ( gcc and ld) options.
I will appreciate any help. I also look forward to using dlopen/dlsym, but first want to check if the original approach can work.
Here is the sample code
/* ./old/b.c */
#include <stdio.h>
int b (int i)
{
printf("module OLD %d\n",i);
return 0;
}
/* ./old/Makefile */
libold.so: b.c
gcc -c -g b.c
gcc -shared b.o -o $#
/* ./new/b.c */
#include <stdio.h>
int b (int i)
{
printf("module new %d\n",i);
return 0;
}
/* ./new/Makefile */
libnew.so: b.c
gcc -c -g b.c
gcc -shared b.o -o $#
/* ./a1.c */
#include <stdio.h>
int b(int);
void call_new(void)
{
printf("will call new 1\n");
b(1);
printf("called new 1\n");
}
/* ./a2.c */
#include <stdio.h>
int b(int);
void call_old(void)
{
printf("will call old 2\n");
b(2);
printf("called old 2\n");
}
/* ./main.c */
#include <stdio.h>
int call_new(void);
int call_old(void);
int main()
{
call_new();
call_old();
return 0;
}
/* ./Makefile */
.PHONY: DEPSNEW DEPSOLD clean
main: liba1.so liba2.so main.c
gcc -c main.c
gcc -o main main.o -rdynamic -Wl,-rpath=new -Wl,-rpath=old -L . -la1 -la2
DEPSNEW:
make -C new
DEPSOLD:
make -C old
liba1.so: DEPSNEW a1.c
gcc -c -fpic a1.c
gcc -shared a1.o -L new -lnew -o liba1.so
liba2.so: DEPSOLD a2.c
gcc -c -fpic a2.c
gcc -shared a2.o -L old -lold -o liba2.so
clean:
find -name "*.so" -o -name "*.o" -o -name main | xargs -r rm
/* ./run.sh */
#/bin/sh
LD_LIBRARY_PATH=new:old:. main
The result is not that I want - function from "new" library is called twice
will call new 1
module new 1
called new 1
will call old 2
module new 2
called old 2
In this case, you can not control the automatic loading of the dynamic library in order to assure which library will be loaded for the depending libraries. What you can do, is to use one of the libraries (the new one) for the dynamic linker and to link the second library manually as follows:
Add function to dynamically load and link the function from the library.
a2.c
#include <stdio.h>
#include <dlfcn.h>
static int (*old_b)(int);
void init_old(void) {
void* lib=dlopen("./old/libold.so", RTLD_LOCAL | RTLD_LAZY);
old_b=dlsym(lib,"b");
}
void call_old(void)
{
printf("will call old 2\n");
old_b(2);
printf("called old 2\n");
}
call the initialization function
main.c
#include <stdio.h>
void init_old(void);
int call_new(void);
int call_old(void);
int main()
{
init_old();
call_new();
call_old();
return 0;
}
Modify the linker options to add the dynamic loading library -ldl
liba2.so: DEPSOLD a2.c
gcc -c -fpic a2.c
gcc -shared a2.o -L old -lold -ldl -o liba2.so
After this modification
~$ ./run.sh
will call new 1
module new 1
called new 1
will call old 2
module OLD 2
called old 2

Linking to an executable on OSX

On Windows it is possible to dynamically link to an executable with exported symbols. For example following code:
// main.c
void __declspec(dllexport) interface_function() {}
int main() {}
// ext.c
void interface_function();
void extension_function() {
interface_function();
}
With
cl.exe main.c
cl.exe ext.c /LD /link main.lib
would produce an executable main.exe, a static library main.lib for implicit linking, and a dynamic library ext.dll.
Similar behavior can be achieved in OSX with shared libraries:
// main.c
void interface_function() {}
int main() {}
// ext.c
void interface_function();
void extension_function() {
interface_function();
}
With
gcc main.c -o main
gcc ext.c -bundle -bundle_loader main -o ext.bundle
it is virtually equivalent to the Windows setup.
But for dynamiclib:
> gcc ext.c -dynamiclib -o ext.dylib
and shared:
> gcc ext.c -shared -o ext.so
I cannot get them to work because of undefined symbols on one hand and unable to load an executable with -l flag on the other.
I can let them resolve undefined symbols in runtime with -undefined dynamic_lookup. But this is not a sustainable way because all the link errors are now happening in run-time instead.
Is there a way to provide the list of symbols to dynamically load from an executable when linking as -shared and -dynamiclib?
Yes this is possible, but then you'll want to create a bundle rather than a shared library (see this answer for more detail).
If you have a main application like so:
#include <stdio.h>
#include <dlfcn.h>
int func(void)
{
return 42;
}
int main(void)
{
void *dl = dlopen("plugin.so", RTLD_LOCAL);
if(!dl) return -1;
int (*derp)(void) = dlsym(dl, "derp");
if(!derp) return -1;
printf("derp(): %i\n", derp());
return 0;
}
clang -o main main.c -Wall -Wl,-export_dynamic
Then you can compile bundles against it like so:
int func(void);
int derp(void)
{
return -func();
}
clang -o plugin.so plugin.c -Wall -bundle -bundle_loader ./main

How to deal with function definitions in header files?

Is there any way I can compile a poorly designed header file to a object file without changing file extension or content using gcc, or do I have to copy the file/edit it? (This because I am using a public SDK, i.e. I do not have permission to edit the header file, and because using cp in my Makefile seems like a major hack, and time consuming too)
Example
main.c
#include <print.h>
#include <app.h>
int main(void) {
print("Starting app . . . ");
run();
}
app.h
#ifndef APP_H
#define APP_H
int runApp(void);
#endif
app.c
#include <print.h>
#include <app.h>
int runApp(void) {
print("This is my app!");
return 0
}
print.h
#ifndef PRINT_H
#define PRINT_H
int print(char* str) {
printf(str);
return 0;
}
#endif
Which is compiled using:
$ gcc -o main.o main.c
$ gcc -o app.o app.c
$ gcc -o main main.o app.o
The SDK example programs use a single object file (gcc -o main.o main.c & gcc -o main main.o), but that would just get really messy in my case.
Create
_print.h
int print(char* str);
print.cpp
#include <print.h>
and change your includes to "_print.h"

Calling functions from a shared library

I'm trying to call a "core" function from a shared library's function but I get:
./a.out: symbol lookup error: ./libtest.so: undefined symbol: testf
The code I'm using is very basic because I'm just getting into writing shared libraries and it's just for testing purposes:
main.h
extern void testf();
main.c
#include <stdio.h>
#include <dlfcn.h>
extern void testf()
{
printf("bla bla\n");
}
int main () {
void *handle = NULL;
void (*testlib)(void) = NULL;
handle = dlopen("./libtest.so" ,RTLD_LAZY);
testlib = dlsym(handle, "testfunc");
if ( testlib == NULL )
{
printf("Error: %s \n", dlerror());
}
else
{
testlib();
}
}
libtest.c
#include <stdio.h>
#include "main.h"
void testfunc() {
printf("Test plugin\n");
testf();
}
And the commands I compile it with:
gcc -fPIC -g -c -Wall libtest.c
gcc -shared -Wl,-soname,libtest.so.1 -o libtest.so libtest.o -lc
gcc main.c -ldl
Is it possible to achieve this? Tried to find the answer, but don't really know how to form the question right so I can search better for it.
Thanks!
here you are trying to call a function of a executable from the library. I think you actually required reverse of this.
Sorry, managed to find the answer:
I was compiling the main program with wrong parameters, should use:
gcc main.c -ldl -rdynamic

Resources