3

Trying to test a simple case where a global variable defined in a shared library is set by a program and used by the shared library, I saw a strange problem. Here are the program codes.

bar.cpp

#include <stdint.h>
#include <stdio.h>

extern "C" {
uint64_t var_from_lib;
}

class BC;

class BC {
public:
    void bar(void);
    BC();
    ~BC();
};

BC::BC()
{
}

BC::~BC()
{
}

void BC::bar(void)
{
    printf("class function : var_from_lib = %lx\n", var_from_lib);
}

extern "C" {
void bar(void)
{
printf("global function : var_from_lib = %lx\n", var_from_lib);
BC tmp;
tmp.bar();
}
}

main1.c

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

extern uint64_t var_from_lib;

int main1(void)
{
    void * dlh = dlopen("./libbar.so", RTLD_NOW);
    if (!dlh) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE); 
    }
    void (*bar)(void) = dlsym(dlh,"bar");
    if (!bar) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE); 
    }
    var_from_lib = 0x12341111;
    bar();
    return 0;
}

main2.c

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

extern uint64_t var_from_lib;

int main2(void)
{
    void * dlh = dlopen("./libbar.so", RTLD_NOW);
    if (!dlh) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE); 
    }
    void (*bar)(void) = dlsym(dlh,"bar");
    if (!bar) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE); 
    }
    var_from_lib = 0x12342222;
    bar();
    return 0;
}

main.c

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

extern uint64_t var_from_lib; // = 0x12345678;
uint64_t __attribute__((weak)) var_from_lib; // = 0x12345678;
extern int main1();
extern int main2();

int main(int argc, char *argv[])
{
    if (atoi(argv[1]) == 1) {
        main1();
    }
    else if (atoi(argv[1]) == 2) {
        main2();
    }
    else {
        printf("usage : main [1|2]\n");
    }
    return 0;
}

Makefile

.PHONY: all clean test

LDEXTRAFLAGS ?=

all: prog

%.o: %.c
    gcc -c -Wall -fpic -g -o $@ -ldl $<

%.o: %.cpp
    g++ -c -Wall -fpic -g -o $@ $<

libbar.so: bar.o
    g++ -shared -o $@ $<

prog: main.o main1.o main2.o | libbar.so
    gcc $(LDEXTRAFLAGS) -o $@ $^  -ldl

clean:
    rm -f *.o *.so prog

And here is the build and execution result which is different from what I thought.

ckim@ckim-ubuntu:~/testdir$ make
gcc -c -Wall -fpic -g -o main.o -ldl main.c
gcc -c -Wall -fpic -g -o main1.o -ldl main1.c
gcc -c -Wall -fpic -g -o main2.o -ldl main2.c
g++ -c -Wall -fpic -g -o bar.o bar.cpp
g++ -shared -o libbar.so bar.o
gcc  -o prog main.o main1.o main2.o  -ldl

ckim@ckim-ubuntu:~/testdir$ prog 1
global function : var_from_lib = 0
class function : var_from_lib = 0

The main1() changes the var_from_lib to 0x12341111 and main2() changes the variable to 0x12342222. I expected the changed values will be observed from inside the shared library but it is not!

I used debugger and checked the address of var_from_lib and it was the same seen from main.c and seen from bar.cpp. What could be wrong here?

Barmar
  • 741,623
  • 53
  • 500
  • 612
Chan Kim
  • 5,177
  • 12
  • 57
  • 112

1 Answers1

2

Looks like you are not linking to the shared library. You are dlopen-ing it.

Your expected behavior works like this only when you are directly linking with the shared library.

With dlopen you are expected to do all the work yourself: using dlsym to obtain the address of a symbol that's defined by the shared library.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Ah, thank you very much. I wasn't fully aware that I have to use dlsym also for variables. (for others : adding `uint64 *var_from_lib; var_from_lib = dlsym(dlh,"var_from_lib"); *var_from_lib = 0x12341111(or 0x12342222);` now makes it work as I expected.) – Chan Kim Jul 06 '21 at 00:37