Skip to content

Commit 6508eb8

Browse files
committed
jit: Enable JIT without "std" feature
Add a new "alloc" feature that indicates that the crate importing rbpf has an implementation of the GlobalAlloc trait. Memory protection is ignored in the "no_std" environment. Signed-off-by: Nate Sweet <[email protected]>
1 parent f31e471 commit 6508eb8

File tree

4 files changed

+70
-12
lines changed

4 files changed

+70
-12
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ combine = { version = "4.6", default-features = false }
3535
libc = { version = "0.2", optional = true }
3636
time = { version = "0.2", optional = true }
3737

38+
# Optional Dependencies for using alloc
39+
no-std-compat = {version = "0.4.1", optional = true }
40+
41+
3842
# Optional Dependencies for the CraneLift JIT
3943
cranelift-codegen = { version = "0.99", optional = true }
4044
cranelift-frontend = { version = "0.99", optional = true }
@@ -52,6 +56,7 @@ hex = "0.4.3"
5256
[features]
5357
default = ["std"]
5458
std = ["dep:time", "dep:libc", "combine/std"]
59+
alloc = ["dep:no-std-compat"]
5560
cranelift = [
5661
"dep:cranelift-codegen",
5762
"dep:cranelift-frontend",

README.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ get more information and examples on how to use it.
568568

569569
## Build features
570570

571-
### `no_std`
571+
### `std`
572572

573573
The `rbpf` crate has a Cargo feature named "std" that is enabled by default. To
574574
use `rbpf` in `no_std` environments this feature needs to be disabled. To do
@@ -581,15 +581,22 @@ rbpf = { version = "0.3.0", default-features = false }
581581
```
582582

583583
Note that when using this crate in `no_std` environments, the `jit` module
584-
isn't available. This is because it depends on functions provided by `libc`
585-
(`libc::posix_memalign()`, `libc::mprotect()`) which aren't available on
586-
`no_std`.
584+
isn't available, unless the `alloc` feature is turned on. This is because
585+
it depends on allocation being memory aligned and a memory protection function
586+
provided by `libc` (`libc::mprotect()`) which isn't available on `no_std`.
587587

588588
The `assembler` module is available, albeit with reduced debugging features. It
589589
depends on the `combine` crate providing parser combinators. Under `no_std`
590590
this crate only provides simple parsers which generate less descriptive error
591591
messages.
592592

593+
### `alloc`
594+
595+
The `rbpf` crate has a Cargoe featured named "alloc" that is not enabled by
596+
default. `std` must be turned off and is mutually exclusive with alloc.
597+
When `alloc` is turned on the library importing rbpf must provide an
598+
implementation of the [`GlobalAlloc` trait](https://doc.rust-lang.org/beta/std/alloc/trait.GlobalAlloc.html).
599+
593600
## Feedback welcome!
594601

595602
This is the author's first try at writing Rust code. He learned a lot in the

src/jit.rs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,8 @@ pub struct JitMemory<'a> {
10101010
contents: &'a mut [u8],
10111011
#[cfg(feature = "std")]
10121012
layout: std::alloc::Layout,
1013+
#[cfg(feature = "alloc")]
1014+
layout: core::alloc::Layout,
10131015
offset: usize,
10141016
}
10151017

@@ -1055,7 +1057,45 @@ impl<'a> JitMemory<'a> {
10551057
Ok(mem)
10561058
}
10571059

1058-
#[cfg(not(feature = "std"))]
1060+
#[cfg(feature = "alloc")]
1061+
pub fn new(
1062+
prog: &[u8],
1063+
helpers: &HashMap<u32, ebpf::Helper>,
1064+
use_mbuff: bool,
1065+
update_data_ptr: bool,
1066+
) -> Result<JitMemory<'a>, Error> {
1067+
let layout;
1068+
1069+
// Allocate the appropriately sized memory.
1070+
let contents = unsafe {
1071+
// Create a layout with the proper size and alignment.
1072+
let size = NUM_PAGES * PAGE_SIZE;
1073+
layout = core::alloc::Layout::from_size_align_unchecked(size, PAGE_SIZE);
1074+
1075+
// Allocate the region of memory.
1076+
let ptr = alloc::alloc::alloc(layout);
1077+
if ptr.is_null() {
1078+
return Err(Error::new(ErrorKind::Other, "Out of memory"));
1079+
}
1080+
1081+
// Convert to a slice.
1082+
no_std_compat::slice::from_raw_parts_mut(ptr, size)
1083+
};
1084+
1085+
let mut mem = JitMemory {
1086+
contents,
1087+
layout,
1088+
offset: 0,
1089+
};
1090+
1091+
let mut jit = JitCompiler::new();
1092+
jit.jit_compile(&mut mem, prog, use_mbuff, update_data_ptr, helpers)?;
1093+
jit.resolve_jumps(&mut mem)?;
1094+
1095+
Ok(mem)
1096+
}
1097+
1098+
#[cfg(not(any(feature = "std", feature = "alloc")))]
10591099
pub fn new(
10601100
prog: &[u8],
10611101
executable_memory: &'a mut [u8],
@@ -1108,11 +1148,14 @@ impl IndexMut<usize> for JitMemory<'_> {
11081148
}
11091149
}
11101150

1111-
#[cfg(feature = "std")]
1151+
#[cfg(any(feature = "std", feature = "alloc"))]
11121152
impl Drop for JitMemory<'_> {
11131153
fn drop(&mut self) {
11141154
unsafe {
1155+
#[cfg(feature = "std")]
11151156
std::alloc::dealloc(self.contents.as_mut_ptr(), self.layout);
1157+
#[cfg(feature = "alloc")]
1158+
alloc::alloc::dealloc(self.contents.as_mut_ptr(), self.layout);
11161159
}
11171160
}
11181161
}

src/lib.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
// Configures the crate to be `no_std` when `std` feature is disabled.
1414
#![cfg_attr(not(feature = "std"), no_std)]
1515

16+
#[cfg(all(feature = "std", feature = "alloc"))]
17+
compile_error!("feature \"std\" and feature \"alloc\" cannot be enabled at the same time");
18+
1619
extern crate byteorder;
1720
extern crate combine;
1821
extern crate log;
@@ -510,11 +513,11 @@ impl<'a> EbpfVmMbuff<'a> {
510513
"Error: No program set, call prog_set() to load one",
511514
))?,
512515
};
513-
#[cfg(feature = "std")]
516+
#[cfg(any(feature = "std", feature = "alloc"))]
514517
{
515518
self.jit = Some(jit::JitMemory::new(prog, &self.helpers, true, false)?);
516519
}
517-
#[cfg(not(feature = "std"))]
520+
#[cfg(not(any(feature = "std", feature = "alloc")))]
518521
{
519522
let exec_memory = match self.custom_exec_memory.take() {
520523
Some(memory) => memory,
@@ -1141,11 +1144,11 @@ impl<'a> EbpfVmFixedMbuff<'a> {
11411144
"Error: No program set, call prog_set() to load one",
11421145
))?,
11431146
};
1144-
#[cfg(feature = "std")]
1147+
#[cfg(any(feature = "std", feature = "alloc"))]
11451148
{
11461149
self.parent.jit = Some(jit::JitMemory::new(prog, &self.parent.helpers, true, true)?);
11471150
}
1148-
#[cfg(not(feature = "std"))]
1151+
#[cfg(not(any(feature = "std", feature = "alloc")))]
11491152
{
11501153
let exec_memory = match self.parent.custom_exec_memory.take() {
11511154
Some(memory) => memory,
@@ -1661,7 +1664,7 @@ impl<'a> EbpfVmRaw<'a> {
16611664
"Error: No program set, call prog_set() to load one",
16621665
))?,
16631666
};
1664-
#[cfg(feature = "std")]
1667+
#[cfg(any(feature = "std", feature = "alloc"))]
16651668
{
16661669
self.parent.jit = Some(jit::JitMemory::new(
16671670
prog,
@@ -1670,7 +1673,7 @@ impl<'a> EbpfVmRaw<'a> {
16701673
false,
16711674
)?);
16721675
}
1673-
#[cfg(not(feature = "std"))]
1676+
#[cfg(not(any(feature = "std", feature = "alloc")))]
16741677
{
16751678
let exec_memory = match self.parent.custom_exec_memory.take() {
16761679
Some(memory) => memory,

0 commit comments

Comments
 (0)