wip: elf packing
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Jake Hillion 2022-05-10 22:24:39 +01:00
parent f07dab1b4b
commit bd0d114145
5 changed files with 188 additions and 7 deletions

93
Cargo.lock generated
View File

@ -2,6 +2,23 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -131,6 +148,7 @@ dependencies = [
"libc",
"log",
"nix",
"object",
"serde",
"serde_json",
"tempfile",
@ -147,6 +165,15 @@ dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "criterion"
version = "0.3.5"
@ -284,6 +311,29 @@ dependencies = [
"instant",
]
[[package]]
name = "flate2"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
dependencies = [
"cfg-if",
"crc32fast",
"libc",
"miniz_oxide",
]
[[package]]
name = "getrandom"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "half"
version = "1.8.2"
@ -295,6 +345,9 @@ name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hermit-abi"
@ -405,6 +458,15 @@ dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
dependencies = [
"adler",
]
[[package]]
name = "nix"
version = "0.23.1"
@ -437,6 +499,25 @@ dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456"
dependencies = [
"crc32fast",
"flate2",
"hashbrown",
"indexmap",
"memchr",
]
[[package]]
name = "once_cell"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "oorandom"
version = "11.1.3"
@ -735,6 +816,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.3.2"
@ -746,6 +833,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.79"

View File

@ -22,6 +22,7 @@ nix = "0.23.1"
close_fds = "0.3.2"
tempfile = "3.3"
object = { version = "0.28", features = ["write_core"] }
[dev-dependencies]
criterion = "0.3"

View File

@ -18,13 +18,22 @@ pub enum Error {
#[error("bincode: {0}")]
Bincode(#[from] bincode::Error),
#[error("elf: read: {0}")]
ElfRead(#[from] object::read::Error),
#[error("elf: write: {0}")]
ElfWrite(#[from] object::write::Error),
#[error("bad pipe specification: a pipe must have exactly one reader and one writer: {0}")]
BadPipe(String),
#[error("bad socket specification: a socket must have exactly one reader and one writer: {0}")]
BadFileSocket(String),
#[error("bad specification type: only .json files are supported")]
#[error("no specification provided")]
NoSpecification,
#[error("bad specification type: only json files are supported")]
BadSpecType,
#[error("bad trigger argument: this entrypoint is not triggered by something with arguments")]

View File

@ -2,6 +2,7 @@ use log::{debug, info};
pub mod clone;
mod error;
mod pack;
mod spawner;
mod specification;
mod void;
@ -18,7 +19,6 @@ use std::path::Path;
use nix::fcntl::OFlag;
use nix::sys::socket;
use nix::unistd;
pub struct PackArgs<'a> {
pub spec: &'a Path,
pub binary: &'a Path,
@ -26,16 +26,14 @@ pub struct PackArgs<'a> {
}
pub fn pack(args: &PackArgs) -> Result<()> {
let spec: Specification = if args.spec.ends_with(".json") {
let spec: Specification = if args.spec.extension().map(|e| e == "json") == Some(true) {
let f = std::fs::File::open(args.spec)?;
Ok(serde_json::from_reader(f)?)
} else {
Err(Error::BadSpecType)
}?;
let spec_bin = bincode::serialize(&spec)?;
Ok(())
pack::pack_binary(args.binary, &spec, args.output)
}
pub struct RunArgs<'a> {
@ -56,7 +54,12 @@ pub fn run(args: &RunArgs) -> Result<()> {
Err(Error::BadSpecType)
}
} else {
unimplemented!("reading spec from the elf is unimplemented")
let spec = pack::extract_specification(args.binary)?;
if let Some(s) = spec {
Ok(s)
} else {
Err(Error::NoSpecification)
}
}?;
debug!("specification read: {:?}", &spec);

75
src/pack.rs Normal file
View File

@ -0,0 +1,75 @@
use crate::{Result, Specification};
use std::fs::File;
use std::path::Path;
use bincode::Options;
use object::endian::Endianness;
use object::read::ReadCache;
use object::read::{Object, ObjectSection};
use object::write::{StandardSegment, StreamingBuffer};
use object::SectionKind;
const SPECIFICATION_SECTION_NAME: &str = "void_specification";
pub(crate) fn pack_binary(binary: &Path, spec: &Specification, output: &Path) -> Result<()> {
let binary = File::open(binary)?;
let binary = ReadCache::new(binary);
let output = File::create(output)?;
let mut output = StreamingBuffer::new(output);
let input_object = object::File::parse(&binary)?;
let format = input_object.format();
let architecture = input_object.architecture();
let endianness = if input_object.is_little_endian() {
Endianness::Little
} else {
Endianness::Big
};
let mut output_object = object::write::Object::new(format, architecture, endianness);
for input_section in input_object.sections() {
let output_section = output_object.add_section(
input_section.segment_name_bytes()?.unwrap_or(&[]).to_vec(),
input_section.name_bytes()?.to_vec(),
input_section.kind(),
);
output_object.set_section_data(output_section, input_section.data()?, 0);
}
let spec_section = output_object.add_section(
output_object.segment_name(StandardSegment::Debug).to_vec(),
SPECIFICATION_SECTION_NAME.to_string().into(),
SectionKind::Other,
);
let spec = bincode_options().serialize(spec)?;
output_object.set_section_data(spec_section, spec, 0);
output_object.emit(&mut output)?;
Ok(())
}
pub(crate) fn extract_specification(binary: &Path) -> Result<Option<Specification>> {
let binary = File::open(binary)?;
let binary = ReadCache::new(binary);
let input_object = object::File::parse(&binary)?;
let spec_section = if let Some(s) = input_object.section_by_name(SPECIFICATION_SECTION_NAME) {
s
} else {
return Ok(None);
};
let spec_data = spec_section.data()?;
Ok(Some(bincode_options().deserialize(spec_data)?))
}
fn bincode_options() -> impl bincode::Options {
bincode::DefaultOptions::new()
}