def _encode_label_branch(self, address, label_address=None, long_encoding=False): if label_address is None: encodings = [encode(0) for (_, encode) in self.encodings] else: encodings = [] from peachpy.x86_64.encoding import Flags from peachpy.util import is_sint8, is_sint32 for (flags, encode) in self.encodings: offset = label_address - (address + len(encode(0))) if flags & Flags.Rel8Label != 0 and is_sint8(offset) or \ flags & Flags.Rel32Label != 0 and is_sint32(offset): encodings.append(encode(offset)) if not encodings: raise ValueError("Can not encode offset to label %s" % self.label_name) assert len( encodings ) <= 2, "At most 2 encodings expected for branch instructions with immediate code offset" if len(encodings) == 1: return True, encodings[0] else: if long_encoding: return True, max(encodings, key=len) else: return False, min(encodings, key=len)
def _encode_label_branch(self, address, label_address=None, long_encoding=False): if label_address is None: encodings = [encode(0) for (_, encode) in self.encodings] else: encodings = [] from peachpy.x86_64.encoding import Flags from peachpy.util import is_sint8, is_sint32 for (flags, encode) in self.encodings: offset = label_address - (address + len(encode(0))) if ( flags & Flags.Rel8Label != 0 and is_sint8(offset) or flags & Flags.Rel32Label != 0 and is_sint32(offset) ): encodings.append(encode(offset)) if not encodings: raise ValueError("Can not encode offset to label %s" % self.label_name) assert len(encodings) <= 2, "At most 2 encodings expected for branch instructions with immediate code offset" if len(encodings) == 1: return True, encodings[0] else: if long_encoding: return True, max(encodings, key=len) else: return False, min(encodings, key=len)
def is_rel8(operand): from peachpy.util import is_sint8 return isinstance(operand, RIPRelativeOffset) and is_sint8(operand.offset)
def modrm_sib_disp(reg, rm, force_sib=False, min_disp=0): from peachpy.x86_64.operand import MemoryAddress from peachpy.x86_64.registers import rsp, rbp, r12, r13 from peachpy.util import is_int, is_sint8, ilog2 assert is_int(reg) and 0 <= reg <= 7, \ "Constant reg value expected, got " + str(reg) assert isinstance(rm, MemoryAddress) # TODO: support global addresses, including rip-relative addresses assert rm.base is not None or rm.index is not None, \ "Global addressing is not yet supported" # ModR/M byte # +----------------+---------------+--------------+ # | Bits 6-7: mode | Bits 3-5: reg | Bits 0-2: rm | # +----------------+---------------+--------------+ # # SIB byte # +-----------------+-----------------+----------------+ # | Bits 6-7: scale | Bits 3-5: index | Bits 0-2: base | # +-----------------+-----------------+----------------+ if not force_sib and rm.index is None and rm.base.lcode != 0b100: # No SIB byte if rm.displacement == 0 and rm.base != rbp and rm.base != r13 and min_disp <= 0: # ModRM.mode = 0 (no displacement) assert rm.base.lcode != 0b100, "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)" assert rm.base.lcode != 0b101, "rbp/r13 is not encodable as a base register (interpreted as disp32 address)" return bytearray([(reg << 3) | rm.base.lcode]) elif is_sint8(rm.displacement) and min_disp <= 1: # ModRM.mode = 1 (8-bit displacement) assert rm.base.lcode != 0b100, "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)" return bytearray( [0x40 | (reg << 3) | rm.base.lcode, rm.displacement & 0xFF]) else: # ModRM.mode == 2 (32-bit displacement) assert rm.base.lcode != 0b100, "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)" return bytearray([ 0x80 | (reg << 3) | rm.base.lcode, rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF, (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF ]) else: # All encodings below use ModRM.rm = 4 (0b100) to indicate the presence of SIB assert rsp != rm.index, "rsp is not encodable as an index register (interpreted as no index)" # Index = 4 (0b100) denotes no-index encoding index = 0x4 if rm.index is None else rm.index.lcode scale = 0 if rm.scale is None else ilog2(rm.scale) if rm.base is None: # SIB.base = 5 (0b101) and ModRM.mode = 0 indicates no-base encoding with disp32 return bytearray([(reg << 3) | 0x4, (scale << 6) | (index << 3) | 0x5, rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF, (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF]) else: if rm.displacement == 0 and rm.base.lcode != 0b101 and min_disp <= 0: # ModRM.mode == 0 (no displacement) assert rm.base.lcode != 0b101, \ "rbp/r13 is not encodable as a base register (interpreted as disp32 address)" return bytearray([(reg << 3) | 0x4, (scale << 6) | (index << 3) | rm.base.lcode]) elif is_sint8(rm.displacement) and min_disp <= 1: # ModRM.mode == 1 (8-bit displacement) return bytearray([(reg << 3) | 0x44, (scale << 6) | (index << 3) | rm.base.lcode, rm.displacement & 0xFF]) else: # ModRM.mode == 2 (32-bit displacement) return bytearray([(reg << 3) | 0x84, (scale << 6) | (index << 3) | rm.base.lcode, rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF, (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF])
def modrm_sib_disp(reg, rm, force_sib=False, min_disp=0, disp8xN=None): from peachpy.x86_64.operand import MemoryAddress from peachpy.x86_64.registers import rsp, rbp, r12, r13 from peachpy.util import is_int, is_sint8, ilog2 assert is_int(reg) and 0 <= reg <= 7, \ "Constant reg value expected, got " + str(reg) assert isinstance(rm, (MemoryAddress, int)) if disp8xN is None: disp8xN = 1 assert disp8xN in [1, 2, 4, 8, 16, 32, 64] # ModR/M byte # +----------------+---------------+--------------+ # | Bits 6-7: mode | Bits 3-5: reg | Bits 0-2: rm | # +----------------+---------------+--------------+ # # SIB byte # +-----------------+-----------------+----------------+ # | Bits 6-7: scale | Bits 3-5: index | Bits 0-2: base | # +-----------------+-----------------+----------------+ if isinstance(rm, MemoryAddress): # TODO: support global addresses, including rip-relative addresses assert rm.base is not None or rm.index is not None, \ "Global addressing is not yet supported" if not force_sib and rm.index is None and rm.base.lcode != 0b100: # No SIB byte if rm.displacement == 0 and rm.base != rbp and rm.base != r13 and min_disp <= 0: # ModRM.mode = 0 (no displacement) assert rm.base.lcode != 0b100, \ "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)" assert rm.base.lcode != 0b101, \ "rbp/r13 is not encodable as a base register (interpreted as disp32 address)" return bytearray([(reg << 3) | rm.base.lcode]) elif (rm.displacement % disp8xN == 0) and is_sint8(rm.displacement // disp8xN) and min_disp <= 1: # ModRM.mode = 1 (8-bit displacement) assert rm.base.lcode != 0b100, \ "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)" return bytearray([0x40 | (reg << 3) | rm.base.lcode, (rm.displacement // disp8xN) & 0xFF]) else: # ModRM.mode == 2 (32-bit displacement) assert rm.base.lcode != 0b100, \ "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)" return bytearray([0x80 | (reg << 3) | rm.base.lcode, rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF, (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF]) else: # All encodings below use ModRM.rm = 4 (0b100) to indicate the presence of SIB assert rsp != rm.index, "rsp is not encodable as an index register (interpreted as no index)" # Index = 4 (0b100) denotes no-index encoding index = 0x4 if rm.index is None else rm.index.lcode scale = 0 if rm.scale is None else ilog2(rm.scale) if rm.base is None: # SIB.base = 5 (0b101) and ModRM.mode = 0 indicates no-base encoding with disp32 return bytearray([(reg << 3) | 0x4, (scale << 6) | (index << 3) | 0x5, rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF, (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF]) else: if rm.displacement == 0 and rm.base.lcode != 0b101 and min_disp <= 0: # ModRM.mode == 0 (no displacement) assert rm.base.lcode != 0b101, \ "rbp/r13 is not encodable as a base register (interpreted as disp32 address)" return bytearray([(reg << 3) | 0x4, (scale << 6) | (index << 3) | rm.base.lcode]) elif (rm.displacement % disp8xN == 0) and is_sint8(rm.displacement // disp8xN) and min_disp <= 1: # ModRM.mode == 1 (8-bit displacement) return bytearray([(reg << 3) | 0x44, (scale << 6) | (index << 3) | rm.base.lcode, (rm.displacement // disp8xN) & 0xFF]) else: # ModRM.mode == 2 (32-bit displacement) return bytearray([(reg << 3) | 0x84, (scale << 6) | (index << 3) | rm.base.lcode, rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF, (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF]) else: # ModRM.mode == 0 and ModeRM.rm == 5 (0b101) indicates (rip + disp32) addressing return bytearray([0b00000101 | (reg << 3), rm & 0xFF, (rm >> 8) & 0xFF, (rm >> 16) & 0xFF, (rm >> 24) & 0xFF])