1# This file is part of PeachPy package and is licensed under the Simplified BSD license.
2#    See license.rst for the full text of the license.
3
4
5def optional_rex(r, rm, force_rex=False):
6    assert r in {0, 1}, "REX.R must be 0 or 1"
7    from peachpy.x86_64.operand import MemoryAddress, RIPRelativeOffset
8    from peachpy.x86_64.registers import Register
9    assert isinstance(rm, (Register, MemoryAddress, RIPRelativeOffset)), \
10        "rm is expected to be a register or a memory address"
11    b = 0
12    x = 0
13    if isinstance(rm, Register):
14        b = rm.hcode
15    elif isinstance(rm, MemoryAddress):
16        if rm.base is not None:
17            b = rm.base.hcode
18        if rm.index is not None:
19            x = rm.index.hcode
20    # If REX.R, REX.X, and REX.B are all zeroes, REX prefix can be omitted
21    if (r | x | b) == 0 and not force_rex:
22        return bytearray()
23    else:
24        return bytearray([0x40 | (r << 2) | (x << 1) | b])
25
26
27def rex(w, r, rm):
28    assert w in {0, 1}, "REX.W must be 0 or 1"
29    assert r in {0, 1}, "REX.R must be 0 or 1"
30    from peachpy.x86_64.operand import MemoryAddress, RIPRelativeOffset
31    assert isinstance(rm, (MemoryAddress, RIPRelativeOffset)), \
32        "rm is expected to be a memory address"
33    b = 0
34    x = 0
35    if isinstance(rm, MemoryAddress):
36        if rm.base is not None:
37            b = rm.base.hcode
38        if rm.index is not None:
39            x = rm.index.hcode
40    return bytearray([0x40 | (w << 3) | (r << 2) | (x << 1) | b])
41
42
43def vex2(lpp, r, rm, vvvv=0, force_vex3=False):
44    #                          2-byte VEX prefix:
45    # Requires: VEX.W = 0, VEX.mmmmm = 0b00001 and VEX.B = VEX.X = 0
46    #         +----------------+
47    # Byte 0: | Bits 0-7: 0xC5 |
48    #         +----------------+
49    #
50    #         +-----------+----------------+----------+--------------+
51    # Byte 1: | Bit 7: ~R | Bits 3-6 ~vvvv | Bit 2: L | Bits 0-1: pp |
52    #         +-----------+----------------+----------+--------------+
53    #
54    #
55    #                          3-byte VEX prefix:
56    #         +----------------+
57    # Byte 0: | Bits 0-7: 0xC4 |
58    #         +----------------+
59    #
60    #         +-----------+-----------+-----------+-------------------+
61    # Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: 0b00001 |
62    #         +-----------+-----------+-----------+-------------------+
63    #
64    #         +----------+-----------------+----------+--------------+
65    # Byte 2: | Bit 7: 0 | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
66    #         +----------+-----------------+----------+--------------+
67    assert lpp & ~0b111 == 0, "VEX.Lpp must be a 3-bit mask"
68    assert r & ~0b1 == 0, "VEX.R must be a single-bit mask"
69    assert vvvv & ~0b1111 == 0, "VEX.vvvv must be a 4-bit mask"
70    from peachpy.x86_64.operand import MemoryAddress, RIPRelativeOffset
71    from peachpy.x86_64.registers import Register
72    assert rm is None or isinstance(rm, (Register, MemoryAddress, RIPRelativeOffset)), \
73        "rm is expected to be a register, a memory address, a rip-relative offset, or None"
74    b = 0
75    x = 0
76    if rm is not None:
77        if isinstance(rm, Register):
78            b = rm.hcode
79        elif isinstance(rm, MemoryAddress):
80            if rm.base is not None:
81                b = rm.base.hcode
82            if rm.index is not None:
83                x = rm.index.hcode
84    # If VEX.B and VEX.X are zeroes, 2-byte VEX prefix can be used
85    if (x | b) == 0 and not force_vex3:
86        return bytearray([0xC5, 0xF8 ^ (r << 7) ^ (vvvv << 3) ^ lpp])
87    else:
88        return bytearray([0xC4, 0xE1 ^ (r << 7) ^ (x << 6) ^ (b << 5), 0x78 ^ (vvvv << 3) ^ lpp])
89
90
91def vex3(escape, mmmmm, w____lpp, r, rm, vvvv=0):
92    #                         3-byte VEX/XOP prefix
93    #         +-----------------------------------+
94    # Byte 0: | Bits 0-7: 0xC4 (VEX) / 0x8F (XOP) |
95    #         +-----------------------------------+
96    #
97    #         +-----------+-----------+-----------+-----------------+
98    # Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: mmmmm |
99    #         +-----------+-----------+-----------+-----------------+
100    #
101    #         +----------+-----------------+----------+--------------+
102    # Byte 2: | Bit 7: W | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
103    #         +----------+-----------------+----------+--------------+
104    assert escape in {0xC4, 0x8F}, "escape must be a 3-byte VEX (0xC4) or XOP (0x8F) prefix"
105    assert w____lpp & ~0b10000111 == 0, "VEX.W____Lpp is expected to have no bits set except 0, 1, 2 and 7"
106    assert mmmmm & ~0b11111 == 0, "VEX.m-mmmm is expected to be a 5-bit mask"
107    assert r & ~0b1 == 0, "VEX.R must be a single-bit mask"
108    assert vvvv & ~0b1111 == 0, "VEX.vvvv must be a 4-bit mask"
109    from peachpy.x86_64.operand import MemoryAddress, RIPRelativeOffset
110    assert isinstance(rm, (MemoryAddress, RIPRelativeOffset)), \
111        "rm is expected to be a memory address or a rip-relative offset"
112    b = 0
113    x = 0
114    if isinstance(rm, MemoryAddress):
115        if rm.base is not None:
116            b = rm.base.hcode
117        if rm.index is not None:
118            x = rm.index.hcode
119    return bytearray([escape, 0xE0 ^ (r << 7) ^ (x << 6) ^ (b << 5) ^ mmmmm, 0x78 ^ (vvvv << 3) ^ w____lpp])
120
121
122def evex(mm, w____1pp, ll, rr, rm, Vvvvv=0, aaa=0, z=0, b=0):
123    assert mm & ~0b11 == 0, "EVEX.mm must be a 2-bit mask"
124    assert w____1pp & ~0b10000011 == 0b100, "EVEX.W____1pp is expected to have no bits set except 0, 1, 2, and 7"
125    assert ll & ~0b11 == 0, "EVEX.L'L must be a 2-bit mask"
126    assert rr & ~0b11 == 0, "EVEX.R'R must be a 2-bit mask"
127    assert Vvvvv & ~0b11111 == 0, "EVEX.v'vvvv must be a 5-bit mask"
128    assert aaa & ~0b111 == 0, "EVEX.aaa must be a 3-bit mask"
129    assert z & ~0b1 == 0, "EVEX.z must be a single-bit mask"
130    from peachpy.x86_64.operand import MemoryAddress, RIPRelativeOffset
131    from peachpy.x86_64.registers import Register, XMMRegister, YMMRegister, ZMMRegister
132    assert rm is None or isinstance(rm, (Register, MemoryAddress, RIPRelativeOffset)), \
133        "rm is expected to be a register, a memory address, or None"
134    r_, r = rr >> 1, rr & 1
135    v_, vvvv = Vvvvv >> 4, Vvvvv & 0b1111
136    b_ = 0
137    x = 0
138    if rm is not None:
139        if isinstance(rm, Register):
140            b_ = rm.hcode
141            x = rm.ecode
142        elif isinstance(rm, MemoryAddress):
143            if rm.base is not None:
144                b_ = rm.base.hcode
145            if rm.index is not None:
146                x = rm.index.hcode
147                if isinstance(rm.index, (XMMRegister, YMMRegister, ZMMRegister)):
148                    v_ = rm.index.ecode
149    p0 = (r << 7) | (x << 6) | (b_ << 5) | (r_ << 4) | mm
150    p1 = w____1pp | (vvvv << 3)
151    p2 = (z << 7) | (ll << 5) | (b << 4) | (v_ << 3) | aaa
152    # p0: invert RXBR' (bits 4-7)
153    # p1: invert vvvv (bits 3-6)
154    # p2: invert V' (bit 3)
155    return bytearray([0x62, p0 ^ 0xF0, p1 ^ 0x78, p2 ^ 0x08])
156
157
158def modrm_sib_disp(reg, rm, force_sib=False, min_disp=0, disp8xN=None):
159    from peachpy.x86_64.operand import MemoryAddress, RIPRelativeOffset
160    from peachpy.x86_64.registers import rsp, rbp, r13
161    from peachpy.util import is_int, is_sint8, ilog2
162
163    assert is_int(reg) and 0 <= reg <= 7, \
164        "Constant reg value expected, got " + str(reg)
165    assert isinstance(rm, (MemoryAddress, RIPRelativeOffset))
166
167    if disp8xN is None:
168        disp8xN = 1
169    assert disp8xN in [1, 2, 4, 8, 16, 32, 64]
170
171    #                    ModR/M byte
172    # +----------------+---------------+--------------+
173    # | Bits 6-7: mode | Bits 3-5: reg | Bits 0-2: rm |
174    # +----------------+---------------+--------------+
175    #
176    #                         SIB byte
177    # +-----------------+-----------------+----------------+
178    # | Bits 6-7: scale | Bits 3-5: index | Bits 0-2: base |
179    # +-----------------+-----------------+----------------+
180    if isinstance(rm, MemoryAddress):
181        # TODO: support global addresses, including rip-relative addresses
182        assert rm.base is not None or rm.index is not None, \
183            "Global addressing is not yet supported"
184        if not force_sib and rm.index is None and rm.base.lcode != 0b100:
185            # No SIB byte
186            if rm.displacement == 0 and rm.base != rbp and rm.base != r13 and min_disp <= 0:
187                # ModRM.mode = 0 (no displacement)
188
189                assert rm.base.lcode != 0b100, \
190                    "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)"
191                assert rm.base.lcode != 0b101, \
192                    "rbp/r13 is not encodable as a base register (interpreted as disp32 address)"
193                return bytearray([(reg << 3) | rm.base.lcode])
194            elif (rm.displacement % disp8xN == 0) and is_sint8(rm.displacement // disp8xN) and min_disp <= 1:
195                # ModRM.mode = 1 (8-bit displacement)
196
197                assert rm.base.lcode != 0b100, \
198                    "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)"
199                return bytearray([0x40 | (reg << 3) | rm.base.lcode, (rm.displacement // disp8xN) & 0xFF])
200            else:
201                # ModRM.mode == 2 (32-bit displacement)
202
203                assert rm.base.lcode != 0b100, \
204                    "rsp/r12 are not encodable as a base register (interpreted as SIB indicator)"
205                return bytearray([0x80 | (reg << 3) | rm.base.lcode,
206                                 rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF,
207                                 (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF])
208        else:
209            # All encodings below use ModRM.rm = 4 (0b100) to indicate the presence of SIB
210
211            assert rsp != rm.index, "rsp is not encodable as an index register (interpreted as no index)"
212            # Index = 4 (0b100) denotes no-index encoding
213            index = 0x4 if rm.index is None else rm.index.lcode
214            scale = 0 if rm.scale is None else ilog2(rm.scale)
215            if rm.base is None:
216                # SIB.base = 5 (0b101) and ModRM.mode = 0 indicates no-base encoding with disp32
217
218                return bytearray([(reg << 3) | 0x4, (scale << 6) | (index << 3) | 0x5,
219                                 rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF,
220                                 (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF])
221            else:
222                if rm.displacement == 0 and rm.base.lcode != 0b101 and min_disp <= 0:
223                    # ModRM.mode == 0 (no displacement)
224
225                    assert rm.base.lcode != 0b101, \
226                        "rbp/r13 is not encodable as a base register (interpreted as disp32 address)"
227                    return bytearray([(reg << 3) | 0x4, (scale << 6) | (index << 3) | rm.base.lcode])
228                elif (rm.displacement % disp8xN == 0) and is_sint8(rm.displacement // disp8xN) and min_disp <= 1:
229                    # ModRM.mode == 1 (8-bit displacement)
230
231                    return bytearray([(reg << 3) | 0x44, (scale << 6) | (index << 3) | rm.base.lcode,
232                                      (rm.displacement // disp8xN) & 0xFF])
233                else:
234                    # ModRM.mode == 2 (32-bit displacement)
235
236                    return bytearray([(reg << 3) | 0x84, (scale << 6) | (index << 3) | rm.base.lcode,
237                                     rm.displacement & 0xFF, (rm.displacement >> 8) & 0xFF,
238                                     (rm.displacement >> 16) & 0xFF, (rm.displacement >> 24) & 0xFF])
239    elif isinstance(rm, RIPRelativeOffset):
240        # ModRM.mode == 0 and ModeRM.rm == 5 (0b101) indicates (rip + disp32) addressing
241        return bytearray([0b00000101 | (reg << 3),
242                          rm.offset & 0xFF, (rm.offset >> 8) & 0xFF,
243                          (rm.offset >> 16) & 0xFF, (rm.offset >> 24) & 0xFF])
244
245
246def nop(length):
247    assert 1 <= length <= 15
248    # Note: the generated NOPs must be allowed by NaCl validator, see
249    # https://src.chromium.org/viewvc/native_client/trunk/src/native_client/src/trusted/validator_ragel/instruction_definitions/general_purpose_instructions.def
250    # https://src.chromium.org/viewvc/native_client/trunk/src/native_client/src/trusted/validator_ragel/instruction_definitions/nops.def
251    return {
252        1: bytearray([0x90]),
253        2: bytearray([0x40, 0x90]),
254        3: bytearray([0x0F, 0x1F, 0x00]),
255        4: bytearray([0x0F, 0x1F, 0x40, 0x00]),
256        5: bytearray([0x0F, 0x1F, 0x44, 0x00, 0x00]),
257        6: bytearray([0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00]),
258        7: bytearray([0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00]),
259        8: bytearray([0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
260        9: bytearray([0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
261        10: bytearray([0x66, 0x2E, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
262        11: bytearray([0x66, 0x66, 0x2E, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
263        12: bytearray([0x66, 0x66, 0x66, 0x2E, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
264        13: bytearray([0x66, 0x66, 0x66, 0x66, 0x2E, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
265        14: bytearray([0x66, 0x66, 0x66, 0x66, 0x66, 0x2E, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
266        15: bytearray([0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x2E, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00])
267    }[length]
268
269
270class Flags:
271    AccumulatorOp0 = 0x01
272    AccumulatorOp1 = 0x02
273    Rel8Label = 0x04
274    Rel32Label = 0x08
275    ModRMSIBDisp = 0x10
276    OptionalREX = 0x20
277    VEX2 = 0x40
278
279
280class Options:
281    Disp8 = 0x01
282    Disp32 = 0x02
283    SIB = 0x04
284    REX = 0x08
285    VEX3 = 0x10