fix signed fields

This commit is contained in:
Richard Patel 2022-04-07 04:07:15 +02:00
parent 9e7f70444f
commit b8199e678c
8 changed files with 486 additions and 115 deletions

File diff suppressed because it is too large Load Diff

View File

@ -313,6 +313,26 @@ impl Ins {
pub fn bits(&self, range: Range<usize>) -> u32 {
bits(self.code, range)
}
/*
pub fn branch_offset(&self) -> Option<i32> {
match self.op {
Opcode::B => Some(self.li()),
Opcode::Bc | Opcode::Bcctr | Opcode::Bclr => Some(self.field_BD() as i32),
_ => None,
}
}
pub fn branch_dest(&self) -> Option<u32> {
self.branch_offset().and_then(|offset| {
if offset < 0 {
self.addr.checked_sub((-offset) as u32)
} else {
self.addr.checked_add(offset as u32)
}
})
}
*/
}
/// A simplified PowerPC 750CL instruction.

View File

@ -85,7 +85,7 @@ fn test_ins_andi_() {
fn test_ins_andis_() {
assert_asm!(0x77c802ff, "andis. r8, r30, 0x2ff");
}
/*
#[test]
fn test_ins_b() {
assert_asm!(0x48000000, "b 0x0");
@ -96,6 +96,7 @@ fn test_ins_b() {
assert_asm!(0x4BDC1A59, "bl -0x23e5a8");
}
/*
#[test]
fn test_ins_bc() {
assert_asm!(0x40800008, "bge 0x8");

View File

@ -8,9 +8,9 @@ description = "Control flow graph analysis for PowerPC 750CL"
repository = "https://github.com/terorie/ppc750cl"
[dependencies]
clap = "2.33"
clap = "3"
dol = { version = "0.1.0", path = "../dol" }
itertools = "0.10"
parse_int = "0.5"
parse_int = "0.6"
petgraph = "0.6"
ppc750cl = { version = "0.1.1", path = "../disasm" }

View File

@ -55,14 +55,17 @@ impl<'a> BasicBlock<'a> {
Opcode::Addis => {
if ins.a() == 0 {
// lis
defs.insert(ins.d(), ins.uimm());
defs.insert(ins.d(), ins.field_uimm() as u16);
} else {
defs.remove(&ins.d());
}
}
Opcode::Addi => {
if let Some(hi) = defs.get(&ins.a()) {
data_refs.insert(ins.addr / 4, ((*hi as u32) << 16) + (ins.uimm() as u32));
data_refs.insert(
ins.addr / 4,
((*hi as u32) << 16) + (ins.field_uimm() as u32),
);
}
defs.remove(&ins.d());
}

View File

@ -33,7 +33,7 @@ impl BasicSlices {
continue;
}
// We encountered some kind of control flow instruction.
if ins.code != Opcode::BLR {
if ins.field_BO() == 20 && ins.field_BI() == 0 {
// There's a possibility that branch can be taken.
// Branch destinations are always the first instruction of a block.
// Thus, we also found the end of another block.
@ -58,5 +58,5 @@ fn is_conditional_branch(ins: &Ins) -> bool {
_ => return false,
};
// Check whether bits "branch always".
ins.bo() & 0b10100 != 0b10100
ins.field_BO() & 0b10100 != 0b10100
}

View File

@ -97,24 +97,49 @@ pub(crate) struct Field {
signed: bool,
split: bool,
arg: Option<String>,
shift_left: u8,
}
impl Field {
fn variant_identifier(&self) -> Option<TokenTree> {
self.identifier("")
}
fn identifier(&self, prefix: &str) -> Option<TokenTree> {
if self.name.strip_suffix(".nz").is_none() {
Some(to_rust_ident(&self.name))
Some(to_rust_ident(prefix, &self.name))
} else {
None
}
}
fn express_value(&self, code: TokenStream) -> TokenStream {
let mut val = quote!(#code);
let shift = 32 - self.bits.0.end;
let mask = (1u32 << self.bits.0.len()) - 1;
let mask = LitInt::new(&format!("0x{:x}", mask), Span::call_site());
quote! {
((#code >> #shift) & #mask)
if shift > 0 {
val = quote!((#val >> #shift));
}
let mask = (1u32 << self.bits.0.len()) - 1;
if mask != 0xFFFF_FFFF {
let mask = LitInt::new(&format!("0x{:x}", mask), Span::call_site());
val = quote!((#val & #mask));
}
// https://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
if self.signed {
let mask2 = 1u32 << (self.bits.0.len() - 1);
let mask2 = LitInt::new(&format!("0x{:x}", mask2), Span::call_site());
val = quote!(((#val ^ #mask2).wrapping_sub(#mask2)))
}
let val_shift = self.shift_left;
if val_shift > 0 {
val = quote!((#val << #val_shift));
}
val
}
fn express_value_self(&self) -> TokenStream {
@ -153,6 +178,27 @@ impl Field {
fn construct_variant_self(&self) -> TokenStream {
self.construct_variant(quote!(self.code))
}
fn construct_accessor(&self) -> TokenStream {
let field_variant = match self.identifier("field_") {
Some(v) => v,
None => return TokenStream::new(),
};
if self.arg.is_none() {
return TokenStream::new();
}
let value = self.express_value_self();
let ret_type = if self.signed {
quote!(isize)
} else {
quote!(usize)
};
quote! {
pub fn #field_variant(&self) -> #ret_type {
#value as _
}
}
}
}
#[derive(Deserialize, Default)]
@ -475,9 +521,15 @@ impl Isa {
let use_match_arms = token_stream!(use_match_arms);
let modifier_match_arms = token_stream!(modifier_match_arms);
let simplified_ins_match_arms = token_stream!(simplified_ins_match_arms);
let field_accessors = self
.fields
.iter()
.map(|field| field.construct_accessor())
.collect::<Vec<_>>();
let field_accessors = token_stream!(field_accessors);
// Generate final fields function.
let ins_impl = quote! {
#[allow(clippy::all)]
#[allow(clippy::all, unused_mut)]
impl Ins {
pub(crate) fn _fields(&self) -> Vec<Field> {
match self.op {
@ -486,7 +538,6 @@ impl Isa {
}
}
#[allow(unused_mut)]
pub(crate) fn _defs(&self) -> Vec<Field> {
match self.op {
Opcode::Illegal => vec![],
@ -494,7 +545,6 @@ impl Isa {
}
}
#[allow(unused_mut)]
pub(crate) fn _uses(&self) -> Vec<Field> {
match self.op {
Opcode::Illegal => vec![],
@ -502,7 +552,6 @@ impl Isa {
}
}
#[allow(unused_mut)]
pub(crate) fn _modifiers(&self) -> Modifiers {
match self.op {
Opcode::Illegal => Modifiers::default(),
@ -518,14 +567,21 @@ impl Isa {
SimplifiedIns::basic_form(self)
}
}
#[allow(clippy::all, non_snake_case)]
impl Ins {
#field_accessors
}
};
Ok(ins_impl)
}
}
/// Converts the given key into an identifier.
fn to_rust_ident(key: &str) -> TokenTree {
TokenTree::Ident(Ident::new(&key.replace('.', "_"), Span::call_site()))
fn to_rust_ident(prefix: &str, key: &str) -> TokenTree {
TokenTree::Ident(Ident::new(
&(prefix.to_owned() + &key.replace('.', "_")),
Span::call_site(),
))
}
/// Converts the given key into an enum variant key.

View File

@ -22,9 +22,11 @@ fields:
arg: BranchDest
bits: 16..30
shift_left: 2
signed: true
- name: LI
arg: BranchDest
bits: 6..30
signed: true
shift_left: 2
# Shift/rotate type fields
- name: SH