如何使用libc dlopen和dlsym

问题描述 投票:0回答:1

vala-lang 如何访问动态链接函数?

作为参考示例,假设我们想要重现此 cpp openssl md5 程序](https://stackoverflow.com/a/73843621/1695680),除非使用动态加载的 libssl。

glibc libc vala dlopen dlsym
1个回答
0
投票

在下面的例子中,我们使用

dlopen
dlsym
打开

// vala-dlopen-openssl-md5sum.vala
// begin POSIX dlopen
[CCode (cname="dlopen")]
extern unowned void *dlopen(string filename, int flag);
[CCode (cname="dlerror")]
extern unowned string dlerror();
[CCode (cname="dlsym")]
extern unowned void *dlsym(void *handle, string symbol);

const int RTLD_LAZY = 1;
// end POSIX dlopen

// being openssl
delegate unowned void *EVP_MD_CTX_new();
delegate unowned void *EVP_md5();
delegate unowned int EVP_DigestInit_ex2(void *ctx, void *md, void* params);
delegate unowned int EVP_DigestUpdate(void *ctx, void *d, ulong cnt);
delegate unowned int EVP_DigestFinal_ex(void *ctx, uchar *md, uint *s);
// end openssl

int main(string[] args) {
    // begin dlopen
    var openssl = dlopen("libssl.so", RTLD_LAZY);
    if (openssl == null) {
        stderr.printf("dlopen failed: %s\n", dlerror());
        return 2;
    }

    var fn_EVP_MD_CTX_new = (EVP_MD_CTX_new) dlsym(openssl, "EVP_MD_CTX_new");
    if (fn_EVP_MD_CTX_new == null) {
        stderr.printf("dlsym failed: %s\n", dlerror());
        return 2;
    }
    var fn_EVP_md5 = (EVP_md5) dlsym(openssl, "EVP_md5");
    if (fn_EVP_md5 == null) {
        stderr.printf("dlsym failed: %s\n", dlerror());
        return 2;
    }
    var fn_EVP_DigestInit_ex2 = (EVP_DigestInit_ex2) dlsym(openssl, "EVP_DigestInit_ex2");
    if (fn_EVP_DigestInit_ex2 == null) {
        stderr.printf("dlsym failed: %s\n", dlerror());
        return 2;
    }
    var fn_EVP_DigestUpdate = (EVP_DigestUpdate) dlsym(openssl, "EVP_DigestUpdate");
    if (fn_EVP_DigestUpdate == null) {
        stderr.printf("dlsym failed: %s\n", dlerror());
        return 2;
    }
    var fn_EVP_DigestFinal_ex = (EVP_DigestFinal_ex) dlsym(openssl, "EVP_DigestFinal_ex");
    if (fn_EVP_DigestFinal_ex == null) {
        stderr.printf("dlsym failed: %s\n", dlerror());
        return 2;
    }
    // end dlopen

    // begin ms5sum example
    void *ctx = fn_EVP_MD_CTX_new();
    void *md = fn_EVP_md5();
    uchar md_value[33];
    md_value = { 0 };
    uint md_len = 0;

    fn_EVP_DigestInit_ex2(ctx, md, null);

    // example-md5sum a string (argv 1)
    // vala ./vala-dlopen-openssl-md5sum.vala --run-args "hello world"
    string subject = args[1];
    if (subject != null) {
        char []content = subject.to_utf8();
        fn_EVP_DigestUpdate(ctx, content, content.length);

    // example-md5sum a stream (stdin)
    // echo "hello world" | vala ./vala-dlopen-openssl-md5sum.vala
    } else {
        while (!stdin.eof()) {
            uint8[] buf = new uint8[40960];
            size_t buf_size = stdin.read (buf, 40960);
            fn_EVP_DigestUpdate(ctx, buf, buf_size);
        }
    }

    fn_EVP_DigestFinal_ex(ctx, md_value, &md_len);

    // digest to hex
    string output = "";
    for (uint i = 0; i < md_len; ++i) {
        output = "%s%02x".printf(output, md_value[i]);
    }
    // end ms5sum example

    stdout.printf("%s\n", output);
    return 0;
}

我在这个论坛帖子中发现了一个与 dlopen/dlsym 交互的例子:https://www.rocksaying.tw/archives/14551049.html

包含的示例依赖于一个神秘的 ./md5sum.dll,但涉及与 dlopen/dlsym 交互的 vala 代码似乎确实有效,从那里我能够将此示例改编为工作的 openssl md5sum 客户端,并将 md5sum 保留为简单的“你好世界”示例。

值得注意的是,在这个例子中,我们凭空拉出

dlopen
dlsym
,大概它们链接是因为 POSIX 标准或包含的 libc 指定它们将存在。

如果我们没有特别需要动态链接,我们当然可以使用 vala-api/.vapi 文件包装目标 c 库,并跳过

delegate
声明并将函数指针类型转换为委托类型。

© www.soinside.com 2019 - 2024. All rights reserved.