Skip to content

Commit

Permalink
Support linking Rust code in Oak Runtime (#319)
Browse files Browse the repository at this point in the history
Currently only compiled with `no_std`, therefore only stack allocation
is allowed. In the future we should plug in a real allocator and link to
`liballoc` to make it more useful.

Note to reviewers: I have added a simple check in `oak_runtime.cc` to
verify that the bindings are working, but let me know if you prefer to
leave that out.

Ref #313
  • Loading branch information
tiziano88 authored Nov 18, 2019
1 parent 980aaf5 commit 8294164
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 4 deletions.
39 changes: 35 additions & 4 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,43 @@ git_repository(
remote = "https://github.com/daviddrysdale/wabt",
)

load(
"@com_google_asylo//asylo/bazel:asylo_deps.bzl",
"asylo_deps",
"asylo_go_deps",
http_archive(
name = "bazel_skylib",
sha256 = "9a737999532daca978a158f94e77e9af6a6a169709c0cee274f0a4c3359519bd",
strip_prefix = "bazel-skylib-1.0.0",
url = "https://github.com/bazelbuild/bazel-skylib/archive/1.0.0.tar.gz",
)

http_archive(
name = "io_bazel_rules_rust",
repo_mapping = {"@bazel_version": "@bazel_version_rust"},
sha256 = "69b67e19532b12da3edccda404772e85a788d16ae739343f5338dd340a0fba2e",
strip_prefix = "rules_rust-ec436b5ff2ab1ddeba6f27a7a1a5d263812981a6",
urls = [
# Master branch as of 2019-11-15.
"https://github.com/bazelbuild/rules_rust/archive/ec436b5ff2ab1ddeba6f27a7a1a5d263812981a6.tar.gz",
],
)

load("@io_bazel_rules_rust//rust:repositories.bzl", "rust_repository_set")

rust_repository_set(
name = "rust_linux_x86_64",
exec_triple = "x86_64-unknown-linux-gnu",
extra_target_triples = [],
iso_date = "2019-11-06",
version = "nightly",
)

load("@io_bazel_rules_rust//:workspace.bzl", "bazel_version")

# We need to alias this with a different name so it does not conflict with an existing rule imported
# from Asylo.
# See https://github.com/google/asylo/issues/44.
bazel_version(name = "bazel_version_rust")

load("@com_google_asylo//asylo/bazel:asylo_deps.bzl", "asylo_deps", "asylo_go_deps")

asylo_deps()

asylo_go_deps()
Expand Down
1 change: 1 addition & 0 deletions oak/server/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ cc_library(
"//oak/proto:oak_api_cc_proto",
"//oak/server:logging_node",
"//oak/server/storage:storage_node",
"//rust/oak_runtime:wrapper",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/synchronization",
"@com_google_asylo//asylo/util:logging",
Expand Down
9 changes: 9 additions & 0 deletions oak/server/oak_runtime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "absl/memory/memory.h"
#include "asylo/util/logging.h"
#include "oak/common/app_config.h"
#include "rust/oak_runtime/oak_runtime.h"

namespace oak {

Expand Down Expand Up @@ -107,6 +108,14 @@ grpc::Status OakRuntime::Initialize(const ApplicationConfiguration& config) {
}

grpc::Status OakRuntime::Start() {
// We call into the Rust runtime to verify that bindings between C++ and Rust are working
// correctly.
{
LOG(INFO) << "Calling Rust runtime";
int32_t rust_check = add_magic_number(1000);
LOG(INFO) << "Rust runtime called, result: " << rust_check;
}

LOG(INFO) << "Starting runtime";

// Now all dependencies are running, start the thread for all the Wasm Nodes.
Expand Down
77 changes: 77 additions & 0 deletions rust/oak_runtime/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#
# Copyright 2019 The Project Oak Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

load("@io_bazel_rules_rust//rust:rust.bzl", "rust_library")
load("@rules_cc//cc:defs.bzl", "cc_library")

package(
licenses = ["notice"],
)

rust_library(
name = "oak_runtime",
srcs = [
"src/lib.rs",
],
crate_type = "staticlib",
edition = "2018",
)

# Strip unnecessary binary objects from the generated static library archive. It seems to contain
# mostly references to compiler intrinsics that are not needed and cannot be linked to the final
# enclave file.
# - The Asylo build creates a `.so` dynamic library to run in the enclave.
# - Because it's linking a `.so`, all static libraries dependencies are linked with the
# `-whole-archive` option, which pulls in all the object files in the static library regardless of
# whether they're used or not.
# - The static library built from the Rust code includes some small objects implementing compiler
# intrinsics, including `__divxc3()` in a file `divxc3.o`.
# - This object file has undefined references to `fmaxl`, `logbl` and `scalbnl` (intrinsics for
# working with `long double`s)
# - The Asylo tools versions of `libm.a` and `libc.a` do not include these symbols; they just have:
# + `libm.a`:
# * `fmax`, `logb` (for `double`)
# * `fmaxf`, `logbf` (for `float`)
# + `libc.a`
# * `scalbn` (for `double`)
# * `scalbnf` (for `float`)
# - Net cause: we're building the Rust library with a compiler that supports log double but linking
# with libraries that don't.
genrule(
name = "oak_runtime_stripped",
srcs = [":oak_runtime"],
outs = ["oak_runtime_stripped.a"],
cmd = "cp $< $@ && chmod +rw $@ && ar d $@ divxc3.o",
)

# Wrapper rule to expose the resulting static library as a statically linked cc_library and
# corresponding header so that it can be depended on by other cc_library and cc_binary rules.
#
# TODO: There seems to be something wrong with this rule related to caching in Bazel.
# To reproduce:
# - change src/lib.rs and introduce a syntax error
# - bazel build //rust/oak_runtime:wrapper
# - this should produce a compile error, instead Bazel is still caching the old artifact
# The final link of //oak/server/asylo:oak uses oak_runtime_stripped.a not libwrapper.a. Similarly,
# a change to the Rust file does induce a rebuild when doing bazel build //oak/server/dev:oak. So is
# Bazel maybe doing something special for a target with a single src that is itself a .a file?
cc_library(
name = "wrapper",
srcs = [":oak_runtime_stripped"],
hdrs = ["oak_runtime.h"],
linkstatic = True,
visibility = ["//oak/server:__subpackages__"],
)
6 changes: 6 additions & 0 deletions rust/oak_runtime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions rust/oak_runtime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Placeholder file, only to make VSCode happy. All compilation is actually done via Bazel.

[package]
name = "oak_runtime"
version = "0.1.0"
authors = ["Tiziano Santoro <[email protected]>"]

[lib]
crate-type = ["staticlib"]

# This signals to Cargo that this package should not be included in the parent workspace.
# TODO: Split Rust packages that are used in Oak Runtime and those used for the SDK into separate
# top-level workspaces.
[workspace]
29 changes: 29 additions & 0 deletions rust/oak_runtime/oak_runtime.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2019 The Project Oak Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef RUST_OAK_RUNTIME_OAK_RUNTIME_H_
#define RUST_OAK_RUNTIME_OAK_RUNTIME_H_

#include <cstdint>

extern "C" {

// TODO(#320): Remove this placeholder when we have some actual functions implemented in Rust and
// used from the C++ side of the Oak Runtime.
int32_t add_magic_number(int32_t x);
};

#endif // RUST_OAK_RUNTIME_OAK_RUNTIME_H_
24 changes: 24 additions & 0 deletions rust/oak_runtime/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// TODO: Plug in memory allocator and depend on https://doc.rust-lang.org/alloc/ to enable use of
// heap.

#![no_std]
#![feature(lang_items)]

use core::panic::PanicInfo;

// See https://doc.rust-lang.org/nomicon/panic-handler.html.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}

// See https://doc.rust-lang.org/1.2.0/book/no-stdlib.html.
#[lang = "eh_personality"]
pub extern "C" fn eh_personality() {}

/// An exported placeholder function to check that linking against C++ is successful.
/// It just adds "42" to the provided value and returns it to the caller.
#[no_mangle]
pub extern "C" fn add_magic_number(x: i32) -> i32 {
x + 42
}

0 comments on commit 8294164

Please sign in to comment.