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