美文网首页
[习题29]C语言:库与链接 dlopen( )

[习题29]C语言:库与链接 dlopen( )

作者: AkuRinbu | 来源:发表于2018-12-28 20:44 被阅读21次

    使用教材

    《“笨办法” 学C语言(Learn C The Hard Way)》
    https://www.jianshu.com/p/b0631208a794

    • 完整源码 : learn-c-the-hard-way-lectures/ex29/

    https://github.com/zedshaw/learn-c-the-hard-way-lectures/tree/master/ex29

    命令行操作

    • 首先,编译 .c文件 ,生成 .so文件
    $ cc -fPIC -c libex29.c -o libex29.o
    $ ls
    dbg.h  ex29.c  libex29.c  libex29.o
    
    $ cc -shared -o libex29.so libex29.o
    $ ls
    dbg.h  ex29.c  libex29.c  libex29.o  libex29.so
    
    $ cc -Wall -g -DNDEBUG ex29.c -ldl -o ex29
    $ ls
    dbg.h  ex29  ex29.c  libex29.c  libex29.o  libex29.so
    
    • 然后,在命令行输入函数名 参数,就可以直接调用函数函数名来自于ex29.c文件里面自己写的函数
    
    $ ./ex29 ./libex29.so print_a_message "hello world"
    A STRING: hello world
    
    $ ./ex29 ./libex29.so uppercase "hello there"
    HELLO THERE
    
    $ ./ex29 ./libex29.so lowercase "HELLO WorlD"
    hello world
    
    • 故意诱发各种错误(测试函数 fail_on_purpose、输入一个不存在的函数名are_you_here?、输入一个不存在的库lib.so
    $ ./ex29 ./libex29.so fail_on_purpose "i fall"
    [ERROR] (ex29.c:27: errno: None) Function fail_on_purpose return 1 for data: i fall
    $ ./ex29 ./libex29.so fail_on_purpose
    [ERROR] (ex29.c:10: errno: None) USAGE: ex29 libex29.so function data
    
    $ ./ex29 ./libex29.so are_you_here?
    [ERROR] (ex29.c:10: errno: None) USAGE: ex29 libex29.so function data
    $ ./ex29 ./libex29.so are_you_here? are_you?
    [ERROR] (ex29.c:23: errno: None) Did not find are_you_here? function in the library ./libex29.so: ./libex29.so: undefined symbol: are_you_here?
    
    $ ./ex29 ./lib.so aaaaaa ccccccc
    [ERROR] (ex29.c:18: errno: None) Failed to open the library ./lib.so: ./lib.so: cannot open shared object file: No such file or directory
    

    完整源码

    libex29.c

    #include <stdio.h>
    #include <ctype.h>
    #include "dbg.h"
    
    
    int print_a_message(const char *msg)
    {
        printf("A STRING: %s\n", msg);
    
        return 0;
    }
    
    
    int uppercase(const char *msg)
    {
        int i = 0;
    
        // BUG: \0 termination problems
        for(i = 0; msg[i] != '\0'; i++) {
            printf("%c", toupper(msg[i]));
        }
    
        printf("\n");
    
        return 0;
    }
    
    int lowercase(const char *msg)
    {
        int i = 0;
    
        // BUG: \0 termination problems
        for(i = 0; msg[i] != '\0'; i++) {
            printf("%c", tolower(msg[i]));
        }
    
        printf("\n");
    
        return 0;
    }
    
    int fail_on_purpose(const char *msg)
    {
        return 1;
    } 
    

    ex29.c

    #include <stdio.h>
    #include "dbg.h"
    #include <dlfcn.h>
    
    typedef int (*lib_function) (const char *data);
    
    int main(int argc, char *argv[])
    {
        int rc = 0;
        check(argc == 4, "USAGE: ex29 libex29.so function data");
    
        char *lib_file = argv[1];
        char *func_to_run = argv[2];
        char *data = argv[3];
    
        void *lib = dlopen(lib_file, RTLD_NOW);
        check(lib != NULL, "Failed to open the library %s: %s", lib_file,
                dlerror());
    
        lib_function func = dlsym(lib, func_to_run);
        check(func != NULL,
                "Did not find %s function in the library %s: %s", func_to_run,
                lib_file, dlerror());
    
        rc = func(data);
        check(rc == 0, "Function %s return %d for data: %s", func_to_run,
                rc, data);
    
        rc = dlclose(lib);
        check(rc == 0, "Failed to close %s", lib_file);
    
        return 0;
    
    error:
        return 1;
    }
    

    概念解释

    • 静态库,就是一系列 .o文件;
    • 动态库,典型的后缀名有.so .dll,在运行程序时,操作系统会动态地加载这些文件,并且将它们随时链接到你的程序上;

    代码说明

    • ( ex29.c ) typedef int (*lib_function) (const char *data); ,函数指针;
    • ( ex29.c ) void *lib = dlopen(lib_file, RTLD_NOW); ,调用dlopen函数来加载lib_file所表示的库
    • ( ex29.c ) lib_function func = dlsym(lib, func_to_run); ,调用 dlsym函数,通过使用函数func_to_run中的字符串名称,从lib中获取了一个函数,从而实现,通过命令行argv得到字符串,之后通过这个字符串动态地获取一个指向函数的指针
    [举 例 说 明]
    /****    ex29.c    ****/
      char *lib_file = argv[1];
      char *func_to_run = argv[2];
      char *data = argv[3];
    /****    ex29.c    ****/
    
    $  ./ex29     ./libex29.so   print_a_message   "hello world"
    argv[1] = ./libex29.so  
    argv[2] = print_a_message  
    argv[3] = hello world 
    

    参考资料

    • 解决:/usr/bin/ld: libex29.o: relocation R_X86_64_32 against `.rodata'
      can not be used when making a shared object; recompile with -fPIC
      libex29.o: error adding symbols: Bad value
      collect2: error: ld returned 1 exit status
      https://www.jianshu.com/p/91edc58041fb

    相关文章

      网友评论

          本文标题:[习题29]C语言:库与链接 dlopen( )

          本文链接:https://www.haomeiwen.com/subject/dinelqtx.html