Closed
Description
Currently during dynamicClass::IL_STUB_PInvoke
methods holds StubSecretArg
in caller-saved registers: x12
for arm64 and t2
for riscv64. Later this register value is used for CORINFO_HELP_INIT_PINVOKE_FRAME call as arg. But in the middle there are may appear some call which may trash this register. Check arm64 listing below for x12
:
G_M9476_IG01: ; offs=0x000000, size=0x005C, bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref, nogc <-- Prolog IG
IN0060: 000000 stp x19, x20, [sp, #-0x50]!
IN0061: 000004 stp x21, x22, [sp, #0x10]
IN0062: 000008 stp x23, x24, [sp, #0x20]
IN0063: 00000C stp x25, x26, [sp, #0x30]
IN0064: 000010 stp x27, x28, [sp, #0x40]
IN0065: 000014 stp fp, lr, [sp, #-0x1F0]!
IN0066: 000018 mov fp, sp
IN0067: 00001C str x12, [fp, #0x60] // [V06 tmp1] // x12 has correct StubSecretArg value which is pMethodDesc
IN0068: 000020 movi v16.16b, #0
IN0069: 000024 add x9, fp, #184
IN006a: 000028 add x10, fp, #408
IN006b: 00002C stp q16, q16, [x9, #-0x40]
IN006c: 000030 stp q16, q16, [x9, #-0x20]
IN006d: 000034 bfm x9, xzr, #0, #5
IN006e: 000038 dczva x9
IN006f: 00003C add x9, x9, #64
IN0070: 000040 cmp x9, x10
IN0071: 000044 blo pc-16 (-4 instructions)
IN0072: 000048 stp q16, q16, [x10]
IN0073: 00004C stp q16, q16, [x10, #0x20]
IN0074: 000050 add x1, sp, #576
IN0075: 000054 str x1, [fp, #0x1E8] // [V10 PSPSym]
IN0076: 000058 str x0, [fp, #0x1E0] // [V00 arg0]
;; size=92 bbWeight=1 PerfScore 19.50
G_M9476_IG02: ; offs=0x00005C, size=0x0040, bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, BB09 [0008], BB01 [0000], byref
IN0001: 00005C add x0, fp, #128 // [V03 loc2]
IN0002: 000060 movn w1, #50
IN0003: 000064 mov x2, #296
recordRelocation: 0x7f6e000280 (rw: 0x7f6e000280) => 0x7fae164630, type 3 (IMAGE_REL_ARM64_BRANCH26), delta 0
IN0004: 000068 bl CORINFO_HELP_MEMSET // x12 is caller-saved register, so it may trashed inside.
; gcr arg pop 0
IN0005: 00006C add x0, fp, #32 // [V09 PInvokeFrame+0x08]
IN0006: 000070 mov x1, x12 // correct x12 with StubSecretArg is used here, however need to restore value from stack because have calls `bl` before
recordRelocation: 0x7f6e00028c (rw: 0x7f6e00028c) => 0x7fadfcc6a4, type 3 (IMAGE_REL_ARM64_BRANCH26), delta 0
IN0007: 000074 bl CORINFO_HELP_INIT_PINVOKE_FRAME
IN0008: 000078 str x0, [fp, #0x68] // [V08 FramesRoot]
For riscv64 assert appears with DOTNET_GCStress=0x1
on test JIT/SIMD/Vector3Interop_r/Vector3Interop_r.dll
. Check t2
register and comments in asm:
(gdb) dism 0x0000003f78281dd0
Disassemble for 0x3f78281d20 ,+ 0x388 void [Vector3Interop_r] dynamicClass::IL_STUB_PInvoke(valuetype ComplexDT&)[MinOptJitted]
Dump of assembler code from 0x3f78281d20 to 0x3f782820a8:
0x0000003f78281d20: addi sp,sp,-576
0x0000003f78281d24: sd s0,0(sp)
0x0000003f78281d28: sd ra,8(sp)
0x0000003f78281d2c: sd s1,488(sp)
0x0000003f78281d30: sd s2,496(sp)
0x0000003f78281d34: sd s3,504(sp)
0x0000003f78281d38: sd s4,512(sp)
0x0000003f78281d3c: sd s5,520(sp)
0x0000003f78281d40: sd s6,528(sp)
0x0000003f78281d44: sd s7,536(sp)
0x0000003f78281d48: sd s8,544(sp)
0x0000003f78281d4c: sd s9,552(sp)
0x0000003f78281d50: sd s10,560(sp)
0x0000003f78281d54: sd s11,568(sp)
0x0000003f78281d58: mv s0,sp
0x0000003f78281d5c: sd t2,88(s0) // t2 has correct StubSecretArg value which is pMethodDesc
0x0000003f78281d60: addi s1,s0,112
0x0000003f78281d64: li t0,22
0x0000003f78281d68: sd zero,8(s1)
0x0000003f78281d6c: sd zero,0(s1)
0x0000003f78281d70: addi t0,t0,-1
0x0000003f78281d74: addi s1,s1,16
0x0000003f78281d78: bnez t0,0x3f78281d68
0x0000003f78281d7c: addi s1,sp,576
0x0000003f78281d80: sd s1,480(s0)
0x0000003f78281d84: sd a0,472(s0)
0x0000003f78281d88: addi a0,s0,120
0x0000003f78281d8c: li a1,-51
0x0000003f78281d90: li a2,296
0x0000003f78281d94: lui t2,0x0 // t2 is used as tmp addr to call native JIT_MemSet
0x0000003f78281d98: addi t2,t2,63 # 0x3f
0x0000003f78281d9c: slli t2,t2,0xb
0x0000003f78281da0: addi t2,t2,1978
0x0000003f78281da4: slli t2,t2,0xb
0x0000003f78281da8: addi t2,t2,1499
0x0000003f78281dac: slli t2,t2,0xa
0x0000003f78281db0: jalr 968(t2)
0x0000003f78281db4: addi a0,s0,24
0x0000003f78281db8: mv a1,t2 // corrupted t2 is used like StubSecretArg, need to restore value from stack here, ld a1, 88(s0) instead mv
0x0000003f78281dbc: lui a2,0x7fee6
0x0000003f78281dc0: addiw a2,a2,196 # 0x7fee60c4
0x0000003f78281dc4: slli a2,a2,0x7
0x0000003f78281dc8: addi a2,a2,36
0x0000003f78281dcc: jalr a2 // JIT_InitPInvokeFrame called with trashed StubSecretArg arg, and trashed StubSecretArg get stored in pFrame
0x0000003f78281dd0: sd a0,96(s0)
0x0000003f78281dd4: mv a0,sp
0x0000003f78281dd8: sd a0,56(s0)
0x0000003f78281ddc: mv a0,s0
0x0000003f78281de0: sd a0,72(s0)
0x0000003f78281de4: ld a0,96(s0)
0x0000003f78281de8: addi a1,s0,24
0x0000003f78281dec: sd a1,16(a0)
0x0000003f78281df0: sw zero,468(s0)
0x0000003f78281df4: nop
0x0000003f78281df8: ld a0,472(s0)
0x0000003f78281dfc: ld a1,0(a0)
0x0000003f78281e00: ld ra,8(a0)
0x0000003f78281e04: sd a1,416(s0)
0x0000003f78281e08: sd ra,424(s0)
0x0000003f78281e0c: ld a1,16(a0)
0x0000003f78281e10: ld ra,24(a0)
0x0000003f78281e14: sd a1,432(s0)
0x0000003f78281e18: sd ra,440(s0)
0x0000003f78281e1c: ld a1,32(a0)
0x0000003f78281e20: ld ra,40(a0)
0x0000003f78281e24: sd a1,448(s0)
0x0000003f78281e28: sd ra,456(s0)
0x0000003f78281e2c: addi a0,s0,416
0x0000003f78281e30: addi a1,s0,120
0x0000003f78281e34: addi a3,s0,112
0x0000003f78281e38: li a2,0
0x0000003f78281e3c: lui a4,0x7ef0d
0x0000003f78281e40: addiw a4,a4,1895 # 0x7ef0d767
0x0000003f78281e44: slli a4,a4,0x7
0x0000003f78281e48: mv a4,a4
0x0000003f78281e4c: jalr a4 // call ThePreStub, StackFrameIterator::CheckForSkippedFrames and m_crawl.pFunc->SanityCheck() inside. trashed StubSecretArg dereference leads to assert.
0x0000003f78281e50: li a0,1
...
Should StubSecretArg
restored from the stack before JIT_InitPInvokeFrame
for all architectures?
cc @jkotas @jakobbotsch @dotnet/samsung