Skip to content

Commit 73395f8

Browse files
Fix x64 constant immediate size calculation failing for slightly more complex immediates and displacements, due to changes needed for #95
1 parent e7290dd commit 73395f8

File tree

2 files changed

+37
-14
lines changed

2 files changed

+37
-14
lines changed

plugin/src/arch/x64/compiler.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -753,31 +753,36 @@ fn sanitize_indirects_and_sizes(ctx: &Context, args: &mut [CleanArg]) -> Result<
753753

754754
// Tries to find the maximum size necessary to hold the result of an expression.
755755
fn derive_size(expr: &syn::Expr) -> Option<Size> {
756-
// strip any wrapping Group nodes due to delimiting
756+
// strip any wrapping Group or Paren nodes due to delimiting
757757
let mut inner = expr;
758-
while let syn::Expr::Group(syn::ExprGroup { expr, .. }) = inner {
759-
inner = expr;
758+
loop {
759+
inner = match inner {
760+
syn::Expr::Group(syn::ExprGroup { expr, ..}) => expr,
761+
syn::Expr::Paren(syn::ExprParen { expr, .. }) => expr,
762+
_ => break
763+
}
760764
}
761765

762766
match inner {
763767
syn::Expr::Lit(syn::ExprLit { ref lit, .. } ) => match lit {
764768
syn::Lit::Byte(_) => Some(Size::BYTE),
765-
syn::Lit::Int(i) => match i.base10_parse::<u32>() {
766-
Ok(x) if x < 0x80 => Some(Size::BYTE),
767-
Ok(x) if x < 0x8000 => Some(Size::B_2),
768-
Ok(x) if x < 0x8000_0000 => Some(Size::B_4),
769-
_ => Some(Size::B_8),
769+
syn::Lit::Int(i) => match i.base10_parse::<i32>() {
770+
Err(_) => Some(Size::B_8),
771+
Ok(x) if x > 0x7FFF || x < -0x8000 => Some(Size::B_4),
772+
Ok(x) if x > 0x7F || x < -0x80 => Some(Size::B_2),
773+
Ok(_) => Some(Size::BYTE),
770774
},
771775
_ => None
772776
},
773777
syn::Expr::Unary(syn::ExprUnary { op: syn::UnOp::Neg(_), ref expr, .. } ) => match &**expr {
774778
syn::Expr::Lit(syn::ExprLit { ref lit, .. } ) => match lit {
775779
syn::Lit::Byte(_) => Some(Size::BYTE),
776-
syn::Lit::Int(i) => match i.base10_parse::<u32>() {
777-
Ok(x) if x <= 0x80 => Some(Size::BYTE),
778-
Ok(x) if x <= 0x8000 => Some(Size::B_2),
779-
Ok(x) if x <= 0x8000_0000 => Some(Size::B_4),
780-
_ => Some(Size::B_8),
780+
syn::Lit::Int(i) => match i.base10_parse::<i64>() {
781+
Err(_) => Some(Size::B_8),
782+
Ok(x) if x > 0x8000_0000 || x < -0x7FFF_FFFF => Some(Size::B_4),
783+
Ok(x) if x > 0x8000 || x < -0x7FFF => Some(Size::B_4),
784+
Ok(x) if x > 0x80 || x < -0x7F => Some(Size::B_2),
785+
Ok(_) => Some(Size::BYTE),
781786
},
782787
_ => None
783788
},

testing/tests/bugreports.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ fn bugreport_4() {
8282
// Precedence issue around typemapped operands due to proc_macro2::Delimiter::None being broken.
8383
#[test]
8484
fn bugreport_5() {
85-
#![allow(unused_parens)]
8685
#[allow(dead_code)]
8786
struct Test {
8887
a: u32,
@@ -100,3 +99,22 @@ fn bugreport_5() {
10099
let hex: String = hex.join(", ");
101100
assert_eq!(hex, "0x48, 0x89, 0x83, 0x1C, 0x00, 0x00, 0x00", "bugreport_5");
102101
}
102+
103+
// Bad sizing of constant immediates in x64 mode
104+
#[test]
105+
fn bugreport_6() {
106+
let mut ops = dynasmrt::x64::Assembler::new().unwrap();
107+
dynasm!(ops
108+
; .arch x64
109+
; lea rax, [rbx + 1]
110+
; lea rax, [rbx + 0x80]
111+
; lea rax, [rbx - 1]
112+
; lea rax, [rbx + -1]
113+
; lea rax, [rbx - 0x81]
114+
);
115+
116+
let buf = ops.finalize().unwrap();
117+
let hex: Vec<String> = buf.iter().map(|x| format!("0x{:02X}", *x)).collect();
118+
let hex: String = hex.join(", ");
119+
assert_eq!(hex, "0x48, 0x8D, 0x43, 0x01, 0x48, 0x8D, 0x83, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x43, 0xFF, 0x48, 0x8D, 0x43, 0xFF, 0x48, 0x8D, 0x83, 0x7F, 0xFF, 0xFF, 0xFF", "bugreport_6");
120+
}

0 commit comments

Comments
 (0)