wa-lang.org/wazero@v1.0.2/internal/asm/amd64/impl_staticconst_test.go (about) 1 package amd64 2 3 import ( 4 "encoding/hex" 5 "testing" 6 7 "wa-lang.org/wazero/internal/asm" 8 "wa-lang.org/wazero/internal/testing/require" 9 ) 10 11 func TestAssemblerImpl_CompileStaticConstToRegister(t *testing.T) { 12 a := NewAssembler() 13 t.Run("odd count of bytes", func(t *testing.T) { 14 err := a.CompileStaticConstToRegister(MOVDQU, asm.NewStaticConst([]byte{1}), RegAX) 15 require.Error(t, err) 16 }) 17 t.Run("ok", func(t *testing.T) { 18 cons := asm.NewStaticConst([]byte{1, 2, 3, 4}) 19 err := a.CompileStaticConstToRegister(MOVDQU, cons, RegAX) 20 require.NoError(t, err) 21 actualNode := a.current 22 require.Equal(t, MOVDQU, actualNode.instruction) 23 require.Equal(t, operandTypeStaticConst, actualNode.types.src) 24 require.Equal(t, operandTypeRegister, actualNode.types.dst) 25 require.Equal(t, cons, actualNode.staticConst) 26 }) 27 } 28 29 func TestAssemblerImpl_CompileRegisterToStaticConst(t *testing.T) { 30 a := NewAssembler() 31 t.Run("odd count of bytes", func(t *testing.T) { 32 err := a.CompileRegisterToStaticConst(MOVDQU, RegAX, asm.NewStaticConst([]byte{1})) 33 require.Error(t, err) 34 }) 35 t.Run("ok", func(t *testing.T) { 36 cons := asm.NewStaticConst([]byte{1, 2, 3, 4}) 37 err := a.CompileRegisterToStaticConst(MOVDQU, RegAX, cons) 38 require.NoError(t, err) 39 actualNode := a.current 40 require.Equal(t, MOVDQU, actualNode.instruction) 41 require.Equal(t, operandTypeRegister, actualNode.types.src) 42 require.Equal(t, operandTypeStaticConst, actualNode.types.dst) 43 require.Equal(t, cons, actualNode.staticConst) 44 }) 45 } 46 47 func TestAssemblerImpl_maybeFlushConstants(t *testing.T) { 48 t.Run("no consts", func(t *testing.T) { 49 a := NewAssembler() 50 // Invoking maybeFlushConstants before encoding consts usage should not panic. 51 a.maybeFlushConstants(false) 52 a.maybeFlushConstants(true) 53 }) 54 55 largeData := make([]byte, 256) 56 57 tests := []struct { 58 name string 59 endOfFunction bool 60 dummyBodyBeforeFlush []byte 61 firstUseOffsetInBinary uint64 62 consts [][]byte 63 expectedOffsetForConsts []uint64 64 exp []byte 65 maxDisplacement int 66 }{ 67 { 68 name: "end of function", 69 endOfFunction: true, 70 dummyBodyBeforeFlush: []byte{'?', '?', '?', '?'}, 71 consts: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8}, {10, 11, 12, 13}}, 72 expectedOffsetForConsts: []uint64{4, 4 + 8}, // 4 = len(dummyBodyBeforeFlush) 73 firstUseOffsetInBinary: 0, 74 exp: []byte{'?', '?', '?', '?', 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13}, 75 maxDisplacement: 1 << 31, // large displacement will emit the consts at the end of function. 76 }, 77 { 78 name: "not flush", 79 endOfFunction: false, 80 dummyBodyBeforeFlush: []byte{'?', '?', '?', '?'}, 81 consts: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8}, {10, 11, 12, 13}}, 82 firstUseOffsetInBinary: 0, 83 exp: []byte{'?', '?', '?', '?'}, 84 maxDisplacement: 1 << 31, // large displacement will emit the consts at the end of function. 85 }, 86 { 87 name: "not end of function but flush - short jump", 88 endOfFunction: false, 89 dummyBodyBeforeFlush: []byte{'?', '?', '?', '?'}, 90 consts: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8}, {10, 11, 12, 13}}, 91 expectedOffsetForConsts: []uint64{4 + 2, 4 + 2 + 8}, // 4 = len(dummyBodyBeforeFlush), 2 = the size of jump 92 firstUseOffsetInBinary: 0, 93 exp: []byte{ 94 '?', '?', '?', '?', 95 0xeb, 0x0c, // short jump with offset = len(consts[0]) + len(consts[1]) = 12 = 0xc. 96 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 97 }, 98 maxDisplacement: 0, // small displacement flushes the const immediately, not at the end of function. 99 }, 100 { 101 name: "not end of function but flush - long jump", 102 endOfFunction: false, 103 dummyBodyBeforeFlush: []byte{'?', '?', '?', '?'}, 104 consts: [][]byte{largeData}, 105 expectedOffsetForConsts: []uint64{4 + 5}, // 4 = len(dummyBodyBeforeFlush), 5 = the size of jump 106 firstUseOffsetInBinary: 0, 107 exp: append([]byte{ 108 '?', '?', '?', '?', 109 0xe9, 0x0, 0x1, 0x0, 0x0, // short jump with offset = 256 = 0x0, 0x1, 0x0, 0x0 (in Little Endian). 110 }, largeData...), 111 maxDisplacement: 0, // small displacement flushes the const immediately, not at the end of function. 112 }, 113 } 114 115 for _, tc := range tests { 116 t.Run(tc.name, func(t *testing.T) { 117 a := NewAssembler() 118 a.MaxDisplacementForConstantPool = tc.maxDisplacement 119 a.buf.Write(tc.dummyBodyBeforeFlush) 120 121 for i, c := range tc.consts { 122 sc := asm.NewStaticConst(c) 123 a.pool.AddConst(sc, 100) 124 i := i 125 sc.AddOffsetFinalizedCallback(func(offsetOfConstInBinary uint64) { 126 require.Equal(t, tc.expectedOffsetForConsts[i], offsetOfConstInBinary) 127 }) 128 } 129 130 a.pool.FirstUseOffsetInBinary = &tc.firstUseOffsetInBinary 131 a.maybeFlushConstants(tc.endOfFunction) 132 133 require.Equal(t, tc.exp, a.buf.Bytes()) 134 }) 135 } 136 } 137 138 func TestAssemblerImpl_encodeRegisterToStaticConst(t *testing.T) { 139 tests := []struct { 140 name string 141 ins asm.Instruction 142 c []byte 143 reg asm.Register 144 ud2sBeforeConst int 145 exp []byte 146 }{ 147 { 148 name: "cmp r12d, dword ptr [rip + 0x14]", 149 ins: CMPL, 150 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 151 reg: RegR12, 152 ud2sBeforeConst: 10, 153 exp: []byte{ 154 // cmp r12d, dword ptr [rip + 0x14] 155 // where rip = 0x7, therefore [rip + 0x14] = [0x1b] 156 0x44, 0x3b, 0x25, 0x14, 0x0, 0x0, 0x0, 157 // UD2 * ud2sBeforeConst 158 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 159 // 0x1b: consts 160 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 161 }, 162 }, 163 { 164 name: "cmp eax, dword ptr [rip + 0x14]", 165 ins: CMPL, 166 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 167 reg: RegAX, 168 ud2sBeforeConst: 10, 169 exp: []byte{ 170 // cmp eax, dword ptr [rip + 0x14] 171 // where rip = 0x6, therefore [rip + 0x14] = [0x1a] 172 0x3b, 0x5, 0x14, 0x0, 0x0, 0x0, 173 // UD2 * ud2sBeforeConst 174 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 175 // 0x1a: consts 176 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 177 }, 178 }, 179 { 180 name: "cmp r12, qword ptr [rip]", 181 ins: CMPQ, 182 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 183 reg: RegR12, 184 ud2sBeforeConst: 0, 185 exp: []byte{ 186 // cmp r12, qword ptr [rip] 187 // where rip points to the end of this instruction == the const. 188 0x4c, 0x3b, 0x25, 0x0, 0x0, 0x0, 0x0, 189 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 190 }, 191 }, 192 { 193 name: "cmp rsp, qword ptr [rip + 0xa]", 194 ins: CMPQ, 195 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 196 reg: RegSP, 197 ud2sBeforeConst: 5, 198 exp: []byte{ 199 // cmp rsp, qword ptr [rip + 0xa] 200 // where rip = 0x6, therefore [rip + 0xa] = [0x11] 201 0x48, 0x3b, 0x25, 0xa, 0x0, 0x0, 0x0, 202 // UD2 * ud2sBeforeConst 203 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 204 // 0x11: 205 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 206 }, 207 }, 208 } 209 210 for _, tc := range tests { 211 tc := tc 212 t.Run(tc.name, func(t *testing.T) { 213 a := NewAssembler() 214 215 err := a.CompileRegisterToStaticConst(tc.ins, tc.reg, asm.NewStaticConst(tc.c)) 216 require.NoError(t, err) 217 218 for i := 0; i < tc.ud2sBeforeConst; i++ { 219 a.CompileStandAlone(UD2) 220 } 221 222 actual, err := a.Assemble() 223 require.NoError(t, err) 224 225 require.Equal(t, tc.exp, actual, hex.EncodeToString(actual)) 226 }) 227 } 228 } 229 230 func TestAssemblerImpl_encodeStaticConstToRegister(t *testing.T) { 231 tests := []struct { 232 name string 233 ins asm.Instruction 234 c []byte 235 reg asm.Register 236 ud2sBeforeConst int 237 exp []byte 238 }{ 239 { 240 name: "movdqu xmm14, xmmword ptr [rip + 0xa]", 241 ins: MOVDQU, 242 c: []byte{ 243 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 244 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 245 }, 246 reg: RegX14, 247 ud2sBeforeConst: 5, 248 exp: []byte{ 249 // movdqu xmm14, xmmword ptr [rip + 0xa] 250 // where rip = 0x9, therefore [rip + 0xa] = [0x13] 251 0xf3, 0x44, 0xf, 0x6f, 0x35, 0xa, 0x0, 0x0, 0x0, 252 // UD2 * ud2sBeforeConst 253 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 254 // 0x13: 255 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 256 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 257 }, 258 }, 259 { 260 name: "movupd xmm1, xmmword ptr [rip + 0xa]", 261 ins: MOVUPD, 262 c: []byte{ 263 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 264 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 265 }, 266 reg: RegX1, 267 ud2sBeforeConst: 5, 268 exp: []byte{ 269 // movdqu xmm14, xmmword ptr [rip + 0xa] 270 // where rip = 0x8, therefore [rip + 0xa] = [0x12] 271 0x66, 0xf, 0x10, 0xd, 0xa, 0x0, 0x0, 0x0, 272 // UD2 * ud2sBeforeConst 273 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 274 // 0x12: 275 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 276 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 277 }, 278 }, 279 { 280 name: "lea r11, [rip + 0x14]", 281 ins: LEAQ, 282 c: []byte{ 283 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 284 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 285 }, 286 reg: RegR11, 287 ud2sBeforeConst: 10, 288 exp: []byte{ 289 // lea r11, [rip + 0x14] 290 // where rip = 0x7, therefore [rip + 0x14] = [0x1b] 291 0x4c, 0x8d, 0x1d, 0x14, 0x0, 0x0, 0x0, 292 // UD2 * ud2sBeforeConst 293 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 294 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 295 // 0x1b: 296 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 297 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 298 }, 299 }, 300 { 301 name: "mov r11d, dword ptr [rip + 0x3c]", 302 ins: MOVL, 303 c: []byte{ 304 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 305 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 306 }, 307 reg: RegR11, 308 ud2sBeforeConst: 30, 309 exp: []byte{ 310 // mov r11d, dword ptr [rip + 0x3c] 311 // where rip = 0x7, therefore [rip + 0x3c] = [0x43] 312 0x44, 0x8b, 0x1d, 0x3c, 0x0, 0x0, 0x0, 313 // UD2 * ud2sBeforeConst 314 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 315 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 316 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 317 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 318 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 319 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 320 // 0x43: 321 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 322 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 323 }, 324 }, 325 { 326 name: "movd xmm14, dword ptr [rip + 0x3c]", 327 ins: MOVL, 328 c: []byte{ 329 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 330 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 331 }, 332 reg: RegX14, 333 ud2sBeforeConst: 30, 334 exp: []byte{ 335 // movd xmm14, dword ptr [rip + 0x3c] 336 // where rip = 0x9, therefore [rip + 0x3c] = [0x45] 337 0x66, 0x44, 0xf, 0x6e, 0x35, 0x3c, 0x0, 0x0, 0x0, 338 // UD2 * ud2sBeforeConst 339 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 340 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 341 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 342 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 343 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 344 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 345 // 0x45: 346 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 347 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 348 }, 349 }, 350 { 351 name: "mov rsp, qword ptr [rip + 0x3c]", 352 ins: MOVQ, 353 c: []byte{ 354 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 355 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 356 }, 357 reg: RegSP, 358 ud2sBeforeConst: 30, 359 exp: []byte{ 360 // mov rsp, qword ptr [rip + 0x3c] 361 // where rip = 0x7, therefore [rip + 0x3c] = [0x43] 362 0x48, 0x8b, 0x25, 0x3c, 0x0, 0x0, 0x0, 363 // UD2 * ud2sBeforeConst 364 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 365 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 366 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 367 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 368 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 369 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 370 // 0x43: 371 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 372 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 373 }, 374 }, 375 { 376 name: "movq xmm1, qword ptr [rip + 0x3c]", 377 ins: MOVQ, 378 c: []byte{ 379 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 380 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 381 }, 382 reg: RegX1, 383 ud2sBeforeConst: 30, 384 exp: []byte{ 385 // movq xmm1, qword ptr [rip + 0x3c] 386 // where rip = 0x8, therefore [rip + 0x3c] = [0x44] 387 0xf3, 0xf, 0x7e, 0xd, 0x3c, 0x0, 0x0, 0x0, 388 // UD2 * ud2sBeforeConst 389 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 390 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 391 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 392 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 393 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 394 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 395 // 0x44: 396 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 397 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 398 }, 399 }, 400 { 401 name: "ucomisd xmm15, qword ptr [rip + 6]", 402 ins: UCOMISD, 403 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 404 reg: RegX15, 405 ud2sBeforeConst: 3, 406 exp: []byte{ 407 // ucomisd xmm15, qword ptr [rip + 6] 408 // where rip = 0x9, therefore [rip + 6] = [0xf] 409 0x66, 0x44, 0xf, 0x2e, 0x3d, 0x6, 0x0, 0x0, 0x0, 410 // UD2 * ud2sBeforeConst 411 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 412 // 0xf: 413 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 414 }, 415 }, 416 { 417 name: "ucomiss xmm15, dword ptr [rip + 6]", 418 ins: UCOMISS, 419 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 420 reg: RegX15, 421 ud2sBeforeConst: 3, 422 exp: []byte{ 423 // ucomiss xmm15, dword ptr [rip + 6] 424 // where rip = 0x8, therefore [rip + 6] = [0xe] 425 0x44, 0xf, 0x2e, 0x3d, 0x6, 0x0, 0x0, 0x0, 426 // UD2 * ud2sBeforeConst 427 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 428 // 0xe: 429 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 430 }, 431 }, 432 { 433 name: "subss xmm13, dword ptr [rip + 0xa]", 434 ins: SUBSS, 435 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 436 reg: RegX13, 437 ud2sBeforeConst: 5, 438 exp: []byte{ 439 // subss xmm13, dword ptr [rip + 0xa] 440 // where rip = 0x9, therefore [rip + 0xa] = [0x13] 441 0xf3, 0x44, 0xf, 0x5c, 0x2d, 0xa, 0x0, 0x0, 0x0, 442 // UD2 * ud2sBeforeConst 443 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 444 // 0x12: 445 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 446 }, 447 }, 448 { 449 name: "subsd xmm1, qword ptr [rip + 0xa]", 450 ins: SUBSD, 451 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 452 reg: RegX1, 453 ud2sBeforeConst: 5, 454 exp: []byte{ 455 // subsd xmm1, qword ptr [rip + 0xa] 456 // where rip = 0x8, therefore [rip + 0xa] = [0x12] 457 0xf2, 0xf, 0x5c, 0xd, 0xa, 0x0, 0x0, 0x0, 458 // UD2 * ud2sBeforeConst 459 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 460 // 0x12: 461 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 462 }, 463 }, 464 { 465 name: "cmp dword ptr [rip + 0x14], r12d", 466 ins: CMPL, 467 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 468 reg: RegR12, 469 ud2sBeforeConst: 10, 470 exp: []byte{ 471 // cmp dword ptr [rip + 0x14], r12d 472 // where rip = 0x7, therefore [rip + 0x14] = [0x1b] 473 0x44, 0x39, 0x25, 0x14, 0x0, 0x0, 0x0, 474 // UD2 * ud2sBeforeConst 475 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 476 // 0x1b: consts 477 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 478 }, 479 }, 480 { 481 name: "cmp dword ptr [rip + 0x14], eax", 482 ins: CMPL, 483 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 484 reg: RegAX, 485 ud2sBeforeConst: 10, 486 exp: []byte{ 487 // cmp dword ptr [rip + 0x14], eax 488 // where rip = 0x6, therefore [rip + 0x14] = [0x1a] 489 0x39, 0x5, 0x14, 0x0, 0x0, 0x0, 490 // UD2 * ud2sBeforeConst 491 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 492 // 0x1a: consts 493 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 494 }, 495 }, 496 { 497 name: "cmp qword ptr [rip], r12", 498 ins: CMPQ, 499 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 500 reg: RegR12, 501 ud2sBeforeConst: 0, 502 exp: []byte{ 503 // cmp qword ptr [rip], r12 504 // where rip points to the end of this instruction == the const. 505 0x4c, 0x39, 0x25, 0x0, 0x0, 0x0, 0x0, 506 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 507 }, 508 }, 509 { 510 name: "cmp qword ptr [rip + 0xa], rsp", 511 ins: CMPQ, 512 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 513 reg: RegSP, 514 ud2sBeforeConst: 5, 515 exp: []byte{ 516 // cmp qword ptr [rip + 0xa], rsp 517 // where rip = 0x6, therefore [rip + 0xa] = [0x11] 518 0x48, 0x39, 0x25, 0xa, 0x0, 0x0, 0x0, 519 // UD2 * ud2sBeforeConst 520 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 521 // 0x11: 522 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 523 }, 524 }, 525 { 526 name: "ucomiss xmm15, dword ptr [rip + 6]", 527 ins: UCOMISS, 528 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 529 reg: RegX15, 530 ud2sBeforeConst: 3, 531 exp: []byte{ 532 // ucomiss xmm15, dword ptr [rip + 6] 533 // where rip = 0x8, therefore [rip + 6] = [0xe] 534 0x44, 0xf, 0x2e, 0x3d, 0x6, 0x0, 0x0, 0x0, 535 // UD2 * ud2sBeforeConst 536 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 537 // 0xe: 538 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 539 }, 540 }, 541 { 542 name: "subss xmm13, dword ptr [rip + 0xa]", 543 ins: SUBSS, 544 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 545 reg: RegX13, 546 ud2sBeforeConst: 5, 547 exp: []byte{ 548 // subss xmm13, dword ptr [rip + 0xa] 549 // where rip = 0x9, therefore [rip + 0xa] = [0x13] 550 0xf3, 0x44, 0xf, 0x5c, 0x2d, 0xa, 0x0, 0x0, 0x0, 551 // UD2 * ud2sBeforeConst 552 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 553 // 0x12: 554 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 555 }, 556 }, 557 { 558 name: "subsd xmm1, qword ptr [rip + 0xa]", 559 ins: SUBSD, 560 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 561 reg: RegX1, 562 ud2sBeforeConst: 5, 563 exp: []byte{ 564 // subsd xmm1, qword ptr [rip + 0xa] 565 // where rip = 0x8, therefore [rip + 0xa] = [0x12] 566 0xf2, 0xf, 0x5c, 0xd, 0xa, 0x0, 0x0, 0x0, 567 // UD2 * ud2sBeforeConst 568 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 569 // 0x12: 570 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 571 }, 572 }, 573 { 574 name: "add eax, dword ptr [rip + 0xa]", 575 ins: ADDL, 576 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 577 reg: RegAX, 578 ud2sBeforeConst: 5, 579 exp: []byte{ 580 // add eax, dword ptr [rip + 0xa] 581 // where rip = 0x6, therefore [rip + 0xa] = [0x10] 582 0x3, 0x5, 0xa, 0x0, 0x0, 0x0, 583 // UD2 * ud2sBeforeConst 584 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 585 // 0x10: 586 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 587 }, 588 }, 589 { 590 name: "add rax, qword ptr [rip + 0xa]", 591 ins: ADDQ, 592 c: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, 593 reg: RegAX, 594 ud2sBeforeConst: 5, 595 exp: []byte{ 596 // add rax, dword ptr [rip + 0xa] 597 // where rip = 0x7, therefore [rip + 0xa] = [0x11] 598 0x48, 0x3, 0x5, 0xa, 0x0, 0x0, 0x0, 599 // UD2 * ud2sBeforeConst 600 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 0xf, 0xb, 601 // 0x11: 602 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 603 }, 604 }, 605 } 606 607 for _, tc := range tests { 608 tc := tc 609 t.Run(tc.name, func(t *testing.T) { 610 a := NewAssembler() 611 612 err := a.CompileStaticConstToRegister(tc.ins, asm.NewStaticConst(tc.c), tc.reg) 613 require.NoError(t, err) 614 615 for i := 0; i < tc.ud2sBeforeConst; i++ { 616 a.CompileStandAlone(UD2) 617 } 618 619 actual, err := a.Assemble() 620 require.NoError(t, err) 621 622 require.Equal(t, tc.exp, actual, hex.EncodeToString(actual)) 623 }) 624 } 625 }