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.