为什么程序会打印共享对象全局变量的错误值?

时间:2017-07-18 04:16:19

标签: c shared-libraries

我使用以下命令从以下C代码构建了一个共享对象:

gcc -fPIC -shared libx.c -o libx.so

libx.c

extern int printf(const char *, ...);

int libvar = 250;

void libfunc(){

    printf("%d,",libvar);    
}

然后我使用以下命令将以下C代码链接到libx.so库:

gcc -no-pie -lx -L ./ -o main main.c
  

-no-pie:告诉编译器生成ELF可执行文件而不是共享对象(因为这是我的编译器默认执行的操作)。

的main.c

extern void libfunc();

int main(){
    libfunc();
}

现在,在启动程序时,理论上,动态加载程序会将共享库libx.so映射到正在运行的进程(./main)的地址空间,并将解析符号libfunc& ; libvar(更改[{1}}的{​​{1}}和.got段中的内容),最终将解析.plt符号,然后打印PIC的值这是printf
但程序打印出一些奇怪的值:

libvar

我已经进行了长时间的调试,以了解正在发生的事情,但我无法弄明白!

3 个答案:

答案 0 :(得分:2)

我改变了一点你的榜样。我的libfunc现在包含:

void libfunc(){
  printf("in libfunc libvar=%d\n",libvar);    
}

请注意,gcc的参数顺序与 lot 相关(并且您对gcc的参数的顺序错误)。详细了解Invoking GCC

我用

编译了你的库
gcc -fPIC -shared -Wall libx.c -o libx.so

然后我用

编译了你的main.c
gcc -Wall main.c -L. -lx -o main

然后执行失败

 ./main: error while loading shared libraries: libx.so: cannot open 
                      shared object file: No such file or directory

这是正常的,请参阅ld-linux(8)

要更正该错误,请明确设置LD_LIBRARY_PATH以包含具有libx.so的目录(例如.),例如输入运行程序的相同的终端,例如
export LD_LIBRARY_PATH=.

或通过编译程序

来适当地设置rpath
  gcc -Wall main.c -Wl,-rpath,. -L. -lx -o main

在这两种情况下我都会

  in libfunc libvar=250
运行./main

时预期

BTW,使用strace(1)可以帮助您找到您的错误(不是您显示的代码,而是系统配置错误)。您还可以使用-g编译库和可执行文件,然后使用gdb调试器。

答案 1 :(得分:-1)

由于这是一个dinâmica变量,libvar在堆中被不安全地分配,并且可以被操作系统中使用相同内存的其他程序更改。

如果需要更改,最佳做法是每次调用时使用常量或传递值。

答案 2 :(得分:-1)

有人指出图书馆在/lib,所以我去看看它&我发现我使用的是错误的库,它定义了相同的符号libfunc& libvar并且在函数libfunc中有一些其他printf导致程序打印错误的值。
因此,从技术上讲,两个库之间的区别在于格式printf中的字符串参数,我在调试时没有检出。