Exemplo n.º 1
0
 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)
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
def is_rel8(operand):
    from peachpy.util import is_sint8
    return isinstance(operand, RIPRelativeOffset) and is_sint8(operand.offset)
Exemplo n.º 4
0
def is_rel8(operand):
    from peachpy.util import is_sint8
    return isinstance(operand, RIPRelativeOffset) and is_sint8(operand.offset)
Exemplo n.º 5
0
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])
Exemplo n.º 6
0
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])