From 049125145e1d63eefb228f01fa013512773c9a64 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Wed, 4 Jun 2025 08:08:11 +0200 Subject: [PATCH 01/11] Remove dead code for parsing/emitting X86 instructions --- src/coreclr/vm/gc_unwind_x86.inl | 11 --- src/coreclr/vm/i386/stublinkerx86.cpp | 105 -------------------------- src/coreclr/vm/i386/stublinkerx86.h | 16 ---- 3 files changed, 132 deletions(-) diff --git a/src/coreclr/vm/gc_unwind_x86.inl b/src/coreclr/vm/gc_unwind_x86.inl index fa5b88b32be20b..5aaa8fa7f805e6 100644 --- a/src/coreclr/vm/gc_unwind_x86.inl +++ b/src/coreclr/vm/gc_unwind_x86.inl @@ -7,21 +7,10 @@ #define RETURN_ADDR_OFFS 1 // in DWORDS -#define X86_INSTR_TEST_ESP_SIB 0x24 -#define X86_INSTR_PUSH_0 0x6A // push 00, entire instruction is 0x6A00 -#define X86_INSTR_PUSH_IMM 0x68 // push NNNN, -#define X86_INSTR_W_PUSH_IND_IMM 0x35FF // push [NNNN] #define X86_INSTR_CALL_REL32 0xE8 // call rel32 #define X86_INSTR_W_CALL_IND_IMM 0x15FF // call [addr32] #define X86_INSTR_NOP 0x90 // nop -#define X86_INSTR_NOP2 0x9090 // 2-byte nop -#define X86_INSTR_NOP3_1 0x9090 // 1st word of 3-byte nop -#define X86_INSTR_NOP3_3 0x90 // 3rd byte of 3-byte nop -#define X86_INSTR_NOP4 0x90909090 // 4-byte nop -#define X86_INSTR_NOP5_1 0x90909090 // 1st dword of 5-byte nop -#define X86_INSTR_NOP5_5 0x90 // 5th byte of 5-byte nop #define X86_INSTR_INT3 0xCC // int3 -#define X86_INSTR_HLT 0xF4 // hlt #define X86_INSTR_PUSH_EAX 0x50 // push eax #define X86_INSTR_PUSH_EBP 0x55 // push ebp #define X86_INSTR_W_MOV_EBP_ESP 0xEC8B // mov ebp, esp diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index ad519187e118a2..45f8e2bb78a97e 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -857,22 +857,6 @@ VOID StubLinkerCPU::X86EmitZeroOutReg(X86Reg reg) Emit8(static_cast(0xc0 | (reg << 3) | reg)); } -//--------------------------------------------------------------- -// Emits: -// jmp [reg] -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitJumpReg(X86Reg reg) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - } - CONTRACTL_END; - - Emit8(0xff); - Emit8(static_cast(0xe0) | static_cast(reg)); -} - //--------------------------------------------------------------- // Emits: @@ -937,23 +921,6 @@ VOID StubLinkerCPU::X86EmitIndexPush(X86Reg srcreg, int32_t ofs) } -//--------------------------------------------------------------- -// Emits: -// pop dword ptr [ + ] -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitIndexPop(X86Reg srcreg, int32_t ofs) -{ - STANDARD_VM_CONTRACT; - - if(srcreg != kESP_Unsafe) - X86EmitOffsetModRM(0x8f, (X86Reg)0x0, srcreg, ofs); - else - X86EmitOp(0x8f,(X86Reg)0x0, srcreg, ofs); - - Pop(sizeof(void*)); -} - - //--------------------------------------------------------------- // Emits: // add esp, IMM @@ -1033,24 +1000,6 @@ VOID StubLinkerCPU::X64EmitMovXmmXmm(X86Reg destXmmreg, X86Reg srcXmmReg) X86EmitR2ROp(X86_INSTR_MOVAPS_R_RM, destXmmreg, srcXmmReg, k32BitOp); } -//--------------------------------------------------------------- -// movdqa XmmN, [baseReg + offset] -//--------------------------------------------------------------- -VOID StubLinkerCPU::X64EmitMovdqaFromMem(X86Reg Xmmreg, X86Reg baseReg, int32_t ofs) -{ - STANDARD_VM_CONTRACT; - X64EmitMovXmmWorker(0x66, 0x6F, Xmmreg, baseReg, ofs); -} - -//--------------------------------------------------------------- -// movdqa [baseReg + offset], XmmN -//--------------------------------------------------------------- -VOID StubLinkerCPU::X64EmitMovdqaToMem(X86Reg Xmmreg, X86Reg baseReg, int32_t ofs) -{ - STANDARD_VM_CONTRACT; - X64EmitMovXmmWorker(0x66, 0x7F, Xmmreg, baseReg, ofs); -} - //--------------------------------------------------------------- // movsd XmmN, [baseReg + offset] //--------------------------------------------------------------- @@ -1260,60 +1209,6 @@ VOID StubLinkerCPU::X86EmitOffsetModRM(BYTE opcode, X86Reg opcodereg, X86Reg ind } } -//--------------------------------------------------------------- -// Emits a MOD/RM for accessing a dword at [ + * + ofs32] -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitOffsetModRmSIB(BYTE opcode, X86Reg opcodeOrReg, X86Reg baseReg, X86Reg indexReg, int32_t scale, int32_t ofs) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION(scale == 1 || scale == 2 || scale == 4 || scale == 8); - PRECONDITION(indexReg != kESP_Unsafe); - } - CONTRACTL_END; - - BYTE codeBuffer[8]; - BYTE* code = codeBuffer; - int nBytes = 0; - -#ifdef TARGET_AMD64 - _ASSERTE(!"NYI"); -#endif - code[0] = opcode; - nBytes++; - - BYTE scaleEnc = 0; - switch(scale) - { - case 1: scaleEnc = 0; break; - case 2: scaleEnc = 1; break; - case 4: scaleEnc = 2; break; - case 8: scaleEnc = 3; break; - default: _ASSERTE(!"Unexpected"); - } - - BYTE sib = static_cast((scaleEnc << 6) | (indexReg << 3) | baseReg); - - if (FitsInI1(ofs)) - { - code[1] = static_cast(0x44 | (opcodeOrReg << 3)); - code[2] = sib; - code[3] = (BYTE)ofs; - nBytes += 3; - EmitBytes(codeBuffer, nBytes); - } - else - { - code[1] = static_cast(0x84 | (opcodeOrReg << 3)); - code[2] = sib; - *(int32_t*)(&code[3]) = ofs; - nBytes += 6; - EmitBytes(codeBuffer, nBytes); - } -} - - VOID StubLinkerCPU::X86EmitRegLoad(X86Reg reg, UINT_PTR imm) { diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index bc90a14d52c956..7c56dbee4469cc 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -22,22 +22,11 @@ extern PCODE GetPreStubEntryPoint(); #define X86_INSTR_MOV_EAX_ECX_IND 0x018b // mov eax, [ecx] #define X86_INSTR_CMP_IND_ECX_IMM32 0x3981 // cmp [ecx], imm32 -#define X86_INSTR_MOV_AL 0xB0 // mov al, imm8 -#define X86_INSTR_JMP_REL8 0xEB // jmp short rel8 - -#define X86_INSTR_NOP 0x90 // nop #define X86_INSTR_NOP3_1 0x9090 // 1st word of 3-byte nop #define X86_INSTR_NOP3_3 0x90 // 3rd byte of 3-byte nop #define X86_INSTR_INT3 0xCC // int 3 -#define X86_INSTR_HLT 0xF4 // hlt #define X86_INSTR_MOVAPS_R_RM 0x280F // movaps xmm1, xmm2/mem128 -#define X86_INSTR_MOVAPS_RM_R 0x290F // movaps xmm1/mem128, xmm2 -#define X86_INSTR_MOVLPS_R_RM 0x120F // movlps xmm1, xmm2/mem128 -#define X86_INSTR_MOVLPS_RM_R 0x130F // movlps xmm1/mem128, xmm2 -#define X86_INSTR_MOVUPS_R_RM 0x100F // movups xmm1, xmm2/mem128 -#define X86_INSTR_MOVUPS_RM_R 0x110F // movups xmm1/mem128, xmm2 -#define X86_INSTR_XORPS 0x570F // xorps xmm1, xmm2/mem128 //---------------------------------------------------------------------- // Encodes X86 registers. The numbers are chosen to match Intel's opcode @@ -133,8 +122,6 @@ class StubLinkerCPU : public StubLinker #ifdef TARGET_AMD64 VOID X64EmitMovXmmXmm(X86Reg destXmmreg, X86Reg srcXmmReg); - VOID X64EmitMovdqaFromMem(X86Reg Xmmreg, X86Reg baseReg, int32_t ofs = 0); - VOID X64EmitMovdqaToMem(X86Reg Xmmreg, X86Reg baseReg, int32_t ofs = 0); VOID X64EmitMovSDFromMem(X86Reg Xmmreg, X86Reg baseReg, int32_t ofs = 0); VOID X64EmitMovSDToMem(X86Reg Xmmreg, X86Reg baseReg, int32_t ofs = 0); VOID X64EmitMovSSFromMem(X86Reg Xmmreg, X86Reg baseReg, int32_t ofs = 0); @@ -147,10 +134,8 @@ class StubLinkerCPU : public StubLinker #endif VOID X86EmitZeroOutReg(X86Reg reg); - VOID X86EmitJumpReg(X86Reg reg); VOID X86EmitOffsetModRM(BYTE opcode, X86Reg altreg, X86Reg indexreg, int32_t ofs); - VOID X86EmitOffsetModRmSIB(BYTE opcode, X86Reg opcodeOrReg, X86Reg baseReg, X86Reg indexReg, int32_t scale, int32_t ofs); VOID X86EmitNearJump(CodeLabel *pTarget); @@ -158,7 +143,6 @@ class StubLinkerCPU : public StubLinker VOID X86EmitIndexRegStore(X86Reg dstreg, int32_t ofs, X86Reg srcreg); VOID X86EmitIndexPush(X86Reg srcreg, int32_t ofs); - VOID X86EmitIndexPop(X86Reg srcreg, int32_t ofs); VOID X86EmitAddEsp(INT32 imm32); VOID X86EmitEspOffset(BYTE opcode, From 5157e1e243ae72e01d41bde459923c575d1d7774 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Wed, 4 Jun 2025 11:10:22 +0200 Subject: [PATCH 02/11] Remove more dead code --- src/coreclr/vm/i386/stublinkerx86.cpp | 535 -------------------------- 1 file changed, 535 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index 45f8e2bb78a97e..afba5f8b5ea31b 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -54,272 +54,6 @@ BOOL IsPreservedReg (X86Reg reg) #endif // TARGET_AMD64 -#ifdef TARGET_AMD64 -//----------------------------------------------------------------------- -// InstructionFormat for near Jump and short Jump -//----------------------------------------------------------------------- - -//X64EmitTailcallWithRSPAdjust -class X64NearJumpSetup : public InstructionFormat -{ - public: - X64NearJumpSetup() : InstructionFormat( InstructionFormat::k8|InstructionFormat::k32 - | InstructionFormat::k64Small | InstructionFormat::k64 - ) - { - LIMITED_METHOD_CONTRACT; - } - - virtual UINT GetSizeOfInstruction(UINT refsize, UINT variationCode) - { - LIMITED_METHOD_CONTRACT - switch (refsize) - { - case k8: - return 0; - - case k32: - return 0; - - case k64Small: - return 5; - - case k64: - return 10; - - default: - _ASSERTE(!"unexpected refsize"); - return 0; - - } - } - - virtual VOID EmitInstruction(UINT refsize, int64_t fixedUpReference, BYTE *pOutBufferRX, BYTE *pOutBufferRW, UINT variationCode, BYTE *pDataBuffer) - { - LIMITED_METHOD_CONTRACT - if (k8 == refsize) - { - // do nothing, X64NearJump will take care of this - } - else if (k32 == refsize) - { - // do nothing, X64NearJump will take care of this - } - else if (k64Small == refsize) - { - UINT64 TargetAddress = (INT64)pOutBufferRX + fixedUpReference + GetSizeOfInstruction(refsize, variationCode); - _ASSERTE(FitsInU4(TargetAddress)); - - // mov eax, imm32 ; zero-extended - pOutBufferRW[0] = 0xB8; - *((UINT32*)&pOutBufferRW[1]) = (UINT32)TargetAddress; - } - else if (k64 == refsize) - { - // mov rax, imm64 - pOutBufferRW[0] = REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT; - pOutBufferRW[1] = 0xB8; - *((UINT64*)&pOutBufferRW[2]) = (UINT64)(((INT64)pOutBufferRX) + fixedUpReference + GetSizeOfInstruction(refsize, variationCode)); - } - else - { - _ASSERTE(!"unreached"); - } - } - - virtual BOOL CanReach(UINT refsize, UINT variationCode, BOOL fExternal, INT_PTR offset) - { - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_FORBID_FAULT; - - - if (fExternal) - { - switch (refsize) - { - case InstructionFormat::k8: - // For external, we don't have enough info to predict - // the offset. - return FALSE; - - case InstructionFormat::k32: - return sizeof(PVOID) <= sizeof(UINT32); - - case InstructionFormat::k64Small: - return FitsInI4(offset); - - case InstructionFormat::k64: - // intentional fallthru - case InstructionFormat::kAllowAlways: - return TRUE; - - default: - _ASSERTE(0); - return FALSE; - } - } - else - { - switch (refsize) - { - case InstructionFormat::k8: - return FitsInI1(offset); - - case InstructionFormat::k32: - return FitsInI4(offset); - - case InstructionFormat::k64Small: - // EmitInstruction emits a non-relative jmp for - // k64Small. We don't have enough info to predict the - // target address. (Even if we did, this would only - // handle the set of unsigned offsets with bit 31 set - // and no higher bits set, too uncommon/hard to test.) - return FALSE; - - case InstructionFormat::k64: - // intentional fallthru - case InstructionFormat::kAllowAlways: - return TRUE; - default: - _ASSERTE(0); - return FALSE; - } - } - } -}; - -class X64NearJumpExecute : public InstructionFormat -{ - public: - X64NearJumpExecute() : InstructionFormat( InstructionFormat::k8|InstructionFormat::k32 - | InstructionFormat::k64Small | InstructionFormat::k64 - ) - { - LIMITED_METHOD_CONTRACT; - } - - virtual UINT GetSizeOfInstruction(UINT refsize, UINT variationCode) - { - LIMITED_METHOD_CONTRACT - switch (refsize) - { - case k8: - return 2; - - case k32: - return 5; - - case k64Small: - return 3; - - case k64: - return 3; - - default: - _ASSERTE(!"unexpected refsize"); - return 0; - - } - } - - virtual VOID EmitInstruction(UINT refsize, int64_t fixedUpReference, BYTE *pOutBufferRX, BYTE *pOutBufferRW, UINT variationCode, BYTE *pDataBuffer) - { - LIMITED_METHOD_CONTRACT - if (k8 == refsize) - { - pOutBufferRW[0] = 0xeb; - *((int8_t*)(pOutBufferRW+1)) = (int8_t)fixedUpReference; - } - else if (k32 == refsize) - { - pOutBufferRW[0] = 0xe9; - *((int32_t*)(pOutBufferRW+1)) = (int32_t)fixedUpReference; - } - else if (k64Small == refsize) - { - // REX.W jmp rax - pOutBufferRW[0] = REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT; - pOutBufferRW[1] = 0xFF; - pOutBufferRW[2] = 0xE0; - } - else if (k64 == refsize) - { - // REX.W jmp rax - pOutBufferRW[0] = REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT; - pOutBufferRW[1] = 0xFF; - pOutBufferRW[2] = 0xE0; - } - else - { - _ASSERTE(!"unreached"); - } - } - - virtual BOOL CanReach(UINT refsize, UINT variationCode, BOOL fExternal, INT_PTR offset) - { - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_FORBID_FAULT; - - - if (fExternal) - { - switch (refsize) - { - case InstructionFormat::k8: - // For external, we don't have enough info to predict - // the offset. - return FALSE; - - case InstructionFormat::k32: - return sizeof(PVOID) <= sizeof(UINT32); - - case InstructionFormat::k64Small: - return FitsInI4(offset); - - case InstructionFormat::k64: - // intentional fallthru - case InstructionFormat::kAllowAlways: - return TRUE; - - default: - _ASSERTE(0); - return FALSE; - } - } - else - { - switch (refsize) - { - case InstructionFormat::k8: - return FitsInI1(offset); - - case InstructionFormat::k32: - return FitsInI4(offset); - - case InstructionFormat::k64Small: - // EmitInstruction emits a non-relative jmp for - // k64Small. We don't have enough info to predict the - // target address. (Even if we did, this would only - // handle the set of unsigned offsets with bit 31 set - // and no higher bits set, too uncommon/hard to test.) - return FALSE; - - case InstructionFormat::k64: - // intentional fallthru - case InstructionFormat::kAllowAlways: - return TRUE; - default: - _ASSERTE(0); - return FALSE; - } - } - } -}; - -#endif - //----------------------------------------------------------------------- // InstructionFormat for near Jump and short Jump //----------------------------------------------------------------------- @@ -474,268 +208,7 @@ class X86NearJump : public InstructionFormat } }; - -//----------------------------------------------------------------------- -// InstructionFormat for near call. -//----------------------------------------------------------------------- -class X86Call : public InstructionFormat -{ - public: - X86Call () - : InstructionFormat( InstructionFormat::k32 -#ifdef TARGET_AMD64 - | InstructionFormat::k64Small | InstructionFormat::k64 -#endif // TARGET_AMD64 - ) - { - LIMITED_METHOD_CONTRACT; - } - - virtual UINT GetSizeOfInstruction(UINT refsize, UINT variationCode) - { - LIMITED_METHOD_CONTRACT; - - switch (refsize) - { - case k32: - return 5; - -#ifdef TARGET_AMD64 - case k64Small: - return 5 + 2; - - case k64: - return 10 + 2; -#endif // TARGET_AMD64 - - default: - _ASSERTE(!"unexpected refsize"); - return 0; - } - } - - virtual VOID EmitInstruction(UINT refsize, int64_t fixedUpReference, BYTE *pOutBufferRX, BYTE *pOutBufferRW, UINT variationCode, BYTE *pDataBuffer) - { - LIMITED_METHOD_CONTRACT - - switch (refsize) - { - case k32: - pOutBufferRW[0] = 0xE8; - *((int32_t*)(1+pOutBufferRW)) = (int32_t)fixedUpReference; - break; - -#ifdef TARGET_AMD64 - case k64Small: - UINT64 TargetAddress; - - TargetAddress = (INT64)pOutBufferRX + fixedUpReference + GetSizeOfInstruction(refsize, variationCode); - _ASSERTE(FitsInU4(TargetAddress)); - - // mov eax, ; zero-extends - pOutBufferRW[0] = 0xB8; - *((UINT32*)&pOutBufferRW[1]) = (UINT32)TargetAddress; - - // call rax - pOutBufferRW[5] = 0xff; - pOutBufferRW[6] = 0xd0; - break; - - case k64: - // mov rax, - pOutBufferRW[0] = REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT; - pOutBufferRW[1] = 0xB8; - *((UINT64*)&pOutBufferRW[2]) = (UINT64)(((INT64)pOutBufferRX) + fixedUpReference + GetSizeOfInstruction(refsize, variationCode)); - - // call rax - pOutBufferRW[10] = 0xff; - pOutBufferRW[11] = 0xd0; - break; -#endif // TARGET_AMD64 - - default: - _ASSERTE(!"unreached"); - break; - } - } - -// For x86, the default CanReach implementation will suffice. It only needs -// to handle k32. -#ifdef TARGET_AMD64 - virtual BOOL CanReach(UINT refsize, UINT variationCode, BOOL fExternal, INT_PTR offset) - { - if (fExternal) - { - switch (refsize) - { - case InstructionFormat::k32: - // For external, we don't have enough info to predict - // the offset. - return FALSE; - - case InstructionFormat::k64Small: - return FitsInI4(offset); - - case InstructionFormat::k64: - // intentional fallthru - case InstructionFormat::kAllowAlways: - return TRUE; - - default: - _ASSERTE(0); - return FALSE; - } - } - else - { - switch (refsize) - { - case InstructionFormat::k32: - return FitsInI4(offset); - - case InstructionFormat::k64Small: - // EmitInstruction emits a non-relative jmp for - // k64Small. We don't have enough info to predict the - // target address. (Even if we did, this would only - // handle the set of unsigned offsets with bit 31 set - // and no higher bits set, too uncommon/hard to test.) - return FALSE; - - case InstructionFormat::k64: - // intentional fallthru - case InstructionFormat::kAllowAlways: - return TRUE; - default: - _ASSERTE(0); - return FALSE; - } - } - } -#endif // TARGET_AMD64 -}; - - -//----------------------------------------------------------------------- -// InstructionFormat for push imm32. -//----------------------------------------------------------------------- -class X86PushImm32 : public InstructionFormat -{ - public: - X86PushImm32(UINT allowedSizes) : InstructionFormat(allowedSizes) - { - LIMITED_METHOD_CONTRACT; - } - - virtual UINT GetSizeOfInstruction(UINT refsize, UINT variationCode) - { - LIMITED_METHOD_CONTRACT; - - return 5; - } - - virtual VOID EmitInstruction(UINT refsize, int64_t fixedUpReference, BYTE *pOutBufferRX, BYTE *pOutBufferRW, UINT variationCode, BYTE *pDataBuffer) - { - LIMITED_METHOD_CONTRACT; - - pOutBufferRW[0] = 0x68; - // only support absolute pushimm32 of the label address. The fixedUpReference is - // the offset to the label from the current point, so add to get address - *((int32_t*)(1+pOutBufferRW)) = (int32_t)(fixedUpReference); - } -}; - -#if defined(TARGET_AMD64) -//----------------------------------------------------------------------- -// InstructionFormat for lea reg, [RIP relative]. -//----------------------------------------------------------------------- -class X64LeaRIP : public InstructionFormat -{ - public: - X64LeaRIP() : InstructionFormat(InstructionFormat::k64Small) - { - LIMITED_METHOD_CONTRACT; - } - - virtual UINT GetSizeOfInstruction(UINT refsize, UINT variationCode) - { - LIMITED_METHOD_CONTRACT; - - return 7; - } - - virtual BOOL CanReach(UINT refsize, UINT variationCode, BOOL fExternal, INT_PTR offset) - { - if (fExternal) - { - switch (refsize) - { - case InstructionFormat::k64Small: - // For external, we don't have enough info to predict - // the offset. - return FALSE; - - case InstructionFormat::k64: - // intentional fallthru - case InstructionFormat::kAllowAlways: - return TRUE; - - default: - _ASSERTE(0); - return FALSE; - } - } - else - { - switch (refsize) - { - case InstructionFormat::k64Small: - return FitsInI4(offset); - - case InstructionFormat::k64: - // intentional fallthru - case InstructionFormat::kAllowAlways: - return TRUE; - - default: - _ASSERTE(0); - return FALSE; - } - } - } - - virtual VOID EmitInstruction(UINT refsize, int64_t fixedUpReference, BYTE *pOutBufferRX, BYTE *pOutBufferRW, UINT variationCode, BYTE *pDataBuffer) - { - LIMITED_METHOD_CONTRACT; - - X86Reg reg = (X86Reg)variationCode; - BYTE rex = REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT; - - if (reg >= kR8) - { - rex |= REX_MODRM_REG_EXT; - reg = X86RegFromAMD64Reg(reg); - } - - pOutBufferRW[0] = rex; - pOutBufferRW[1] = 0x8D; - pOutBufferRW[2] = (BYTE)(0x05 | (reg << 3)); - // only support absolute pushimm32 of the label address. The fixedUpReference is - // the offset to the label from the current point, so add to get address - *((int32_t*)(3+pOutBufferRW)) = (int32_t)(fixedUpReference); - } -}; - -#endif // TARGET_AMD64 - -#if defined(TARGET_AMD64) -static BYTE gX64NearJumpSetup[sizeof(X64NearJumpSetup)]; -static BYTE gX64NearJumpExecute[sizeof(X64NearJumpExecute)]; -static BYTE gX64LeaRIP[sizeof(X64LeaRIP)]; -#endif - static BYTE gX86NearJump[sizeof(X86NearJump)]; -static BYTE gX86Call[sizeof(X86Call)]; -static BYTE gX86PushImm32[sizeof(X86PushImm32)]; /* static */ void StubLinkerCPU::Init() { @@ -747,14 +220,6 @@ static BYTE gX86PushImm32[sizeof(X86PushImm32)]; } CONTRACTL_END; new (gX86NearJump) X86NearJump(); - new (gX86Call) X86Call(); - new (gX86PushImm32) X86PushImm32(InstructionFormat::k32); - -#if defined(TARGET_AMD64) - new (gX64NearJumpSetup) X64NearJumpSetup(); - new (gX64NearJumpExecute) X64NearJumpExecute(); - new (gX64LeaRIP) X64LeaRIP(); -#endif } //--------------------------------------------------------------- From a82436f6d6c8b4653f3436353b9e7937fc636aa9 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Wed, 4 Jun 2025 11:13:03 +0200 Subject: [PATCH 03/11] Remove IsPreservedReg --- src/coreclr/vm/i386/stublinkerx86.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index afba5f8b5ea31b..55a4116b28c832 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -35,25 +35,6 @@ #ifndef DACCESS_COMPILE - -#ifdef TARGET_AMD64 - -BOOL IsPreservedReg (X86Reg reg) -{ - UINT16 PreservedRegMask = - (1 << kRBX) - | (1 << kRBP) - | (1 << kRSI) - | (1 << kRDI) - | (1 << kR12) - | (1 << kR13) - | (1 << kR14) - | (1 << kR15); - return PreservedRegMask & (1 << reg); -} - -#endif // TARGET_AMD64 - //----------------------------------------------------------------------- // InstructionFormat for near Jump and short Jump //----------------------------------------------------------------------- From 8d4c8aeba3fb1ba6ada9e98a22e966316acc8a20 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Wed, 4 Jun 2025 11:16:51 +0200 Subject: [PATCH 04/11] Restrict X86NearJump to X86 --- src/coreclr/vm/i386/stublinkerx86.cpp | 71 ++++----------------------- src/coreclr/vm/i386/stublinkerx86.h | 2 + 2 files changed, 11 insertions(+), 62 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index 55a4116b28c832..a9148d8ba19061 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -35,17 +35,14 @@ #ifndef DACCESS_COMPILE +#ifdef TARGET_X86 //----------------------------------------------------------------------- // InstructionFormat for near Jump and short Jump //----------------------------------------------------------------------- class X86NearJump : public InstructionFormat { public: - X86NearJump() : InstructionFormat( InstructionFormat::k8|InstructionFormat::k32 -#ifdef TARGET_AMD64 - | InstructionFormat::k64Small | InstructionFormat::k64 -#endif // TARGET_AMD64 - ) + X86NearJump() : InstructionFormat(InstructionFormat::k8|InstructionFormat::k32) { LIMITED_METHOD_CONTRACT; } @@ -60,13 +57,7 @@ class X86NearJump : public InstructionFormat case k32: return 5; -#ifdef TARGET_AMD64 - case k64Small: - return 5 + 2; - case k64: - return 12; -#endif // TARGET_AMD64 default: _ASSERTE(!"unexpected refsize"); return 0; @@ -87,32 +78,6 @@ class X86NearJump : public InstructionFormat pOutBufferRW[0] = 0xe9; *((int32_t*)(pOutBufferRW+1)) = (int32_t)fixedUpReference; } -#ifdef TARGET_AMD64 - else if (k64Small == refsize) - { - UINT64 TargetAddress = (INT64)pOutBufferRX + fixedUpReference + GetSizeOfInstruction(refsize, variationCode); - _ASSERTE(FitsInU4(TargetAddress)); - - // mov eax, imm32 ; zero-extended - pOutBufferRW[0] = 0xB8; - *((UINT32*)&pOutBufferRW[1]) = (UINT32)TargetAddress; - - // jmp rax - pOutBufferRW[5] = 0xFF; - pOutBufferRW[6] = 0xE0; - } - else if (k64 == refsize) - { - // mov rax, imm64 - pOutBufferRW[0] = REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT; - pOutBufferRW[1] = 0xB8; - *((UINT64*)&pOutBufferRW[2]) = (UINT64)(((INT64)pOutBufferRX) + fixedUpReference + GetSizeOfInstruction(refsize, variationCode)); - - // jmp rax - pOutBufferRW[10] = 0xFF; - pOutBufferRW[11] = 0xE0; - } -#endif // TARGET_AMD64 else { _ASSERTE(!"unreached"); @@ -138,13 +103,6 @@ class X86NearJump : public InstructionFormat case InstructionFormat::k32: return sizeof(PVOID) <= sizeof(UINT32); -#ifdef TARGET_AMD64 - case InstructionFormat::k64Small: - return FitsInI4(offset); - - case InstructionFormat::k64: - // intentional fallthru -#endif case InstructionFormat::kAllowAlways: return TRUE; @@ -161,26 +119,9 @@ class X86NearJump : public InstructionFormat return FitsInI1(offset); case InstructionFormat::k32: -#ifdef TARGET_AMD64 - return FitsInI4(offset); -#else - return TRUE; -#endif - -#ifdef TARGET_AMD64 - case InstructionFormat::k64Small: - // EmitInstruction emits a non-relative jmp for - // k64Small. We don't have enough info to predict the - // target address. (Even if we did, this would only - // handle the set of unsigned offsets with bit 31 set - // and no higher bits set, too uncommon/hard to test.) - return FALSE; - - case InstructionFormat::k64: - // intentional fallthru -#endif case InstructionFormat::kAllowAlways: return TRUE; + default: _ASSERTE(0); return FALSE; @@ -190,6 +131,7 @@ class X86NearJump : public InstructionFormat }; static BYTE gX86NearJump[sizeof(X86NearJump)]; +#endif // TARGET_X86 /* static */ void StubLinkerCPU::Init() { @@ -200,7 +142,10 @@ static BYTE gX86NearJump[sizeof(X86NearJump)]; INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END; + +#ifdef TARGET_X86 new (gX86NearJump) X86NearJump(); +#endif } //--------------------------------------------------------------- @@ -304,6 +249,7 @@ VOID StubLinkerCPU::X86EmitZeroOutReg(X86Reg reg) } +#ifdef TARGET_X86 //--------------------------------------------------------------- // Emits: // JMP or @@ -314,6 +260,7 @@ VOID StubLinkerCPU::X86EmitNearJump(CodeLabel *target) STANDARD_VM_CONTRACT; EmitLabelRef(target, reinterpret_cast(gX86NearJump), 0); } +#endif // TARGET_X86 //--------------------------------------------------------------- diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index 7c56dbee4469cc..813af3c2797895 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -137,7 +137,9 @@ class StubLinkerCPU : public StubLinker VOID X86EmitOffsetModRM(BYTE opcode, X86Reg altreg, X86Reg indexreg, int32_t ofs); +#ifdef TARGET_X86 VOID X86EmitNearJump(CodeLabel *pTarget); +#endif VOID X86EmitIndexRegLoad(X86Reg dstreg, X86Reg srcreg, int32_t ofs = 0); VOID X86EmitIndexRegStore(X86Reg dstreg, int32_t ofs, X86Reg srcreg); From 1c7c810038279920116b244ed92acc734145f0e4 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Wed, 4 Jun 2025 11:32:08 +0200 Subject: [PATCH 05/11] Add #ifdef TARGET_X86 to header file for consistency --- src/coreclr/vm/i386/stublinkerx86.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index 813af3c2797895..1090ab0660ef24 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -115,10 +115,12 @@ class StubLinkerCPU : public StubLinker VOID X86EmitMovRegReg(X86Reg destReg, X86Reg srcReg); +#ifdef TARGET_X86 VOID X86EmitPushReg(X86Reg reg); VOID X86EmitPopReg(X86Reg reg); VOID X86EmitPushImm32(UINT value); VOID X86EmitPushImmPtr(LPVOID value BIT64_ARG(X86Reg tmpReg = kR10)); +#endif #ifdef TARGET_AMD64 VOID X64EmitMovXmmXmm(X86Reg destXmmreg, X86Reg srcXmmReg); From 9ef81952f13d62ac47d63257fdba09ce835a28e6 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Wed, 4 Jun 2025 11:36:23 +0200 Subject: [PATCH 06/11] Remove X86EmitDebugTrashReg --- src/coreclr/vm/i386/stublinkerx86.cpp | 27 --------------------------- src/coreclr/vm/i386/stublinkerx86.h | 4 ---- 2 files changed, 31 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index a9148d8ba19061..c010570fbefb99 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -927,33 +927,6 @@ VOID StubLinkerCPU::X86EmitEspOffset(BYTE opcode, } -#ifdef _DEBUG -//--------------------------------------------------------------- -// Emits: -// mov ,0xcccccccc -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitDebugTrashReg(X86Reg reg) -{ - STANDARD_VM_CONTRACT; - -#ifdef TARGET_AMD64 - BYTE rex = REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT; - - if (reg >= kR8) - { - rex |= REX_OPCODE_REG_EXT; - reg = X86RegFromAMD64Reg(reg); - } - Emit8(rex); - Emit8(0xb8|reg); - Emit64(0xcccccccccccccccc); -#else - Emit8(static_cast(0xb8 | reg)); - Emit32(0xcccccccc); -#endif -} -#endif //_DEBUG - // Get X86Reg indexes of argument registers based on offset into ArgumentRegister X86Reg GetX86ArgumentRegisterFromOffset(size_t ofs) diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index 1090ab0660ef24..174f50260c6c16 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -243,10 +243,6 @@ class StubLinkerCPU : public StubLinker // Emits code to adjust for a static delegate target. VOID EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray); -#ifdef _DEBUG - VOID X86EmitDebugTrashReg(X86Reg reg); -#endif - public: static void Init(); From 29ca2ed7a611b8734c75138ef0f2717b865e9a76 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Thu, 5 Jun 2025 16:04:32 +0200 Subject: [PATCH 07/11] Inline both usages of X86EmitR2ROp --- src/coreclr/vm/i386/stublinkerx86.cpp | 87 +++++++-------------------- src/coreclr/vm/i386/stublinkerx86.h | 19 ------ 2 files changed, 23 insertions(+), 83 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index c010570fbefb99..25809f367302cc 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -388,9 +388,29 @@ VOID StubLinkerCPU::X86EmitAddReg(X86Reg reg, INT32 imm32) VOID StubLinkerCPU::X64EmitMovXmmXmm(X86Reg destXmmreg, X86Reg srcXmmReg) { STANDARD_VM_CONTRACT; + // There are several that could be used to mov xmm registers. MovAps is // what C++ compiler uses so let's use it here too. - X86EmitR2ROp(X86_INSTR_MOVAPS_R_RM, destXmmreg, srcXmmReg, k32BitOp); + + BYTE rex = 0; + + if (srcXmmReg >= kR8) + { + rex |= REX_MODRM_RM_EXT; + srcXmmReg = X86RegFromAMD64Reg(srcXmmReg); + } + + if (destXmmreg >= kR8) + { + rex |= REX_MODRM_REG_EXT; + destXmmreg = X86RegFromAMD64Reg(destXmmreg); + } + + if (rex) + Emit8(REX_PREFIX_BASE | rex); + + Emit16(X86_INSTR_MOVAPS_R_RM); + Emit8(static_cast(0300 | (destXmmreg << 3) | srcXmmReg)); } //--------------------------------------------------------------- @@ -800,68 +820,6 @@ VOID StubLinkerCPU::X86EmitOp(WORD opcode, } -// Emits -// -// opcode altreg, modrmreg -// -// or -// -// opcode modrmreg, altreg -// -// (the opcode determines which one comes first) -// -// For single-operand opcodes, "altreg" actually selects -// an operation rather than a register. - -VOID StubLinkerCPU::X86EmitR2ROp (WORD opcode, - X86Reg altreg, - X86Reg modrmreg - AMD64_ARG(X86OperandSize OperandSize /*= k64BitOp*/) - ) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - - // All 2-byte opcodes start with 0x0f. - PRECONDITION(!(opcode >> 8) || (opcode & 0xff) == 0x0f); - - PRECONDITION( ((UINT)altreg) < NumX86Regs ); - PRECONDITION( ((UINT)modrmreg) < NumX86Regs ); - } - CONTRACTL_END; - -#ifdef TARGET_AMD64 - BYTE rex = 0; - - if (modrmreg >= kR8) - { - rex |= REX_MODRM_RM_EXT; - modrmreg = X86RegFromAMD64Reg(modrmreg); - } - - if (altreg >= kR8) - { - rex |= REX_MODRM_REG_EXT; - altreg = X86RegFromAMD64Reg(altreg); - } - - if (k64BitOp == OperandSize) - rex |= REX_OPERAND_SIZE_64BIT; - - if (rex) - Emit8(REX_PREFIX_BASE | rex); -#endif // TARGET_AMD64 - - Emit8((BYTE)opcode); - - if (opcode >> 8) - Emit8(opcode >> 8); - - Emit8(static_cast(0300 | (altreg << 3) | modrmreg)); -} - - //--------------------------------------------------------------- // Emits: // op altreg, [esp+ofs] @@ -1308,7 +1266,8 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) X86EmitAddReg(kR11, DelegateObject::GetOffsetOfMethodPtrAux()); // Now jump to real target // jmp r10 - X86EmitR2ROp(0xff, (X86Reg)4, kR10); + static const BYTE bjmpr10[] = { 0x41, 0xff, 0xe2 }; + EmitBytes(bjmpr10, sizeof(bjmpr10)); #else // TARGET_AMD64 diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index 174f50260c6c16..efdf84ed12af51 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -197,25 +197,6 @@ class StubLinkerCPU : public StubLinker } #endif // TARGET_AMD64 - // Emits - // - // opcode altreg, modrmreg - // - // or - // - // opcode modrmreg, altreg - // - // (the opcode determines which one comes first) - // - // For single-operand opcodes, "altreg" actually selects - // an operation rather than a register. - - VOID X86EmitR2ROp(WORD opcode, - X86Reg altreg, - X86Reg modrmreg - AMD64_ARG(X86OperandSize OperandSize = k64BitOp) - ); - VOID X86EmitRegLoad(X86Reg reg, UINT_PTR imm); VOID X86_64BitOperands () From 8f19027f10445c9436a35a518021e2b699d8e027 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Thu, 5 Jun 2025 16:09:13 +0200 Subject: [PATCH 08/11] Inline the value of X86_INSTR_MOVAPS_R_RM --- src/coreclr/vm/i386/stublinkerx86.cpp | 4 ++-- src/coreclr/vm/i386/stublinkerx86.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index 25809f367302cc..e1099e0a0b91c7 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -383,7 +383,7 @@ VOID StubLinkerCPU::X86EmitAddReg(X86Reg reg, INT32 imm32) #if defined(TARGET_AMD64) //--------------------------------------------------------------- -// movdqa destXmmreg, srcXmmReg +// movaps destXmmreg, srcXmmReg //--------------------------------------------------------------- VOID StubLinkerCPU::X64EmitMovXmmXmm(X86Reg destXmmreg, X86Reg srcXmmReg) { @@ -409,7 +409,7 @@ VOID StubLinkerCPU::X64EmitMovXmmXmm(X86Reg destXmmreg, X86Reg srcXmmReg) if (rex) Emit8(REX_PREFIX_BASE | rex); - Emit16(X86_INSTR_MOVAPS_R_RM); + Emit16(0x280F); Emit8(static_cast(0300 | (destXmmreg << 3) | srcXmmReg)); } diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index efdf84ed12af51..bfc0f8f43f55e4 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -26,8 +26,6 @@ extern PCODE GetPreStubEntryPoint(); #define X86_INSTR_NOP3_3 0x90 // 3rd byte of 3-byte nop #define X86_INSTR_INT3 0xCC // int 3 -#define X86_INSTR_MOVAPS_R_RM 0x280F // movaps xmm1, xmm2/mem128 - //---------------------------------------------------------------------- // Encodes X86 registers. The numbers are chosen to match Intel's opcode // encoding. From d0aacef01cc7cf93cfcceea82a5e85dd2aa41323 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Thu, 5 Jun 2025 16:43:42 +0200 Subject: [PATCH 09/11] Remove kESP_Unsafe --- src/coreclr/vm/i386/stublinkerx86.cpp | 11 ++--------- src/coreclr/vm/i386/stublinkerx86.h | 6 ------ 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index e1099e0a0b91c7..ff74843c072034 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -290,10 +290,7 @@ VOID StubLinkerCPU::X86EmitIndexRegStore(X86Reg dstreg, { STANDARD_VM_CONTRACT; - if (dstreg != kESP_Unsafe) - X86EmitOffsetModRM(0x89, srcreg, dstreg, ofs); - else - X86EmitOp(0x89, srcreg, (X86Reg)kESP_Unsafe, ofs); + X86EmitOffsetModRM(0x89, srcreg, dstreg, ofs); } #ifdef TARGET_X86 @@ -305,11 +302,7 @@ VOID StubLinkerCPU::X86EmitIndexPush(X86Reg srcreg, int32_t ofs) { STANDARD_VM_CONTRACT; - if(srcreg != kESP_Unsafe) - X86EmitOffsetModRM(0xff, (X86Reg)0x6, srcreg, ofs); - else - X86EmitOp(0xff,(X86Reg)0x6, srcreg, ofs); - + X86EmitOffsetModRM(0xff, (X86Reg)0x6, srcreg, ofs); Push(sizeof(void*)); } diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index bfc0f8f43f55e4..f68ed703474c61 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -88,12 +88,6 @@ enum X86Reg : UCHAR }; -// Use this only if you are absolutely sure that the instruction format -// handles it. This is not declared as X86Reg so that users are forced -// to add a cast and think about what exactly they are doing. -const int kESP_Unsafe = 4; - - //---------------------------------------------------------------------- // StubLinker with extensions for generating X86 code. //---------------------------------------------------------------------- From 10db079a3801dbabf4b5c4051d9237cd30a95f52 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Thu, 5 Jun 2025 16:47:30 +0200 Subject: [PATCH 10/11] Remove X86EmitEspOffset on x64 --- src/coreclr/vm/i386/stublinkerx86.cpp | 40 +++++---------------------- src/coreclr/vm/i386/stublinkerx86.h | 6 ++-- 2 files changed, 10 insertions(+), 36 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index ff74843c072034..94cfedeee7c411 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -813,45 +813,19 @@ VOID StubLinkerCPU::X86EmitOp(WORD opcode, } +#ifdef TARGET_X86 //--------------------------------------------------------------- // Emits: // op altreg, [esp+ofs] //--------------------------------------------------------------- VOID StubLinkerCPU::X86EmitEspOffset(BYTE opcode, X86Reg altreg, - int32_t ofs - AMD64_ARG(X86OperandSize OperandSize /*= k64BitOp*/) - ) + int32_t ofs) { STANDARD_VM_CONTRACT; - BYTE codeBuffer[8]; + BYTE codeBuffer[7]; BYTE *code = codeBuffer; - int nBytes; - -#ifdef TARGET_AMD64 - BYTE rex = 0; - - if (k64BitOp == OperandSize) - rex |= REX_OPERAND_SIZE_64BIT; - - if (altreg >= kR8) - { - rex |= REX_MODRM_REG_EXT; - altreg = X86RegFromAMD64Reg(altreg); - } - - if (rex) - { - *code = (REX_PREFIX_BASE | rex); - code++; - nBytes = 1; - } - else -#endif // TARGET_AMD64 - { - nBytes = 0; - } code[0] = opcode; BYTE modrm = static_cast((altreg << 3) | 004); @@ -859,24 +833,24 @@ VOID StubLinkerCPU::X86EmitEspOffset(BYTE opcode, { code[1] = modrm; code[2] = 0044; - EmitBytes(codeBuffer, 3 + nBytes); + EmitBytes(codeBuffer, 3); } else if (FitsInI1(ofs)) { code[1] = 0x40|modrm; code[2] = 0044; code[3] = (BYTE)ofs; - EmitBytes(codeBuffer, 4 + nBytes); + EmitBytes(codeBuffer, 4); } else { code[1] = 0x80|modrm; code[2] = 0044; *((int32_t*)(3+code)) = ofs; - EmitBytes(codeBuffer, 7 + nBytes); + EmitBytes(codeBuffer, 7); } - } +#endif // Get X86Reg indexes of argument registers based on offset into ArgumentRegister diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index f68ed703474c61..9e26cae5bbc9f2 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -141,11 +141,11 @@ class StubLinkerCPU : public StubLinker VOID X86EmitIndexPush(X86Reg srcreg, int32_t ofs); VOID X86EmitAddEsp(INT32 imm32); +#ifdef TARGET_X86 VOID X86EmitEspOffset(BYTE opcode, X86Reg altreg, - int32_t ofs - AMD64_ARG(X86OperandSize OperandSize = k64BitOp) - ); + int32_t ofs); +#endif // Emits the most efficient form of the operation: // From b7aeedee7b97cc75ccc0e44244709f546e6980e2 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Fri, 6 Jun 2025 05:59:22 +0200 Subject: [PATCH 11/11] Address PR feedback --- src/coreclr/vm/i386/stublinkerx86.cpp | 29 --------------------------- src/coreclr/vm/i386/stublinkerx86.h | 4 +--- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index 94cfedeee7c411..a6238f46e797fc 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -225,31 +225,8 @@ VOID StubLinkerCPU::X86EmitPushImmPtr(LPVOID value BIT64_ARG(X86Reg tmpReg /*=kR X86EmitPushImm32((UINT_PTR) value); } -#endif // TARGET_X86 - -//--------------------------------------------------------------- -// Emits: -// XOR , -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitZeroOutReg(X86Reg reg) -{ - STANDARD_VM_CONTRACT; - -#ifdef TARGET_AMD64 - // 32-bit results are zero-extended, so we only need the REX byte if - // it's an extended register. - if (reg >= kR8) - { - Emit8(REX_PREFIX_BASE | REX_MODRM_REG_EXT | REX_MODRM_RM_EXT); - reg = X86RegFromAMD64Reg(reg); - } -#endif - Emit8(0x33); - Emit8(static_cast(0xc0 | (reg << 3) | reg)); -} -#ifdef TARGET_X86 //--------------------------------------------------------------- // Emits: // JMP or @@ -620,12 +597,6 @@ VOID StubLinkerCPU::X86EmitRegLoad(X86Reg reg, UINT_PTR imm) { STANDARD_VM_CONTRACT; - if (!imm) - { - X86EmitZeroOutReg(reg); - return; - } - UINT cbimm = sizeof(void*); #ifdef TARGET_AMD64 diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index 9e26cae5bbc9f2..9547cab0746e11 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -127,8 +127,6 @@ class StubLinkerCPU : public StubLinker VOID X64EmitMovqWorker(BYTE opcode, X86Reg Xmmreg, X86Reg reg); #endif - VOID X86EmitZeroOutReg(X86Reg reg); - VOID X86EmitOffsetModRM(BYTE opcode, X86Reg altreg, X86Reg indexreg, int32_t ofs); #ifdef TARGET_X86 @@ -138,10 +136,10 @@ class StubLinkerCPU : public StubLinker VOID X86EmitIndexRegLoad(X86Reg dstreg, X86Reg srcreg, int32_t ofs = 0); VOID X86EmitIndexRegStore(X86Reg dstreg, int32_t ofs, X86Reg srcreg); +#ifdef TARGET_X86 VOID X86EmitIndexPush(X86Reg srcreg, int32_t ofs); VOID X86EmitAddEsp(INT32 imm32); -#ifdef TARGET_X86 VOID X86EmitEspOffset(BYTE opcode, X86Reg altreg, int32_t ofs);