Add data section names and conversion to object file format
* Data section names are encoded in the object file format * Objects can be converted into their file format layouts * Add writing/reading test to make sure that an object converted to bytes and then back from bytes is equal to hopefully catch major object translations Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -143,6 +143,7 @@ impl Assemble for DataSection {
|
|||||||
);
|
);
|
||||||
asm.names.pop();
|
asm.names.pop();
|
||||||
Ok(obj::DataSection {
|
Ok(obj::DataSection {
|
||||||
|
name: self.name.clone(),
|
||||||
start,
|
start,
|
||||||
len: section_len,
|
len: section_len,
|
||||||
contents,
|
contents,
|
||||||
|
|||||||
@@ -1,23 +1,34 @@
|
|||||||
use crate::vm::obj::error::{ParseError, Result};
|
use crate::vm::obj::error::{ParseError, Result};
|
||||||
use byteorder::{ReadBytesExt, LE};
|
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
io::{Cursor, Read},
|
io::{Cursor, Read, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MAGIC: u64 = 0xDEAD_BEA7_BA5E_BA11;
|
pub const MAGIC: u64 = 0xDEAD_BEA7_BA5E_BA11;
|
||||||
pub const OBJ_VERSION: u32 = 0;
|
pub const OBJ_VERSION: u32 = 0;
|
||||||
const OBJECT_HEADER_LEN: usize = 16; // 8 + 4 + 4
|
const OBJECT_HEADER_LEN: usize = 16; // 8 + 4 + 4
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub sections: Vec<Section>,
|
pub sections: Vec<Section>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Object {
|
impl Object {
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut cursor = Cursor::new(Vec::new());
|
||||||
|
cursor.write_u64::<LE>(MAGIC).unwrap();
|
||||||
|
cursor.write_u32::<LE>(OBJ_VERSION).unwrap();
|
||||||
|
cursor.write_u32::<LE>(self.sections.len() as u32).unwrap();
|
||||||
|
for section in self.sections.iter() {
|
||||||
|
cursor.write(§ion.to_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
cursor.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
||||||
let mut cursor = Cursor::new(bytes);
|
let mut cursor = Cursor::new(bytes);
|
||||||
let magic = cursor.read_u64::<LE>()?;
|
let magic = cursor.read_u64::<LE>()?;
|
||||||
@@ -29,18 +40,23 @@ impl Object {
|
|||||||
|
|
||||||
let mut sections = Vec::new();
|
let mut sections = Vec::new();
|
||||||
for _ in 0..section_count {
|
for _ in 0..section_count {
|
||||||
let section = Section::from_bytes(&mut cursor)?;
|
let start = cursor.position() as usize;
|
||||||
|
let section = Section::from_bytes(&bytes[start..])?;
|
||||||
|
cursor.set_position((start + section.len()) as u64);
|
||||||
sections.push(section);
|
sections.push(section);
|
||||||
}
|
}
|
||||||
Ok(Object { version, sections })
|
Ok(Object { version, sections })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn virtual_len(&self) -> usize {
|
pub fn virtual_len(&self) -> usize {
|
||||||
self.sections.iter()
|
self.sections
|
||||||
|
.iter()
|
||||||
.map(|s| match s {
|
.map(|s| match s {
|
||||||
Section::Data(DataSection { start, len, .. }) => { (start + len) as usize }
|
Section::Data(DataSection { start, len, .. }) => (start + len) as usize,
|
||||||
Section::Meta { .. } => { 0 }
|
Section::Meta { .. } => 0,
|
||||||
}).max().unwrap_or(0)
|
})
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +85,16 @@ macro_rules! section_kind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SectionKind> for u8 {
|
||||||
|
fn from(other: SectionKind) -> Self {
|
||||||
|
match other {
|
||||||
|
$(
|
||||||
|
$enum_name::$name => $value,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,20 +105,45 @@ section_kind! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Section {
|
pub enum Section {
|
||||||
Data(DataSection),
|
Data(DataSection),
|
||||||
Meta(MetaSection),
|
Meta(MetaSection),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Section {
|
impl Section {
|
||||||
fn from_bytes(cursor: &mut Cursor<&[u8]>) -> Result<Self> {
|
pub fn len(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Section::Data(s) => { 1 + 8 + s.len() },
|
||||||
|
Section::Meta(s) => { 1 + 8 + s.len() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut cursor = Cursor::new(Vec::new());
|
||||||
|
let bytes = match self {
|
||||||
|
Section::Data(s) => {
|
||||||
|
cursor.write_u8(SectionKind::Data.into()).unwrap();
|
||||||
|
s.to_bytes()
|
||||||
|
}
|
||||||
|
Section::Meta(s) => {
|
||||||
|
cursor.write_u8(SectionKind::Meta.into()).unwrap();
|
||||||
|
s.to_bytes()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
cursor.write_u64::<LE>(bytes.len() as u64).unwrap();
|
||||||
|
cursor.write(&bytes).unwrap();
|
||||||
|
cursor.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
||||||
|
let mut cursor = Cursor::new(bytes);
|
||||||
|
let kind: SectionKind = cursor.read_u8()?.try_into()?;
|
||||||
let len = cursor.read_u64::<LE>()?;
|
let len = cursor.read_u64::<LE>()?;
|
||||||
let start = cursor.position() as usize;
|
let start = cursor.position() as usize;
|
||||||
let end = start + len as usize;
|
let end = start + len as usize;
|
||||||
|
|
||||||
let bytes = &cursor.get_ref()[start..end];
|
let bytes = &cursor.get_ref()[start..end];
|
||||||
let kind: SectionKind = cursor.read_u8()?.try_into()?;
|
|
||||||
match kind {
|
match kind {
|
||||||
SectionKind::Data => Ok(Section::Data(DataSection::from_bytes(bytes)?)),
|
SectionKind::Data => Ok(Section::Data(DataSection::from_bytes(bytes)?)),
|
||||||
SectionKind::Meta => Ok(Section::Meta(MetaSection::from_bytes(bytes)?)),
|
SectionKind::Meta => Ok(Section::Meta(MetaSection::from_bytes(bytes)?)),
|
||||||
@@ -100,20 +151,46 @@ impl Section {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct DataSection {
|
pub struct DataSection {
|
||||||
|
pub name: String,
|
||||||
pub start: u64,
|
pub start: u64,
|
||||||
pub len: u64,
|
pub len: u64,
|
||||||
pub contents: Vec<u8>,
|
pub contents: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataSection {
|
impl DataSection {
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
2 + self.name.as_bytes().len() + 8 + 8 + self.contents.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut cursor = Cursor::new(Vec::new());
|
||||||
|
assert!(self.name.len() < u16::max_value() as usize);
|
||||||
|
cursor.write_u16::<LE>(self.name.len() as u16).unwrap();
|
||||||
|
cursor.write(self.name.as_bytes()).unwrap();
|
||||||
|
cursor.write_u64::<LE>(self.start).unwrap();
|
||||||
|
cursor.write_u64::<LE>(self.len).unwrap();
|
||||||
|
cursor.write(&self.contents).unwrap();
|
||||||
|
cursor.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
||||||
let mut cursor = Cursor::new(bytes);
|
let mut cursor = Cursor::new(bytes);
|
||||||
|
|
||||||
|
let name_len = cursor.read_u16::<LE>()? as usize;
|
||||||
|
let name_start = cursor.position() as usize;
|
||||||
|
let name_end = name_start + name_len;
|
||||||
|
let name_bytes = &bytes[name_start .. name_end];
|
||||||
|
let name_string = String::from_utf8(name_bytes.to_vec())?;
|
||||||
|
cursor.set_position(name_end as u64);
|
||||||
|
|
||||||
let start = cursor.read_u64::<LE>()?;
|
let start = cursor.read_u64::<LE>()?;
|
||||||
let len = cursor.read_u64::<LE>()?;
|
let len = cursor.read_u64::<LE>()?;
|
||||||
|
|
||||||
let contents = &bytes[cursor.position() as usize..];
|
let contents = &bytes[cursor.position() as usize..];
|
||||||
Ok(DataSection {
|
Ok(DataSection {
|
||||||
|
name: name_string,
|
||||||
start,
|
start,
|
||||||
len,
|
len,
|
||||||
contents: From::from(contents),
|
contents: From::from(contents),
|
||||||
@@ -121,12 +198,20 @@ impl DataSection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct MetaSection {
|
pub struct MetaSection {
|
||||||
pub entries: HashMap<String, u64>,
|
pub entries: HashMap<String, u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetaSection {
|
impl MetaSection {
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
todo!() // 8 + ...
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
||||||
let mut cursor = Cursor::new(bytes);
|
let mut cursor = Cursor::new(bytes);
|
||||||
let entry_count = cursor.read_u64::<LE>()?;
|
let entry_count = cursor.read_u64::<LE>()?;
|
||||||
@@ -145,3 +230,27 @@ impl MetaSection {
|
|||||||
Ok(MetaSection { entries })
|
Ok(MetaSection { entries })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_from_bytes() {
|
||||||
|
let obj = Object {
|
||||||
|
version: OBJ_VERSION,
|
||||||
|
sections: vec![
|
||||||
|
Section::Data(DataSection {
|
||||||
|
name: "data".to_string(),
|
||||||
|
start: 0,
|
||||||
|
len: 16,
|
||||||
|
contents: vec!(0u8; 16),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let obj_bytes = obj.to_bytes();
|
||||||
|
let converted = Object::from_bytes(&obj_bytes).unwrap();
|
||||||
|
assert_eq!(obj, converted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ impl State {
|
|||||||
for section in object.sections {
|
for section in object.sections {
|
||||||
match section {
|
match section {
|
||||||
Section::Data(DataSection {
|
Section::Data(DataSection {
|
||||||
|
name: _,
|
||||||
start,
|
start,
|
||||||
len,
|
len,
|
||||||
contents,
|
contents,
|
||||||
|
|||||||
Reference in New Issue
Block a user