use crate::{BufferIterator, FromBytes, ToBytes, WritableBuffer};
use crate::ko::errors::{ReldEntryParseError, SymbolParseError};
use crate::ko::sections::{DataIdx, InstrIdx, StringIdx, SymbolIdx};
use crate::ko::SectionIdx;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
#[repr(u8)]
pub enum SymBind {
Local = 0,
Global = 1,
Extern = 2,
}
impl TryFrom<u8> for SymBind {
type Error = ();
fn try_from(byte: u8) -> Result<Self, Self::Error> {
match byte {
0 => Ok(Self::Local),
1 => Ok(Self::Global),
2 => Ok(Self::Extern),
_ => Err(()),
}
}
}
impl From<SymBind> for u8 {
fn from(bind: SymBind) -> u8 {
match bind {
SymBind::Local => 0,
SymBind::Global => 1,
SymBind::Extern => 2,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
#[repr(u8)]
pub enum SymType {
NoType = 0,
Object = 1,
Func = 2,
Section = 3,
File = 4,
}
impl TryFrom<u8> for SymType {
type Error = ();
fn try_from(byte: u8) -> Result<Self, Self::Error> {
match byte {
0 => Ok(Self::NoType),
1 => Ok(Self::Object),
2 => Ok(Self::Func),
3 => Ok(Self::Section),
4 => Ok(Self::File),
_ => Err(()),
}
}
}
impl From<SymType> for u8 {
fn from(sym_type: SymType) -> u8 {
match sym_type {
SymType::NoType => 0,
SymType::Object => 1,
SymType::Func => 2,
SymType::Section => 3,
SymType::File => 4,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
#[repr(u8)]
pub enum OperandIndex {
One = 1,
Two = 2,
}
impl TryFrom<u8> for OperandIndex {
type Error = ();
fn try_from(byte: u8) -> Result<Self, Self::Error> {
match byte {
1 => Ok(Self::One),
2 => Ok(Self::Two),
_ => Err(()),
}
}
}
impl From<OperandIndex> for u8 {
fn from(index: OperandIndex) -> u8 {
match index {
OperandIndex::One => 1,
OperandIndex::Two => 2,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct KOSymbol {
pub name_idx: StringIdx,
pub value_idx: DataIdx,
pub size: u16,
pub sym_bind: SymBind,
pub sym_type: SymType,
pub sh_idx: SectionIdx,
}
impl KOSymbol {
const SYMBOL_SIZE: u32 = 14;
pub const fn new(
name_idx: StringIdx,
value_idx: DataIdx,
size: u16,
sym_bind: SymBind,
sym_type: SymType,
sh_idx: SectionIdx,
) -> Self {
Self {
name_idx,
value_idx,
size,
sym_bind,
sym_type,
sh_idx,
}
}
pub const fn size_bytes() -> u32 {
Self::SYMBOL_SIZE
}
pub fn parse(source: &mut BufferIterator) -> Result<Self, SymbolParseError> {
let name_idx = StringIdx::from(
u32::from_bytes(source).map_err(|_| SymbolParseError::MissingNameIndexError)?,
);
let value_idx = DataIdx::from(
u32::from_bytes(source).map_err(|_| SymbolParseError::MissingValueIndexError)?,
);
let size = u16::from_bytes(source).map_err(|_| SymbolParseError::MissingSymbolSizeError)?;
let raw_sym_bind =
u8::from_bytes(source).map_err(|_| SymbolParseError::MissingSymbolBindingError)?;
let sym_bind = SymBind::try_from(raw_sym_bind)
.map_err(|_| SymbolParseError::InvalidSymbolBindingError(raw_sym_bind))?;
let raw_sym_type =
u8::from_bytes(source).map_err(|_| SymbolParseError::MissingSymbolTypeError)?;
let sym_type = SymType::try_from(raw_sym_type)
.map_err(|_| SymbolParseError::InvalidSymbolTypeError(raw_sym_type))?;
let sh_idx = SectionIdx::from(
u16::from_bytes(source).map_err(|_| SymbolParseError::MissingSectionIndexError)?,
);
Ok(Self {
name_idx,
value_idx,
size,
sym_bind,
sym_type,
sh_idx,
})
}
pub fn write(&self, buf: &mut impl WritableBuffer) {
(usize::from(self.name_idx) as u32).to_bytes(buf);
u32::from(self.value_idx).to_bytes(buf);
self.size.to_bytes(buf);
buf.write(self.sym_bind as u8);
buf.write(self.sym_type as u8);
u16::from(self.sh_idx).to_bytes(buf);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ReldEntry {
pub section_index: SectionIdx,
pub instr_index: InstrIdx,
pub operand_index: OperandIndex,
pub symbol_index: SymbolIdx,
}
impl ReldEntry {
const RELD_ENTRY_SIZE: u32 = (std::mem::size_of::<u16>()
+ std::mem::size_of::<u32>()
+ std::mem::size_of::<u8>()
+ std::mem::size_of::<u32>()) as u32;
pub const fn new(
section_index: SectionIdx,
instr_index: InstrIdx,
operand_index: OperandIndex,
symbol_index: SymbolIdx,
) -> Self {
Self {
section_index,
instr_index,
operand_index,
symbol_index,
}
}
pub const fn size_bytes(&self) -> u32 {
Self::RELD_ENTRY_SIZE
}
pub fn parse(source: &mut BufferIterator) -> Result<Self, ReldEntryParseError> {
let section_index = SectionIdx::from(
u16::from_bytes(source).map_err(|_| ReldEntryParseError::MissingSectionIndexError)?,
);
let instr_index = InstrIdx::from(
u32::from_bytes(source)
.map_err(|_| ReldEntryParseError::MissingInstructionIndexError)?,
);
let raw_operand_index =
u8::from_bytes(source).map_err(|_| ReldEntryParseError::MissingOperandIndexError)?;
let operand_index = OperandIndex::try_from(raw_operand_index)
.map_err(|_| ReldEntryParseError::InvalidOperandIndexError(raw_operand_index))?;
let symbol_index = SymbolIdx::from(
u32::from_bytes(source).map_err(|_| ReldEntryParseError::MissingSymbolIndexError)?,
);
Ok(Self {
section_index,
instr_index,
operand_index,
symbol_index,
})
}
pub fn write(&self, buf: &mut impl WritableBuffer) {
u16::from(self.section_index).to_bytes(buf);
u32::from(self.instr_index).to_bytes(buf);
u8::from(self.operand_index).to_bytes(buf);
u32::from(self.symbol_index).to_bytes(buf);
}
}
#[cfg(test)]
mod tests {
use crate::ko::sections::{DataIdx, StringIdx};
use crate::ko::symbols::{KOSymbol, SymBind, SymType};
use crate::ko::SectionIdx;
use crate::BufferIterator;
#[test]
fn read_write_symbol() {
let mut buffer = Vec::new();
let symbol = KOSymbol::new(
StringIdx::from(23u32),
DataIdx::from(42u32),
45,
SymBind::Global,
SymType::Func,
SectionIdx::from(2u16),
);
symbol.write(&mut buffer);
let mut iter = BufferIterator::new(&buffer);
let read = KOSymbol::parse(&mut iter).unwrap();
assert_eq!(symbol, read);
}
}