代码之家  ›  专栏  ›  技术社区  ›  icktoofay pcp

为什么libao在使用dlopen加载时是静默的?

  •  0
  • icktoofay pcp  · 技术社区  · 5 年前

    我正在用 libao 我调用libao的程序中有一个共享对象:

    // playao.c
    // compile with: gcc -shared -o libplayao.so playao.c -lao -lm
    #include <ao/ao.h>
    #include <stdio.h>
    #include <math.h>
    
    void playao(void) {
        int i;
        unsigned char samps[8000];
        ao_initialize();
        ao_sample_format sf;
        sf.bits = 8;
        sf.rate = 8000;
        sf.channels = 1;
        sf.byte_format = AO_FMT_NATIVE;
        sf.matrix = "M";
        ao_device *device = ao_open_live(ao_default_driver_id(), &sf, NULL);
        if(!device) {
            puts("ao_open_live error");
            ao_shutdown();
            return;
        }
        for(i = 0; i < 8000; ++i) {
            float time = (float)i / 8000;
            float freq = 440;
            float angle = time * freq * M_PI * 2;
            float value = sinf(angle);
            samps[i] = (unsigned char)(value * 127 + 127);
        }
        if(!ao_play(device, (char *)samps, 8000)) {
            puts("ao_play error");
        }
        ao_close(device);
        ao_shutdown();
    }
    

    如果我在程序中链接到这个共享对象,它可以正常工作:

    // directlink.c
    // compile with: gcc -o directlink directlink.c libplayao.so -Wl,-rpath,'$ORIGIN'
    void playao(void);
    
    int main(int argc, char **argv) {
        playao();
        return 0;
    }
    

    dlopen / dlsym

    // usedl.c
    // compile with: gcc -o usedl usedl.c -ldl
    #include <dlfcn.h>
    #include <stdio.h>
    
    int main(int argc, char **argv) {
        void *handle = dlopen("./libplayao.so", RTLD_LAZY);
        if(!handle) {
            puts("dlopen failed");
            return 1;
        }
        void *playao = dlsym(handle, "playao");
        if(!playao) {
            puts("dlsym failed");
            dlclose(handle);
            return 1;
        }
        ((void (*)(void))playao)();
        dlclose(handle);
        return 0;
    }
    

    但是,运行 usedl LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libao.so.4 工作。所以李宝有些东西想在 程序启动,不喜欢以后再加载。

    为什么会这样?有没有办法解决这个问题,让李宝发挥作用 即使在程序执行的后期加载正确?

    0 回复  |  直到 5 年前
        1
  •  1
  •   icktoofay pcp    5 年前

    我在弗里诺德的西弗海峡问过这个问题,西弗蒙特建议掉头 turning on verbose mode

    ERROR: Failed to load plugin /usr/lib/x86_64-linux-gnu/ao/plugins-4/libalsa.so => dlopen() failed
    

    dlopen 有些东西,但它失败了。它没有显示更多的细节,所以我在GDB下运行了这个程序,并在上设置了一个断点 打开 的断点 libalsa 和跑步 finish ,我试图用 print (const char *)dlerror() . 通过这个,我得到了一个更详细的错误:

    /usr/lib/x86_64-linux-gnu/ao/plugins-4/libalsa.so: undefined symbol: ao_is_big_endian
    

    打开

    下列值中的0或更多值也可以是“或” 旗帜 :

    全球RTLD :此共享对象定义的符号将可用于后续加载的共享对象的符号解析。

    本地RTLD :这是相反的 全球RTLD

    因为我的 仅使用呼叫 RTLD_LAZY RTLD_GLOBAL RTLD_LOCAL ,默认为 ,它不公开共享对象中的符号(如 ao_is_big_endian )到随后加载的共享对象(如 libalsa.so ).

    void *handle = dlopen("./libplayao.so", RTLD_LAZY);
    

    收件人:

    void *handle = dlopen("./libplayao.so", RTLD_LAZY | RTLD_GLOBAL);
    

    你瞧,它起作用了!