Skip to content

Commit

Permalink
Remove the JIT-ed CPUID hack from mono-hwcap-x86.
Browse files Browse the repository at this point in the history
A proper workaround for the 32-bit PIC issue exists: Using xchg to
unclobber EBX which is used by the compiler. This means we can just
use inline assembly to issue the instruction, eliminating the hack
where we JIT-compiled a function to do the CPUID.

This patch also makes it so that we use MSVC's __cpuid intrinsic
on both 32-bit and 64-bit x86 since it's available on both.
  • Loading branch information
Alex Rønne Petersen committed Jul 20, 2013
1 parent 08d4170 commit 24c84e6
Showing 1 changed file with 29 additions and 110 deletions.
139 changes: 29 additions & 110 deletions mono/utils/mono-hwcap-x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,63 +24,8 @@
#include <unistd.h>
#endif

#if defined(TARGET_X86)
#include "mono/utils/mono-codeman.h"

typedef void (* CpuidFunc) (int id, int *p_eax, int *p_ebx, int *p_ecx, int *p_edx);

static MonoCodeManager *code_man;
static CpuidFunc func;

#if defined(__native_client__)
static const guchar cpuid_impl [] = {
0x55, /* push %ebp */
0x89, 0xe5, /* mov %esp, %ebp */
0x53, /* push %ebx */
0x8b, 0x45, 0x08, /* mov 0x8 (%ebp), %eax */
0x0f, 0xa2, /* cpuid */
0x50, /* push %eax */
0x8b, 0x45, 0x10, /* mov 0x10 (%ebp), %eax */
0x89, 0x18, /* mov %ebx, (%eax) */
0x8b, 0x45, 0x14, /* mov 0x14 (%ebp), %eax */
0x89, 0x08, /* mov %ecx, (%eax) */
0x8b, 0x45, 0x18, /* mov 0x18 (%ebp), %eax */
0x89, 0x10, /* mov %edx, (%eax) */
0x58, /* pop %eax */
0x8b, 0x55, 0x0c, /* mov 0xc (%ebp), %edx */
0x89, 0x02, /* mov %eax, (%edx) */
0x5b, /* pop %ebx */
0xc9, /* leave */
0x59, 0x83, 0xe1, 0xe0, 0xff, 0xe1, /* naclret */
0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, /* padding, to provide bundle aligned version */
0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
0xf4,
};
#else
static const guchar cpuid_impl [] = {
0x55, /* push %ebp */
0x89, 0xe5, /* mov %esp, %ebp */
0x53, /* push %ebx */
0x8b, 0x45, 0x08, /* mov 0x8 (%ebp), %eax */
0x0f, 0xa2, /* cpuid */
0x50, /* push %eax */
0x8b, 0x45, 0x10, /* mov 0x10 (%ebp), %eax */
0x89, 0x18, /* mov %ebx, (%eax) */
0x8b, 0x45, 0x14, /* mov 0x14 (%ebp), %eax */
0x89, 0x08, /* mov %ecx, (%eax) */
0x8b, 0x45, 0x18, /* mov 0x18 (%ebp), %eax */
0x89, 0x10, /* mov %edx, (%eax) */
0x58, /* pop %eax */
0x8b, 0x55, 0x0c, /* mov 0xc (%ebp), %edx */
0x89, 0x02, /* mov %eax, (%edx) */
0x5b, /* pop %ebx */
0xc9, /* leave */
0xc3, /* ret */
};
#endif

#if defined(_MSC_VER)
#include <intrin.h>
#endif

gboolean mono_hwcap_x86_is_xen = FALSE;
Expand All @@ -97,13 +42,8 @@ gboolean mono_hwcap_x86_has_sse4a = FALSE;
static gboolean
cpuid (int id, int *p_eax, int *p_ebx, int *p_ecx, int *p_edx)
{
/* First, make sure we can use cpuid if we're on 32-bit. */
#if defined(TARGET_X86)

#if defined(__native_client__)
func (id, p_eax, p_ebx, p_ecx, p_edx);

return TRUE;
#else
gboolean have_cpuid = FALSE;

#if defined(_MSC_VER)
Expand All @@ -122,77 +62,60 @@ cpuid (int id, int *p_eax, int *p_ebx, int *p_ecx, int *p_edx)
}
#else
__asm__ __volatile__ (
"pushfl\n"
"popl %%eax\n"
"movl %%eax, %%edx\n"
"xorl $0x200000, %%eax\n"
"pushl %%eax\n"
"popfl\n"
"pushfl\n"
"popl %%eax\n"
"xorl %%edx, %%eax\n"
"andl $0x200000, %%eax\n"
"movl %%eax, %0"
"pushfl\n\t"
"popl\t%%eax\n\t"
"movl\t%%eax, %%edx\n\t"
"xorl\t$0x200000, %%eax\n\t"
"pushl\t%%eax\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl\t%%eax\n\t"
"xorl\t%%edx, %%eax\n\t"
"andl\t$0x200000, %%eax\n\t"
"movl\t%%eax, %0\n\t"
: "=r" (have_cpuid)
:
: "%eax", "%edx"
);
#endif

if (have_cpuid) {
func (id, p_eax, p_ebx, p_ecx, p_edx);

return TRUE;
}

return FALSE;
if (!have_cpuid)
return FALSE;
#endif

#else

/* Now issue the actual cpuid instruction. We can use
MSVC's __cpuid on both 32-bit and 64-bit. */
#if defined(_MSC_VER)
int info [4];
__cpuid (info, id);
*p_eax = info [0];
*p_ebx = info [1];
*p_ecx = info [2];
*p_edx = info [3];
#elif defined(TARGET_X86)
/* This complicated stuff is necessary because EBX
may be used by the compiler in PIC mode. */
__asm__ __volatile__ (
"xchgl\t%%ebx, %k1\n\t"
"cpuid\n\t"
"xchgl\t%%ebx, %k1\n\t"
: "=a" (*p_eax), "=&r" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
: "0" (id)
);
#else
__asm__ __volatile__ (
"cpuid"
"cpuid\n\t"
: "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
: "a" (id)
);
#endif

return TRUE;
#endif
}

void
mono_hwcap_arch_init (void)
{
#if defined(TARGET_X86)
code_man = mono_code_manager_new ();

#if defined(__native_client__)
gpointer ptr = mono_code_manager_reserve (code_man, sizeof (cpuid_impl));
memcpy (ptr, cpuid_impl, sizeof (cpuid_impl));
gpointer end_ptr = ptr + sizeof (cpuid_impl);

guint8 *code = nacl_code_manager_get_dest (code_man, ptr);
mono_code_manager_commit (code_man, ptr, sizeof (cpuid_impl), end_ptr - ptr);

func = (CpuidFunc) code;
#else
gpointer ptr = mono_code_manager_reserve (code_man, sizeof (cpuid_impl));
memcpy (ptr, cpuid_impl, sizeof (cpuid_impl));

func = (CpuidFunc) ptr;
#endif

#endif

int eax, ebx, ecx, edx;

if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
Expand Down Expand Up @@ -231,10 +154,6 @@ mono_hwcap_arch_init (void)
}
}

#if defined(TARGET_X86)
mono_code_manager_destroy (code_man);
#endif

#if defined(HAVE_UNISTD_H)
mono_hwcap_x86_is_xen = !access ("/proc/xen", F_OK);
#endif
Expand Down

0 comments on commit 24c84e6

Please sign in to comment.