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 { pub fn bits(&self, range: Range<usize>) -> u32 {
bits(self.code, range) 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. /// A simplified PowerPC 750CL instruction.

View File

@ -85,7 +85,7 @@ fn test_ins_andi_() {
fn test_ins_andis_() { fn test_ins_andis_() {
assert_asm!(0x77c802ff, "andis. r8, r30, 0x2ff"); assert_asm!(0x77c802ff, "andis. r8, r30, 0x2ff");
} }
/*
#[test] #[test]
fn test_ins_b() { fn test_ins_b() {
assert_asm!(0x48000000, "b 0x0"); assert_asm!(0x48000000, "b 0x0");
@ -96,6 +96,7 @@ fn test_ins_b() {
assert_asm!(0x4BDC1A59, "bl -0x23e5a8"); assert_asm!(0x4BDC1A59, "bl -0x23e5a8");
} }
/*
#[test] #[test]
fn test_ins_bc() { fn test_ins_bc() {
assert_asm!(0x40800008, "bge 0x8"); 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" repository = "https://github.com/terorie/ppc750cl"
[dependencies] [dependencies]
clap = "2.33" clap = "3"
dol = { version = "0.1.0", path = "../dol" } dol = { version = "0.1.0", path = "../dol" }
itertools = "0.10" itertools = "0.10"
parse_int = "0.5" parse_int = "0.6"
petgraph = "0.6" petgraph = "0.6"
ppc750cl = { version = "0.1.1", path = "../disasm" } ppc750cl = { version = "0.1.1", path = "../disasm" }

View File

@ -55,14 +55,17 @@ impl<'a> BasicBlock<'a> {
Opcode::Addis => { Opcode::Addis => {
if ins.a() == 0 { if ins.a() == 0 {
// lis // lis
defs.insert(ins.d(), ins.uimm()); defs.insert(ins.d(), ins.field_uimm() as u16);
} else { } else {
defs.remove(&ins.d()); defs.remove(&ins.d());
} }
} }
Opcode::Addi => { Opcode::Addi => {
if let Some(hi) = defs.get(&ins.a()) { 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()); defs.remove(&ins.d());
} }

View File

@ -33,7 +33,7 @@ impl BasicSlices {
continue; continue;
} }
// We encountered some kind of control flow instruction. // 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. // There's a possibility that branch can be taken.
// Branch destinations are always the first instruction of a block. // Branch destinations are always the first instruction of a block.
// Thus, we also found the end of another block. // Thus, we also found the end of another block.
@ -58,5 +58,5 @@ fn is_conditional_branch(ins: &Ins) -> bool {
_ => return false, _ => return false,
}; };
// Check whether bits "branch always". // 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, signed: bool,
split: bool, split: bool,
arg: Option<String>, arg: Option<String>,
shift_left: u8,
} }
impl Field { impl Field {
fn variant_identifier(&self) -> Option<TokenTree> { fn variant_identifier(&self) -> Option<TokenTree> {
self.identifier("")
}
fn identifier(&self, prefix: &str) -> Option<TokenTree> {
if self.name.strip_suffix(".nz").is_none() { if self.name.strip_suffix(".nz").is_none() {
Some(to_rust_ident(&self.name)) Some(to_rust_ident(prefix, &self.name))
} else { } else {
None None
} }
} }
fn express_value(&self, code: TokenStream) -> TokenStream { fn express_value(&self, code: TokenStream) -> TokenStream {
let mut val = quote!(#code);
let shift = 32 - self.bits.0.end; let shift = 32 - self.bits.0.end;
let mask = (1u32 << self.bits.0.len()) - 1; if shift > 0 {
let mask = LitInt::new(&format!("0x{:x}", mask), Span::call_site()); val = quote!((#val >> #shift));
quote! {
((#code >> #shift) & #mask)
} }
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 { fn express_value_self(&self) -> TokenStream {
@ -153,6 +178,27 @@ impl Field {
fn construct_variant_self(&self) -> TokenStream { fn construct_variant_self(&self) -> TokenStream {
self.construct_variant(quote!(self.code)) 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)] #[derive(Deserialize, Default)]
@ -475,9 +521,15 @@ impl Isa {
let use_match_arms = token_stream!(use_match_arms); let use_match_arms = token_stream!(use_match_arms);
let modifier_match_arms = token_stream!(modifier_match_arms); let modifier_match_arms = token_stream!(modifier_match_arms);
let simplified_ins_match_arms = token_stream!(simplified_ins_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. // Generate final fields function.
let ins_impl = quote! { let ins_impl = quote! {
#[allow(clippy::all)] #[allow(clippy::all, unused_mut)]
impl Ins { impl Ins {
pub(crate) fn _fields(&self) -> Vec<Field> { pub(crate) fn _fields(&self) -> Vec<Field> {
match self.op { match self.op {
@ -486,7 +538,6 @@ impl Isa {
} }
} }
#[allow(unused_mut)]
pub(crate) fn _defs(&self) -> Vec<Field> { pub(crate) fn _defs(&self) -> Vec<Field> {
match self.op { match self.op {
Opcode::Illegal => vec![], Opcode::Illegal => vec![],
@ -494,7 +545,6 @@ impl Isa {
} }
} }
#[allow(unused_mut)]
pub(crate) fn _uses(&self) -> Vec<Field> { pub(crate) fn _uses(&self) -> Vec<Field> {
match self.op { match self.op {
Opcode::Illegal => vec![], Opcode::Illegal => vec![],
@ -502,7 +552,6 @@ impl Isa {
} }
} }
#[allow(unused_mut)]
pub(crate) fn _modifiers(&self) -> Modifiers { pub(crate) fn _modifiers(&self) -> Modifiers {
match self.op { match self.op {
Opcode::Illegal => Modifiers::default(), Opcode::Illegal => Modifiers::default(),
@ -518,14 +567,21 @@ impl Isa {
SimplifiedIns::basic_form(self) SimplifiedIns::basic_form(self)
} }
} }
#[allow(clippy::all, non_snake_case)]
impl Ins {
#field_accessors
}
}; };
Ok(ins_impl) Ok(ins_impl)
} }
} }
/// Converts the given key into an identifier. /// Converts the given key into an identifier.
fn to_rust_ident(key: &str) -> TokenTree { fn to_rust_ident(prefix: &str, key: &str) -> TokenTree {
TokenTree::Ident(Ident::new(&key.replace('.', "_"), Span::call_site())) TokenTree::Ident(Ident::new(
&(prefix.to_owned() + &key.replace('.', "_")),
Span::call_site(),
))
} }
/// Converts the given key into an enum variant key. /// Converts the given key into an enum variant key.

View File

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