tree: 6d5a4d35db8bf22f0fab186a3bf8752e94a4ec85 [path history] [tgz]
  1. bindgen.h
  2. bindgen.sh
  3. boringssl.rs
  4. README.md
  5. test_symbol_conflict.sh
  6. test_symbol_version_name.sh
boringssl/README.md

boringssl

This directory contains source code and Rust bindings for Google's BoringSSL library.

Versions

BoringSSL is vendored here, so each version of Mundane will depend on a particular version of BoringSSL. Each new release will usually vendor the latest version of BoringSSL in order to pick up bug fixes and improvements.

Bindings

Rust bindings live in boringssl.rs. This file is included from the main Mundane source code using a #[path] attribute.

These bindings are auto-generated using the bindgen.sh script, although some manual intervention is required. In particular, after running bindgen.sh, each public function must be annotated with a #[link_name] attribute (the reason for these attributes is explained in the following section). For example, given the following bindgen output:

extern "C" {
    pub fn CBS_init(cbs: *mut CBS, data: *const u8, len: usize);
}

We add a #[link_name] attribute as follows, where X.Y.Z is the current crate version.

extern "C" {
    #[link_name = "__RUST_MUNDANE_X_Y_Z_CBS_init"]
    pub fn CBS_init(cbs: *mut CBS, data: *const u8, len: usize);
}

Symbol Prefixing

Normally, the C build system does not allow multiple copies of the same codebase to be linked together since the namespace for C symbols is global at link time. In order to avoid this problem, we compile BoringSSL with a custom symbol prefix specific to the crate version. This document describes the details of how this works.

Prefixing

Each BoringSSL symbol is given a prefix of __RUST_MUNDANE_X_Y_Z_, where the current crate version number is X.Y.Z. This way, if two different versions of the crate are present during a build, no C symbol will be defined under the same name in both builds of BoringSSL.

Two-phase build

BoringSSL's build system has built-in support for symbol prefixing. However, it requires that the caller provide a list of symbols which need to be prefixed. Since the set of symbols present is highly platform-dependent, a static list would be very brittle and error-prone. Instead, we discover the symbols dynamically at build time by doing a two-phase build.

In the first phase, we build BoringSSL as normal, with no symbol prefixing. Then, using a Go program provided by BoringSSL, we scrape the list of symbols from the build artifacts. Using this list, we run the build again - the second phase - this time using BoringSSL's symbol prefixing feature. We use the artifacts from the second build when performing the final Rust build.

Library names

We instruct Rust to use the appropriate build artifacts using the linker path. The linker path is used in a manner similar to the binary $PATH in Unix systems. When a library is requested, the linker searches for a build artifact of the appropriate name, stopping its search once it has found the appropriate library. For example, given the argument -l foo, the linker would search for a file called libfoo.a.

In order to ensure that the linker is able to find all copies of the BoringSSL build artifacts, we give them unique names. If we didn't, only the first artifact found in the filesystem would be used. Currently, we only link against the crypto library, which, in the normal build system, is stored in libcrypto.a. In order to make sure that all versions of this library are found by the linker - one per version of the crate - we rename them just as we rename symbols. For crate version x.y.z, we rename libcrypto.a to libcrypto_x_y_z.a, and instruct the linker to look for the crypto_x_y_z library.

Testing

In order to test that symbol prefixing is working properly, use the test_symbol_conflicts.sh script in this directory.