Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Add BPF support & C-based BPF tic-tac-toe #1422

Merged
merged 7 commits into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ path = "src/bin/wallet.rs"
codecov = { repository = "solana-labs/solana", branch = "master", service = "github" }

[features]
unstable = []
ipv6 = []
bpf_c = []
chacha = []
cuda = []
erasure = []
ipv6 = []
test = []
chacha = []
unstable = []

[dependencies]
atty = "0.2"
Expand All @@ -82,6 +83,7 @@ bytes = "0.4"
chrono = { version = "0.4.0", features = ["serde"] }
clap = "2.31"
dirs = "1.0.2"
elf = "0.0.10"
env_logger = "0.5.12"
generic-array = { version = "0.12.0", default-features = false, features = ["serde"] }
getopts = "0.2"
Expand All @@ -98,6 +100,7 @@ matches = "0.1.6"
nix = "0.11.0"
pnet_datalink = "0.21.0"
rand = "0.5.1"
rbpf = { git = "https://github.com/solana-labs/rbpf" }
jackcmay marked this conversation as resolved.
Show resolved Hide resolved
rayon = "1.0.0"
reqwest = "0.9.0"
ring = "0.13.2"
Expand All @@ -114,9 +117,8 @@ tokio-codec = "0.1"
untrusted = "0.6.2"

[dev-dependencies]
noop = { path = "programs/noop" }
print = { path = "programs/print" }
move_funds = { path = "programs/move_funds" }
move_funds = { path = "programs/native/move_funds" }
noop = { path = "programs/native/noop" }

[[bench]]
name = "bank"
Expand All @@ -141,8 +143,7 @@ name = "chacha"
members = [
".",
"common",
"programs/noop",
"programs/print",
"programs/move_funds",
"programs/native/move_funds",
"programs/native/noop",
"programs/bpf/noop_rust",
]

27 changes: 25 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::env;
use std::fs;
use std::process::Command;

fn main() {
println!("cargo:rerun-if-changed=target/perf-libs");
Expand All @@ -14,11 +15,33 @@ fn main() {
}
});

let bpf_c = !env::var("CARGO_FEATURE_BPF_C").is_err();
let chacha = !env::var("CARGO_FEATURE_CHACHA").is_err();
let cuda = !env::var("CARGO_FEATURE_CUDA").is_err();
let erasure = !env::var("CARGO_FEATURE_ERASURE").is_err();
let chacha = !env::var("CARGO_FEATURE_CHACHA").is_err();

