use std::io::{Read, Write};
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Address {
Abs(u128),
Disp(i64),
Symbol { name: String, disp: i64 },
PltSym { name: String },
}
impl core::fmt::Display for Address {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Abs(n) => f.write_fmt(format_args!("{:#x}", n)),
Self::Disp(n) => f.write_fmt(format_args!("{:+}", n)),
Self::Symbol { name, disp: 0 } => f.write_str(name),
Self::Symbol { name, disp } => f.write_fmt(format_args!("{}{:+}", name, disp)),
Self::PltSym { name } => f.write_fmt(format_args!("{}@plt", name)),
}
}
}
pub trait InsnRead: Read {
fn read_addr(&mut self, size: usize, rel: bool) -> std::io::Result<Address>;
fn read_reloc(
&mut self,
size: usize,
rel: bool,
offset: Option<isize>,
) -> std::io::Result<Option<Address>>;
}
impl<R: InsnRead + ?Sized> InsnRead for &mut R {
fn read_addr(&mut self, size: usize, rel: bool) -> std::io::Result<Address> {
<R as InsnRead>::read_addr(self, size, rel)
}
fn read_reloc(
&mut self,
size: usize,
rel: bool,
offset: Option<isize>,
) -> std::io::Result<Option<Address>> {
<R as InsnRead>::read_reloc(self, size, rel, offset)
}
}
impl<R: InsnRead + ?Sized> InsnRead for Box<R> {
fn read_addr(&mut self, size: usize, rel: bool) -> std::io::Result<Address> {
<R as InsnRead>::read_addr(self, size, rel)
}
fn read_reloc(
&mut self,
size: usize,
rel: bool,
offset: Option<isize>,
) -> std::io::Result<Option<Address>> {
<R as InsnRead>::read_reloc(self, size, rel, offset)
}
}
pub fn default_write_zeroes<W: Write>(mut out: W, mut count: usize) -> std::io::Result<()> {
let val: [u8; 1024] = [0; 1024];
while count >= 1024 {
out.write_all(&val)?;
count -= 1024;
}
out.write_all(&val[..count])
}
pub trait InsnWrite: Write {
fn write_addr(&mut self, size: usize, addr: Address, rel: bool) -> std::io::Result<()>;
fn write_reloc(&mut self, reloc: Reloc) -> std::io::Result<()>;
fn offset(&self) -> usize;
fn write_zeroes(&mut self, count: usize) -> std::io::Result<()> {
default_write_zeroes(self, count)
}
}
impl<W: InsnWrite + ?Sized> InsnWrite for &mut W {
fn write_addr(&mut self, size: usize, addr: Address, rel: bool) -> std::io::Result<()> {
<W as InsnWrite>::write_addr(self, size, addr, rel)
}
fn offset(&self) -> usize {
<W as InsnWrite>::offset(self)
}
fn write_reloc(&mut self, reloc: Reloc) -> std::io::Result<()> {
<W as InsnWrite>::write_reloc(self, reloc)
}
fn write_zeroes(&mut self, count: usize) -> std::io::Result<()> {
<W as InsnWrite>::write_zeroes(self, count)
}
}
impl<W: InsnWrite + ?Sized> InsnWrite for Box<W> {
fn write_addr(&mut self, size: usize, addr: Address, rel: bool) -> std::io::Result<()> {
<W as InsnWrite>::write_addr(self, size, addr, rel)
}
fn offset(&self) -> usize {
<W as InsnWrite>::offset(self)
}
fn write_reloc(&mut self, reloc: Reloc) -> std::io::Result<()> {
<W as InsnWrite>::write_reloc(self, reloc)
}
fn write_zeroes(&mut self, count: usize) -> std::io::Result<()> {
<W as InsnWrite>::write_zeroes(self, count)
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum RelocCode {
None,
Abs { addr_width: usize },
BaseRel { addr_width: usize },
Rel { addr_width: usize },
AbsShifted { addr_width: usize, shift: usize },
RelShifted { addr_width: usize, shift: usize },
Got { addr_width: usize },
RelGot { addr_wdith: usize },
Plt { addr_width: usize },
RelPlt { addr_width: usize },
DynSymEntry { width: usize },
W65Direct,
W65RelaxJsl,
W65RelaxJml,
W65RelaxBrl,
W65RelaxDirect,
W65RelaxAbs,
W65RelaxJmp,
CleverShort,
CleverShortPcrel,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Reloc {
pub code: RelocCode,
pub symbol: String,
pub addend: Option<i64>,
pub offset: u64,
}