Skip to content

Commit

Permalink
Merge pull request #511 from icedland/fix498
Browse files Browse the repository at this point in the history
Fix block encoder and 32-bit branches from 0 -> FFFF_FF00
  • Loading branch information
wtfsck authored Jan 16, 2024
2 parents 9a2c094 + 91c96e1 commit 3ef209c
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 54 deletions.
9 changes: 9 additions & 0 deletions src/csharp/Intel/Iced/Intel/BlockEncoderInternal/Instr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,15 @@ protected static long CorrectDiff(bool inBlock, long diff, ulong gained) {
else
return diff;
}

protected static long ConvertDiffToBitnessDiff(int bitness, long diff) {
Debug.Assert(bitness == 16 || bitness == 32 || bitness == 64);
return bitness switch {
16 => (short)diff,
32 => (int)diff,
_ => diff,
};
}
}
}
#endif
18 changes: 12 additions & 6 deletions src/csharp/Intel/Iced/Intel/BlockEncoderInternal/JccInstr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Iced.Intel.BlockEncoderInternal {
/// Jcc instruction
/// </summary>
sealed class JccInstr : Instr {
readonly byte bitness;
Instruction instruction;
TargetInstr targetInstr;
BlockData? pointerData;
Expand Down Expand Up @@ -41,6 +42,7 @@ enum InstrKind : byte {

public JccInstr(BlockEncoder blockEncoder, Block block, in Instruction instruction)
: base(block, instruction.IP) {
bitness = (byte)blockEncoder.Bitness;
this.instruction = instruction;
instrKind = InstrKind.Uninitialized;
longInstructionSize64 = (byte)GetLongInstructionSize64(instruction);
Expand Down Expand Up @@ -87,7 +89,7 @@ bool TryOptimize(ulong gained) {
var targetAddress = targetInstr.GetAddress();
var nextRip = IP + shortInstructionSize;
long diff = (long)(targetAddress - nextRip);
diff = CorrectDiff(targetInstr.IsInBlock(Block), diff, gained);
diff = ConvertDiffToBitnessDiff(bitness, CorrectDiff(targetInstr.IsInBlock(Block), diff, gained));
if (sbyte.MinValue <= diff && diff <= sbyte.MaxValue) {
if (pointerData is not null)
pointerData.IsValid = false;
Expand All @@ -97,11 +99,15 @@ bool TryOptimize(ulong gained) {
return true;
}

targetAddress = targetInstr.GetAddress();
nextRip = IP + nearInstructionSize;
diff = (long)(targetAddress - nextRip);
diff = CorrectDiff(targetInstr.IsInBlock(Block), diff, gained);
bool useNear = int.MinValue <= diff && diff <= int.MaxValue;
// If it's in the same block, we assume the target is at most 2GB away.
bool useNear = bitness != 64 || targetInstr.IsInBlock(Block);
if (!useNear) {
targetAddress = targetInstr.GetAddress();
nextRip = IP + nearInstructionSize;
diff = (long)(targetAddress - nextRip);
diff = ConvertDiffToBitnessDiff(bitness, CorrectDiff(targetInstr.IsInBlock(Block), diff, gained));
useNear = int.MinValue <= diff && diff <= int.MaxValue;
}
if (useNear) {
if (pointerData is not null)
pointerData.IsValid = false;
Expand Down
18 changes: 12 additions & 6 deletions src/csharp/Intel/Iced/Intel/BlockEncoderInternal/JmpInstr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Iced.Intel.BlockEncoderInternal {
/// Jmp instruction
/// </summary>
sealed class JmpInstr : Instr {
readonly byte bitness;
Instruction instruction;
TargetInstr targetInstr;
BlockData? pointerData;
Expand All @@ -27,6 +28,7 @@ enum InstrKind : byte {

public JmpInstr(BlockEncoder blockEncoder, Block block, in Instruction instruction)
: base(block, instruction.IP) {
bitness = (byte)blockEncoder.Bitness;
this.instruction = instruction;
instrKind = InstrKind.Uninitialized;

Expand Down Expand Up @@ -72,7 +74,7 @@ bool TryOptimize(ulong gained) {
var targetAddress = targetInstr.GetAddress();
var nextRip = IP + shortInstructionSize;
long diff = (long)(targetAddress - nextRip);
diff = CorrectDiff(targetInstr.IsInBlock(Block), diff, gained);
diff = ConvertDiffToBitnessDiff(bitness, CorrectDiff(targetInstr.IsInBlock(Block), diff, gained));
if (sbyte.MinValue <= diff && diff <= sbyte.MaxValue) {
if (pointerData is not null)
pointerData.IsValid = false;
Expand All @@ -82,11 +84,15 @@ bool TryOptimize(ulong gained) {
return true;
}

targetAddress = targetInstr.GetAddress();
nextRip = IP + nearInstructionSize;
diff = (long)(targetAddress - nextRip);
diff = CorrectDiff(targetInstr.IsInBlock(Block), diff, gained);
bool useNear = int.MinValue <= diff && diff <= int.MaxValue;
// If it's in the same block, we assume the target is at most 2GB away.
bool useNear = bitness != 64 || targetInstr.IsInBlock(Block);
if (!useNear) {
targetAddress = targetInstr.GetAddress();
nextRip = IP + nearInstructionSize;
diff = (long)(targetAddress - nextRip);
diff = ConvertDiffToBitnessDiff(bitness, CorrectDiff(targetInstr.IsInBlock(Block), diff, gained));
useNear = int.MinValue <= diff && diff <= int.MaxValue;
}
if (useNear) {
if (pointerData is not null)
pointerData.IsValid = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Iced.Intel.BlockEncoderInternal {
/// Simple branch instruction that only has one code value, eg. loopcc, jrcxz
/// </summary>
sealed class SimpleBranchInstr : Instr {
readonly byte bitness;
Instruction instruction;
TargetInstr targetInstr;
BlockData? pointerData;
Expand All @@ -30,6 +31,7 @@ enum InstrKind : byte {

public SimpleBranchInstr(BlockEncoder blockEncoder, Block block, in Instruction instruction)
: base(block, instruction.IP) {
bitness = (byte)blockEncoder.Bitness;
this.instruction = instruction;
instrKind = InstrKind.Uninitialized;

Expand Down Expand Up @@ -188,7 +190,7 @@ bool TryOptimize(ulong gained) {
var targetAddress = targetInstr.GetAddress();
var nextRip = IP + shortInstructionSize;
long diff = (long)(targetAddress - nextRip);
diff = CorrectDiff(targetInstr.IsInBlock(Block), diff, gained);
diff = ConvertDiffToBitnessDiff(bitness, CorrectDiff(targetInstr.IsInBlock(Block), diff, gained));
if (sbyte.MinValue <= diff && diff <= sbyte.MaxValue) {
if (pointerData is not null)
pointerData.IsValid = false;
Expand All @@ -198,11 +200,15 @@ bool TryOptimize(ulong gained) {
return true;
}

targetAddress = targetInstr.GetAddress();
nextRip = IP + nearInstructionSize;
diff = (long)(targetAddress - nextRip);
diff = CorrectDiff(targetInstr.IsInBlock(Block), diff, gained);
bool useNear = int.MinValue <= diff && diff <= int.MaxValue;
// If it's in the same block, we assume the target is at most 2GB away.
bool useNear = bitness != 64 || targetInstr.IsInBlock(Block);
if (!useNear) {
targetAddress = targetInstr.GetAddress();
nextRip = IP + nearInstructionSize;
diff = (long)(targetAddress - nextRip);
diff = ConvertDiffToBitnessDiff(bitness, CorrectDiff(targetInstr.IsInBlock(Block), diff, gained));
useNear = int.MinValue <= diff && diff <= int.MaxValue;
}
if (useNear) {
if (pointerData is not null)
pointerData.IsValid = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,4 +275,15 @@ protected static long correctDiff(boolean inBlock, long diff, long gained) {
else
return diff;
}

protected static long convertDiffToBitnessDiff(int bitness, long diff) {
switch (bitness) {
case 16:
return (short)diff;
case 32:
return (int)diff;
default:
return diff;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.github.icedland.iced.x86.internal.IcedConstants;

final class JccInstr extends Instr {
private final byte bitness;
private Instruction instruction;
private TargetInstr targetInstr;
private BlockData pointerData;
Expand Down Expand Up @@ -39,6 +40,7 @@ private static final class InstrKind {

JccInstr(BlockEncoder blockEncoder, Block block, Instruction instruction) {
super(block, instruction.getIP());
this.bitness = (byte)blockEncoder.getBitness();
this.instruction = instruction;
instrKind = InstrKind.UNINITIALIZED;
longInstructionSize64 = (byte)getLongInstructionSize64(instruction);
Expand Down Expand Up @@ -91,7 +93,7 @@ private boolean tryOptimize(long gained) {
long targetAddress = targetInstr.getAddress();
long nextRip = ip + shortInstructionSize;
long diff = targetAddress - nextRip;
diff = correctDiff(targetInstr.isInBlock(block), diff, gained);
diff = convertDiffToBitnessDiff(bitness, correctDiff(targetInstr.isInBlock(block), diff, gained));
if (-0x80 <= diff && diff <= 0x7F) {
if (pointerData != null)
pointerData.isValid = false;
Expand All @@ -101,11 +103,15 @@ private boolean tryOptimize(long gained) {
return true;
}

targetAddress = targetInstr.getAddress();
nextRip = ip + nearInstructionSize;
diff = targetAddress - nextRip;
diff = correctDiff(targetInstr.isInBlock(block), diff, gained);
boolean useNear = -0x8000_0000 <= diff && diff <= 0x7FFF_FFFF;
// If it's in the same block, we assume the target is at most 2GB away.
boolean useNear = bitness != 64 || targetInstr.isInBlock(block);
if (!useNear) {
targetAddress = targetInstr.getAddress();
nextRip = ip + nearInstructionSize;
diff = targetAddress - nextRip;
diff = convertDiffToBitnessDiff(bitness, correctDiff(targetInstr.isInBlock(block), diff, gained));
useNear = -0x8000_0000 <= diff && diff <= 0x7FFF_FFFF;
}
if (useNear) {
if (pointerData != null)
pointerData.isValid = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.github.icedland.iced.x86.internal.IcedConstants;

final class JmpInstr extends Instr {
private final byte bitness;
private Instruction instruction;
private TargetInstr targetInstr;
private BlockData pointerData;
Expand All @@ -26,6 +27,7 @@ private static final class InstrKind {

public JmpInstr(BlockEncoder blockEncoder, Block block, Instruction instruction) {
super(block, instruction.getIP());
this.bitness = (byte)blockEncoder.getBitness();
this.instruction = instruction;
instrKind = InstrKind.UNINITIALIZED;

Expand Down Expand Up @@ -77,7 +79,7 @@ private boolean tryOptimize(long gained) {
long targetAddress = targetInstr.getAddress();
long nextRip = ip + shortInstructionSize;
long diff = targetAddress - nextRip;
diff = correctDiff(targetInstr.isInBlock(block), diff, gained);
diff = convertDiffToBitnessDiff(bitness, correctDiff(targetInstr.isInBlock(block), diff, gained));
if (-0x80 <= diff && diff <= 0x7F) {
if (pointerData != null)
pointerData.isValid = false;
Expand All @@ -87,11 +89,15 @@ private boolean tryOptimize(long gained) {
return true;
}

targetAddress = targetInstr.getAddress();
nextRip = ip + nearInstructionSize;
diff = targetAddress - nextRip;
diff = correctDiff(targetInstr.isInBlock(block), diff, gained);
boolean useNear = -0x8000_0000 <= diff && diff <= 0x7FFF_FFFF;
// If it's in the same block, we assume the target is at most 2GB away.
boolean useNear = bitness != 64 || targetInstr.isInBlock(block);
if (!useNear) {
targetAddress = targetInstr.getAddress();
nextRip = ip + nearInstructionSize;
diff = targetAddress - nextRip;
diff = convertDiffToBitnessDiff(bitness, correctDiff(targetInstr.isInBlock(block), diff, gained));
useNear = -0x8000_0000 <= diff && diff <= 0x7FFF_FFFF;
}
if (useNear) {
if (pointerData != null)
pointerData.isValid = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.github.icedland.iced.x86.internal.IcedConstants;

final class SimpleBranchInstr extends Instr {
private final byte bitness;
private Instruction instruction;
private TargetInstr targetInstr;
private BlockData pointerData;
Expand All @@ -30,6 +31,7 @@ private static final class InstrKind {

public SimpleBranchInstr(BlockEncoder blockEncoder, Block block, Instruction instruction) {
super(block, instruction.getIP());
this.bitness = (byte)blockEncoder.getBitness();
this.instruction = instruction;
instrKind = InstrKind.UNINITIALIZED;

Expand Down Expand Up @@ -210,7 +212,7 @@ private boolean tryOptimize(long gained) {
long targetAddress = targetInstr.getAddress();
long nextRip = ip + shortInstructionSize;
long diff = targetAddress - nextRip;
diff = correctDiff(targetInstr.isInBlock(block), diff, gained);
diff = convertDiffToBitnessDiff(bitness, correctDiff(targetInstr.isInBlock(block), diff, gained));
if (-0x80 <= diff && diff <= 0x7F) {
if (pointerData != null)
pointerData.isValid = false;
Expand All @@ -220,11 +222,15 @@ private boolean tryOptimize(long gained) {
return true;
}

targetAddress = targetInstr.getAddress();
nextRip = ip + nearInstructionSize;
diff = targetAddress - nextRip;
diff = correctDiff(targetInstr.isInBlock(block), diff, gained);
boolean useNear = -0x8000_0000 <= diff && diff <= 0x7FFF_FFFF;
// If it's in the same block, we assume the target is at most 2GB away.
boolean useNear = bitness != 64 || targetInstr.isInBlock(block);
if (!useNear) {
targetAddress = targetInstr.getAddress();
nextRip = ip + nearInstructionSize;
diff = targetAddress - nextRip;
diff = convertDiffToBitnessDiff(bitness, correctDiff(targetInstr.isInBlock(block), diff, gained));
useNear = -0x8000_0000 <= diff && diff <= 0x7FFF_FFFF;
}
if (useNear) {
if (pointerData != null)
pointerData.isValid = false;
Expand Down
18 changes: 12 additions & 6 deletions src/rust/iced-x86/src/block_enc/instr/jcc_instr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum InstrKind {
}

pub(super) struct JccInstr {
bitness: u8,
instruction: Instruction,
target_instr: TargetInstr,
pointer_data: Option<Rc<RefCell<BlockData>>>,
Expand Down Expand Up @@ -76,6 +77,7 @@ impl JccInstr {
} as u32;
}
Self {
bitness: block_encoder.bitness() as u8,
instruction: *instruction,
target_instr: TargetInstr::default(),
pointer_data: None,
Expand All @@ -95,7 +97,7 @@ impl JccInstr {
let mut target_address = self.target_instr.address(ctx);
let mut next_rip = ctx.ip.wrapping_add(self.short_instruction_size as u64);
let mut diff = target_address.wrapping_sub(next_rip) as i64;
diff = correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained);
diff = InstrUtils::convert_diff_to_bitness_diff(self.bitness, correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained));
if i8::MIN as i64 <= diff && diff <= i8::MAX as i64 {
if let Some(ref pointer_data) = self.pointer_data {
pointer_data.borrow_mut().is_valid = false;
Expand All @@ -106,11 +108,15 @@ impl JccInstr {
return true;
}

target_address = self.target_instr.address(ctx);
next_rip = ctx.ip.wrapping_add(self.near_instruction_size as u64);
diff = target_address.wrapping_sub(next_rip) as i64;
diff = correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained);
let use_near = i32::MIN as i64 <= diff && diff <= i32::MAX as i64;
// If it's in the same block, we assume the target is at most 2GB away.
let mut use_near = self.bitness != 64 || self.target_instr.is_in_block(ctx.block);
if !use_near {
target_address = self.target_instr.address(ctx);
next_rip = ctx.ip.wrapping_add(self.near_instruction_size as u64);
diff = target_address.wrapping_sub(next_rip) as i64;
diff = InstrUtils::convert_diff_to_bitness_diff(self.bitness, correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained));
use_near = i32::MIN as i64 <= diff && diff <= i32::MAX as i64;
}
if use_near {
if let Some(ref pointer_data) = self.pointer_data {
pointer_data.borrow_mut().is_valid = false;
Expand Down
18 changes: 12 additions & 6 deletions src/rust/iced-x86/src/block_enc/instr/jmp_instr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum InstrKind {
}

pub(super) struct JmpInstr {
bitness: u8,
instruction: Instruction,
target_instr: TargetInstr,
pointer_data: Option<Rc<RefCell<BlockData>>>,
Expand Down Expand Up @@ -57,6 +58,7 @@ impl JmpInstr {
} as u32
}
Self {
bitness: block_encoder.bitness() as u8,
instruction: *instruction,
target_instr: TargetInstr::default(),
pointer_data: None,
Expand All @@ -75,7 +77,7 @@ impl JmpInstr {
let mut target_address = self.target_instr.address(ctx);
let mut next_rip = ctx.ip.wrapping_add(self.short_instruction_size as u64);
let mut diff = target_address.wrapping_sub(next_rip) as i64;
diff = correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained);
diff = InstrUtils::convert_diff_to_bitness_diff(self.bitness, correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained));
if i8::MIN as i64 <= diff && diff <= i8::MAX as i64 {
if let Some(ref pointer_data) = self.pointer_data {
pointer_data.borrow_mut().is_valid = false;
Expand All @@ -86,11 +88,15 @@ impl JmpInstr {
return true;
}

target_address = self.target_instr.address(ctx);
next_rip = ctx.ip.wrapping_add(self.near_instruction_size as u64);
diff = target_address.wrapping_sub(next_rip) as i64;
diff = correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained);
let use_near = i32::MIN as i64 <= diff && diff <= i32::MAX as i64;
// If it's in the same block, we assume the target is at most 2GB away.
let mut use_near = self.bitness != 64 || self.target_instr.is_in_block(ctx.block);
if !use_near {
target_address = self.target_instr.address(ctx);
next_rip = ctx.ip.wrapping_add(self.near_instruction_size as u64);
diff = target_address.wrapping_sub(next_rip) as i64;
diff = InstrUtils::convert_diff_to_bitness_diff(self.bitness, correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained));
use_near = i32::MIN as i64 <= diff && diff <= i32::MAX as i64;
}
if use_near {
if let Some(ref pointer_data) = self.pointer_data {
pointer_data.borrow_mut().is_valid = false;
Expand Down
Loading

0 comments on commit 3ef209c

Please sign in to comment.