if cuda || erasure || chacha {
if bpf_c {
let out_dir = "target/".to_string() + &env::var("PROFILE").unwrap();

println!("cargo:rerun-if-changed=programs/bpf/move_funds_c/build.sh");
println!("cargo:rerun-if-changed=programs/bpf/move_funds_c/src/move_funds.c");
println!("cargo:warning=(not a warning) Compiling move_funds_c");
let status = Command::new("programs/bpf/move_funds_c/build.sh")
.arg(&out_dir)
.status()
.expect("Failed to call move_funds_c build script");
assert!(status.success());

println!("cargo:rerun-if-changed=programs/bpf/tictactoe_c/build.sh");
println!("cargo:rerun-if-changed=programs/bpf/tictactoe_c/src/tictactoe.c");
println!("cargo:warning=(not a warning) Compiling tictactoe_c");
let status = Command::new("programs/bpf/tictactoe_c/build.sh")
.arg(&out_dir)
.status()
.expect("Failed to call tictactoe_c build script");
assert!(status.success());
}
if chacha || cuda || erasure {
println!("cargo:rustc-link-search=native=target/perf-libs");
}
if cuda {
Expand Down
2 changes: 2 additions & 0 deletions common/src/account.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use pubkey::Pubkey;

/// An Account with userdata that is stored on chain
#[repr(C)]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct Account {
/// tokens in the account
Expand All @@ -22,6 +23,7 @@ impl Account {
}
}

#[repr(C)]
#[derive(Debug)]
pub struct KeyedAccount<'a> {
pub key: &'a Pubkey,
Expand Down
1 change: 1 addition & 0 deletions common/src/pubkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use generic_array::typenum::U32;
use generic_array::GenericArray;
use std::fmt;

#[repr(C)]
#[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Pubkey(GenericArray<u8, U32>);

Expand Down
9 changes: 9 additions & 0 deletions programs/bpf/move_funds_c/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash -ex

OUTDIR="${1:-../../../target/release/}"
THISDIR=$(dirname "$0")
mkdir -p "$OUTDIR"
/usr/local/opt/llvm/bin/clang -Werror -target bpf -O2 -emit-llvm -fno-builtin -o "$OUTDIR"/move_funds_c.bc -c "$THISDIR"/src/move_funds.c
/usr/local/opt/llvm/bin/llc -march=bpf -filetype=obj -function-sections -o "$OUTDIR"/move_funds_c.o "$OUTDIR"/move_funds_c.bc

#/usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble "$OUTDIR"/move_funds_c.o
3 changes: 3 additions & 0 deletions programs/bpf/move_funds_c/dump.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

/usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble ../../../target/release/move_funds_c.o
130 changes: 130 additions & 0 deletions programs/bpf/move_funds_c/src/move_funds.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@

//#include <stdint.h>
//#include <stddef.h>

#if 1
// one way to define a helper function is with index as a fixed value
#define BPF_TRACE_PRINTK_IDX 6
static int (*sol_print)(int, int, int, int, int) = (void *)BPF_TRACE_PRINTK_IDX;
#else
// relocation is another option
extern int sol_print(int, int, int, int, int);
#endif

typedef long long unsigned int uint64_t;
typedef long long int int64_t;
typedef unsigned char uint8_t;

typedef enum { false = 0, true } bool;

#define SIZE_PUBKEY 32
typedef struct {
uint8_t x[SIZE_PUBKEY];
} SolPubkey;

typedef struct {
SolPubkey *key;
int64_t tokens;
uint64_t userdata_len;
uint8_t *userdata;
SolPubkey *program_id;
} SolKeyedAccounts;

// TODO support BPF function calls rather then forcing everything to be inlined
#define SOL_FN_PREFIX __attribute__((always_inline)) static

// TODO move this to a registered helper
SOL_FN_PREFIX void sol_memcpy(void *dst, void *src, int len) {
for (int i = 0; i < len; i++) {
*((uint8_t *)dst + i) = *((uint8_t *)src + i);
}
}

#define sol_panic() _sol_panic(__LINE__)
SOL_FN_PREFIX void _sol_panic(uint64_t line) {
sol_print(0, 0, 0xFF, 0xFF, line);
char *pv = (char *)1;
*pv = 1;
}

SOL_FN_PREFIX int sol_deserialize(uint8_t *src, uint64_t num_ka, SolKeyedAccounts *ka,
uint8_t **userdata, uint64_t *userdata_len) {
if (num_ka != *(uint64_t *)src) {
return -1;
}
src += sizeof(uint64_t);

// TODO fixed iteration loops ok? unrolled?
for (int i = 0; i < num_ka; i++) { // TODO this should end up unrolled, confirm
// key
ka[i].key = (SolPubkey *)src;
src += SIZE_PUBKEY;

// tokens
ka[i].tokens = *(uint64_t *)src;
src += sizeof(uint64_t);

// account userdata
ka[i].userdata_len = *(uint64_t *)src;
src += sizeof(uint64_t);
ka[i].userdata = src;
src += ka[i].userdata_len;

// program_id
ka[i].program_id = (SolPubkey *)src;
src += SIZE_PUBKEY;
}
// tx userdata
*userdata_len = *(uint64_t *)src;
src += sizeof(uint64_t);
*userdata = src;

return 0;
}


// -- Debug --

SOL_FN_PREFIX void print_key(SolPubkey *key) {
for (int j = 0; j < SIZE_PUBKEY; j++) {
sol_print(0, 0, 0, j, key->x[j]);
}
}

SOL_FN_PREFIX void print_userdata(uint8_t *data, int len) {
for (int j = 0; j < len; j++) {
sol_print(0, 0, 0, j, data[j]);
}
}

SOL_FN_PREFIX void print_params(uint64_t num_ka, SolKeyedAccounts *ka,
uint8_t *userdata, uint64_t userdata_len) {
sol_print(0, 0, 0, 0, num_ka);
for (int i = 0; i < num_ka; i++) {
// key
print_key(ka[i].key);

// tokens
sol_print(0, 0, 0, 0, ka[i].tokens);

// account userdata
print_userdata(ka[i].userdata, ka[i].userdata_len);

// program_id
print_key(ka[i].program_id);
}
// tx userdata
print_userdata(userdata, userdata_len);
}

void entrypoint(char *buf) {
SolKeyedAccounts ka[3];
uint64_t userdata_len;
uint8_t *userdata;

if (0 != sol_deserialize((uint8_t *)buf, 3, ka, &userdata, &userdata_len)) {
return;
}

print_params(3, ka, userdata, userdata_len);
}
8 changes: 8 additions & 0 deletions programs/bpf/noop_rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "noop_rust"
version = "0.1.0"
authors = ["Jack May <jack@solana.com>"]

[dependencies]
rbpf = { git = "https://github.com/solana-labs/rbpf" }
solana = { path = "../../.." }
10 changes: 10 additions & 0 deletions programs/bpf/noop_rust/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash -ex

# TODO building release flavor with rust produces a bunch of output .bc files
INTERDIR=../../../target/release
OUTDIR="${1:-../../../target/debug/}"
mkdir -p "$OUTDIR"
# cargo +nightly rustc --release -- -C panic=abort --emit=llvm-ir
cargo +nightly rustc --release -- -C panic=abort --emit=llvm-bc
cp "$INTERDIR"/deps/noop_rust-*.bc "$OUTDIR"/noop_rust.bc
/usr/local/opt/llvm/bin/llc -march=bpf -filetype=obj -o "$OUTDIR"/noop_rust.o "$OUTDIR"/noop_rust.bc
3 changes: 3 additions & 0 deletions programs/bpf/noop_rust/dump.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

/usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble target/release/noop_rust.o
15 changes: 15 additions & 0 deletions programs/bpf/noop_rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
extern crate rbpf;

use std::mem::transmute;

#[no_mangle]
#[link_section = ".text,entrypoint"] // TODO platform independent needed
pub extern "C" fn entrypoint(_raw: *mut u8) {
let bpf_func_trace_printk = unsafe {
transmute::<u64, extern "C" fn(u64, u64, u64, u64, u64)>(
rbpf::helpers::BPF_TRACE_PRINTK_IDX as u64,
)
};

bpf_func_trace_printk(0, 0, 1, 2, 3);
}
9 changes: 9 additions & 0 deletions programs/bpf/tictactoe_c/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash -ex

OUTDIR="${1:-../../../target/release/}"
THISDIR=$(dirname "$0")
mkdir -p "$OUTDIR"
/usr/local/opt/llvm/bin/clang -Werror -target bpf -O2 -emit-llvm -fno-builtin -o "$OUTDIR"/tictactoe_c.bc -c "$THISDIR"/src/tictactoe.c
/usr/local/opt/llvm/bin/llc -march=bpf -filetype=obj -function-sections -o "$OUTDIR"/tictactoe_c.o "$OUTDIR"/tictactoe_c.bc

# /usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble "$OUTDIR"/tictactoe_c.o
3 changes: 3 additions & 0 deletions programs/bpf/tictactoe_c/dump.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

/usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble ../../../target/release/tictactoe_c.o
57 changes: 57 additions & 0 deletions programs/bpf/tictactoe_c/makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Notes:

# TODO needs more investigation into what r10 is used for
# -O2 adds changes the generated code from:
# main:
# 0: b7 01 00 00 00 00 00 00 r1 = 0
# 1: 63 1a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r1
# 2: bf 10 00 00 00 00 00 00 r0 = r1
# 3: 95 00 00 00 00 00 00 00 exit
# To:
# main:
# 0: b7 00 00 00 00 00 00 00 r0 = 0
# 1: 95 00 00 00 00 00 00 00 exit

# - building bpf module that includes stdint.h with clang only (no w/ llc) results in an error
# $(TOOLS_DIR)/clang -nostdlib -O2 -fpie -target bpf -o bpf.o -c bpf.c
# => n file included from /usr/include/sys/_types/_intptr_t.h:30:
# => /usr/include/machine/types.h:37:2: error: architecture not supported
# => error architecture not supported

TOOLS_DIR = /usr/local/opt/llvm/bin

test_x86.o: test.c
$(TOOLS_DIR)/clang -O2 -fpie -target x86_64 -o $@ -c $<

test_x86.so: test_x86.o
$(TOOLS_DIR)/ld.lld --shared -o $@ $<

test_x86_dylib.o: test.c
$(TOOLS_DIR)/clang -O2 -fpie -target x86_64-apple-darwin13.0.0 -o $@ -c $<

test_x86.dylib: test_x86_dylib.o
/usr/local/opt/llvm/bin/ld64.lld -dylib -lc -arch x86_64 -o $@ $<

# TODO does not work if pulling in stdlib, claims unsupported architecture
bpf_clang.o: bpf.c
$(TOOLS_DIR)/clang -nostdlib -O2 -fpie -target bpf -o bpf.o -c bpf.c

bpf.o: bpf.c
$(TOOLS_DIR)/clang -O2 -emit-llvm -c $< -o - | $(TOOLS_DIR)/llc -march=bpf -filetype=obj -o $@

bpf_rust.o: bpf_rust.rs
rustc +nightly -C opt-level=2 -C panic=abort --emit llvm-bc $<
$(TOOLS_DIR)/llc -march=bpf -filetype=obj -function-sections -o $@ bpf_rust.bc

dumpall:
$(TOOLS_DIR)/llvm-objdump -color -source -disassemble *.o

cleanall:
rm -f *.o
rm -f *.so
rm -f *.dylib
rm -f *.ll
rm -rf *.bc

all: bpf_clang.o bpf.o

Loading