Skip to content

Missing BN_* prefixed symbols and library in output binary when dynamic linking #25982

@bullekeup

Description

@bullekeup

Zig Version

0.16.0-dev.1364+f0a3df98d

Steps to Reproduce and Observed Behavior

When dynamically linking system provided OpenSSL with 0.16.0-dev.1364+f0a3df98d, every symbol that starts with BN_* is stripped out of the output binary, nothing shown with readelf -s.

If only BN_* functions are used libcrypto is not linked at all (not shown in ldd output).

This only affects BN_* prefixed OpenSSL symbols, if used, other symbols (X509, ...) are present and properly linked. Something related to the BN_* name that triggers a specific behaviour at build / link time maybe ? I looked through the code but failed to find anything relevant.

I tried to link with lld, it fails to link and crash.

Building with LLVM also fails with the following linkage issue:

error: Global is external, but doesn't have external or weak linkage!
       ptr @openssl_bn.main
       LLVM ERROR: Broken module found, compilation aborted!

Sample code :

// openssl_bn.zig
const std = @import("std");

pub const log_level = std.log.Level.debug;

pub const c = @cImport({
    @cInclude("openssl/bn.h");
});

pub fn main() void {
    std.log.info("*Start test*", .{});

    const value: ?*c.BIGNUM = c.BN_new() orelse {
        std.log.err("Failed to create BN", .{});
        return;
    };
    defer c.BN_free(value);
    _ = c.BN_set_word(value, 1);
    std.log.debug("value: {d}", .{c.BN_get_word(value)});
}

Interestingly, building a small test.c file with zig cc works properly

// zig cc -lc -lcrypto test.c -o test
#include <openssl/bn.h>
#include <stdio.h>

int main() {
  BIGNUM *bn = BN_new();
  BN_set_word(bn, 1);
  printf("%lu\n", BN_get_word(bn));
  BN_free(bn);
  return 0;
}

Reproduced on Ubuntu 25.10 x86_64 and Fedora 43 aarch64

Note: building with zig 0.15.2 works as expected, BN_* symbols are present in the binary.

I made a small repo to reproduce easily at https://github.com/bullekeup/zig-issue-openssl.git

Expected Behavior

Symbols present in the binary as reported by readelf :

readelf -s ./zig-out/bin/bn | grep BN_
  3539: 000000000101a220    16 FUNC    LOCAL  DEFAULT   17 BN_set_word$plt
  3540: 000000000101a230    16 FUNC    LOCAL  DEFAULT   17 BN_new$plt
  3541: 000000000101a240    16 FUNC    LOCAL  DEFAULT   17 BN_get_word$plt
  3542: 000000000101a250    16 FUNC    LOCAL  DEFAULT   17 BN_free$plt
  3575: 0000000000000000   103 FUNC    GLOBAL DEFAULT  UND BN_set_word
  3576: 0000000000000000    50 FUNC    GLOBAL DEFAULT  UND BN_new
  3577: 0000000000000000    41 FUNC    GLOBAL DEFAULT  UND BN_get_word
  3578: 0000000000000000   129 FUNC    GLOBAL DEFAULT  UND BN_free

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugObserved behavior contradicts documented or intended behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions