fix signed fields
This commit is contained in:
parent
9e7f70444f
commit
b8199e678c
File diff suppressed because it is too large
Load Diff
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue