about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm/jitter/jitcore_llvm.py3
-rw-r--r--miasm/runtime/divti3.c36
-rw-r--r--miasm/runtime/export.h10
-rw-r--r--miasm/runtime/int_endianness.h114
-rw-r--r--miasm/runtime/int_lib.h148
-rw-r--r--miasm/runtime/int_types.h174
-rw-r--r--miasm/runtime/int_util.h31
-rw-r--r--miasm/runtime/udivmodti4.c196
-rw-r--r--miasm/runtime/udivti3.c24
-rw-r--r--setup.py57
-rwxr-xr-xtest/test_all.py3
11 files changed, 793 insertions, 3 deletions
diff --git a/miasm/jitter/jitcore_llvm.py b/miasm/jitter/jitcore_llvm.py
index 28fdec89..df7d5950 100644
--- a/miasm/jitter/jitcore_llvm.py
+++ b/miasm/jitter/jitcore_llvm.py
@@ -10,6 +10,9 @@ import miasm.jitter.jitcore as jitcore
 from miasm.jitter import Jitllvm
 import platform
 
+import llvmlite
+llvmlite.binding.load_library_permanently(Jitllvm.__file__)
+
 is_win = platform.system() == "Windows"
 
 class JitCore_LLVM(jitcore.JitCore):
diff --git a/miasm/runtime/divti3.c b/miasm/runtime/divti3.c
new file mode 100644
index 00000000..fc5c1b4d
--- /dev/null
+++ b/miasm/runtime/divti3.c
@@ -0,0 +1,36 @@
+/* ===-- divti3.c - Implement __divti3 -------------------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divti3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#if __x86_64
+
+#include "int_lib.h"
+#include "export.h"
+
+tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
+
+/* Returns: a / b */
+
+ti_int
+__divti3(ti_int a, ti_int b)
+{
+    const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
+    ti_int s_a = a >> bits_in_tword_m1;           /* s_a = a < 0 ? -1 : 0 */
+    ti_int s_b = b >> bits_in_tword_m1;           /* s_b = b < 0 ? -1 : 0 */
+    a = (a ^ s_a) - s_a;                         /* negate if s_a == -1 */
+    b = (b ^ s_b) - s_b;                         /* negate if s_b == -1 */
+    s_a ^= s_b;                                  /* sign of quotient */
+    return (__udivmodti4(a, b, (tu_int*)0) ^ s_a) - s_a;  /* negate if s_a == -1 */
+}
+
+#endif
diff --git a/miasm/runtime/export.h b/miasm/runtime/export.h
new file mode 100644
index 00000000..f21a83a8
--- /dev/null
+++ b/miasm/runtime/export.h
@@ -0,0 +1,10 @@
+#ifndef MIASM_RT_EXPORT_H
+#define MIASM_RT_EXPORT_H
+
+#ifdef _WIN32
+#define _MIASM_EXPORT __declspec(dllexport)
+#else
+#define _MIASM_EXPORT __attribute__((visibility("default")))
+#endif
+
+#endif
diff --git a/miasm/runtime/int_endianness.h b/miasm/runtime/int_endianness.h
new file mode 100644
index 00000000..def046c3
--- /dev/null
+++ b/miasm/runtime/int_endianness.h
@@ -0,0 +1,114 @@
+//===-- int_endianness.h - configuration header for compiler-rt -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a configuration header for compiler-rt.
+// This file is not part of the interface of this library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INT_ENDIANNESS_H
+#define INT_ENDIANNESS_H
+
+#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) &&                \
+    defined(__ORDER_LITTLE_ENDIAN__)
+
+// Clang and GCC provide built-in endianness definitions.
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif // __BYTE_ORDER__
+
+#else // Compilers other than Clang or GCC.
+
+#if defined(__SVR4) && defined(__sun)
+#include <sys/byteorder.h>
+
+#if defined(_BIG_ENDIAN)
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif defined(_LITTLE_ENDIAN)
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#else // !_LITTLE_ENDIAN
+#error "unknown endianness"
+#endif // !_LITTLE_ENDIAN
+
+#endif // Solaris and AuroraUX.
+
+// ..
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) ||   \
+    defined(__minix)
+#include <sys/endian.h>
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif // _BYTE_ORDER
+
+#endif // *BSD
+
+#if defined(__OpenBSD__)
+#include <machine/endian.h>
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif // _BYTE_ORDER
+
+#endif // OpenBSD
+
+// ..
+
+// Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the
+// compiler (at least with GCC)
+#if defined(__APPLE__) || defined(__ellcc__)
+
+#ifdef __BIG_ENDIAN__
+#if __BIG_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 1
+#endif
+#endif // __BIG_ENDIAN__
+
+#ifdef __LITTLE_ENDIAN__
+#if __LITTLE_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+#endif
+#endif // __LITTLE_ENDIAN__
+
+#endif // Mac OSX
+
+// ..
+
+#if defined(_WIN32)
+
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 0
+
+#endif // Windows
+
+#endif // Clang or GCC.
+
+// .
+
+#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN)
+#error Unable to determine endian
+#endif // Check we found an endianness correctly.
+
+#endif // INT_ENDIANNESS_H
diff --git a/miasm/runtime/int_lib.h b/miasm/runtime/int_lib.h
new file mode 100644
index 00000000..7f5eb799
--- /dev/null
+++ b/miasm/runtime/int_lib.h
@@ -0,0 +1,148 @@
+//===-- int_lib.h - configuration header for compiler-rt  -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a configuration header for compiler-rt.
+// This file is not part of the interface of this library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INT_LIB_H
+#define INT_LIB_H
+
+// Assumption: Signed integral is 2's complement.
+// Assumption: Right shift of signed negative is arithmetic shift.
+// Assumption: Endianness is little or big (not mixed).
+
+// ABI macro definitions
+
+#if __ARM_EABI__
+#ifdef COMPILER_RT_ARMHF_TARGET
+#define COMPILER_RT_ABI
+#else
+#define COMPILER_RT_ABI __attribute__((__pcs__("aapcs")))
+#endif
+#else
+#define COMPILER_RT_ABI
+#endif
+
+#define AEABI_RTABI __attribute__((__pcs__("aapcs")))
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define ALWAYS_INLINE __forceinline
+#define NOINLINE __declspec(noinline)
+#define NORETURN __declspec(noreturn)
+#define UNUSED
+#else
+#define ALWAYS_INLINE __attribute__((always_inline))
+#define NOINLINE __attribute__((noinline))
+#define NORETURN __attribute__((noreturn))
+#define UNUSED __attribute__((unused))
+#endif
+
+#define STR(a) #a
+#define XSTR(a) STR(a)
+#define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name
+
+#if defined(__ELF__) || defined(__MINGW32__) || defined(__wasm__)
+#define COMPILER_RT_ALIAS(name, aliasname) \
+  COMPILER_RT_ABI __typeof(name) aliasname __attribute__((__alias__(#name)));
+#elif defined(__APPLE__)
+#if defined(VISIBILITY_HIDDEN)
+#define COMPILER_RT_ALIAS_VISIBILITY(name) \
+  __asm__(".private_extern " SYMBOL_NAME(name));
+#else
+#define COMPILER_RT_ALIAS_VISIBILITY(name)
+#endif
+#define COMPILER_RT_ALIAS(name, aliasname) \
+  __asm__(".globl " SYMBOL_NAME(aliasname)); \
+  COMPILER_RT_ALIAS_VISIBILITY(aliasname) \
+  __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \
+  COMPILER_RT_ABI __typeof(name) aliasname;
+#elif defined(_WIN32)
+#define COMPILER_RT_ALIAS(name, aliasname)
+#else
+#error Unsupported target
+#endif
+
+#if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE))
+//
+// Kernel and boot environment can't use normal headers,
+// so use the equivalent system headers.
+//
+#include <machine/limits.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#else
+// Include the standard compiler builtin headers we use functionality from.
+#include <float.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#endif
+
+// Include the commonly used internal type definitions.
+#include "int_types.h"
+
+// Include internal utility function declarations.
+#include "int_util.h"
+
+COMPILER_RT_ABI si_int __paritysi2(si_int a);
+COMPILER_RT_ABI si_int __paritydi2(di_int a);
+
+COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b);
+COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b);
+COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d);
+
+COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int *rem);
+COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem);
+#ifdef CRT_HAS_128BIT
+COMPILER_RT_ABI si_int __clzti2(ti_int a);
+COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem);
+#endif
+
+// Definitions for builtins unavailable on MSVC
+#if defined(_MSC_VER) && !defined(__clang__)
+#include <intrin.h>
+
+uint32_t __inline __builtin_ctz(uint32_t value) {
+  unsigned long trailing_zero = 0;
+  if (_BitScanForward(&trailing_zero, value))
+    return trailing_zero;
+  return 32;
+}
+
+uint32_t __inline __builtin_clz(uint32_t value) {
+  unsigned long leading_zero = 0;
+  if (_BitScanReverse(&leading_zero, value))
+    return 31 - leading_zero;
+  return 32;
+}
+
+#if defined(_M_ARM) || defined(_M_X64)
+uint32_t __inline __builtin_clzll(uint64_t value) {
+  unsigned long leading_zero = 0;
+  if (_BitScanReverse64(&leading_zero, value))
+    return 63 - leading_zero;
+  return 64;
+}
+#else
+uint32_t __inline __builtin_clzll(uint64_t value) {
+  if (value == 0)
+    return 64;
+  uint32_t msh = (uint32_t)(value >> 32);
+  uint32_t lsh = (uint32_t)(value & 0xFFFFFFFF);
+  if (msh != 0)
+    return __builtin_clz(msh);
+  return 32 + __builtin_clz(lsh);
+}
+#endif
+
+#define __builtin_clzl __builtin_clzll
+#endif // defined(_MSC_VER) && !defined(__clang__)
+
+#endif // INT_LIB_H
diff --git a/miasm/runtime/int_types.h b/miasm/runtime/int_types.h
new file mode 100644
index 00000000..f89220d5
--- /dev/null
+++ b/miasm/runtime/int_types.h
@@ -0,0 +1,174 @@
+//===-- int_lib.h - configuration header for compiler-rt  -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is not part of the interface of this library.
+//
+// This file defines various standard types, most importantly a number of unions
+// used to access parts of larger types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INT_TYPES_H
+#define INT_TYPES_H
+
+#include "int_endianness.h"
+
+// si_int is defined in Linux sysroot's asm-generic/siginfo.h
+#ifdef si_int
+#undef si_int
+#endif
+typedef int si_int;
+typedef unsigned su_int;
+
+typedef long long di_int;
+typedef unsigned long long du_int;
+
+typedef union {
+  di_int all;
+  struct {
+#if _YUGA_LITTLE_ENDIAN
+    su_int low;
+    si_int high;
+#else
+    si_int high;
+    su_int low;
+#endif // _YUGA_LITTLE_ENDIAN
+  } s;
+} dwords;
+
+typedef union {
+  du_int all;
+  struct {
+#if _YUGA_LITTLE_ENDIAN
+    su_int low;
+    su_int high;
+#else
+    su_int high;
+    su_int low;
+#endif // _YUGA_LITTLE_ENDIAN
+  } s;
+} udwords;
+
+#if defined(__LP64__) || defined(__wasm__) || defined(__mips64) ||             \
+    defined(__riscv) || defined(_WIN64)
+#define CRT_HAS_128BIT
+#endif
+
+// MSVC doesn't have a working 128bit integer type. Users should really compile
+// compiler-rt with clang, but if they happen to be doing a standalone build for
+// asan or something else, disable the 128 bit parts so things sort of work.
+#if defined(_MSC_VER) && !defined(__clang__)
+#undef CRT_HAS_128BIT
+#endif
+
+#ifdef CRT_HAS_128BIT
+typedef int ti_int __attribute__((mode(TI)));
+typedef unsigned tu_int __attribute__((mode(TI)));
+
+typedef union {
+  ti_int all;
+  struct {
+#if _YUGA_LITTLE_ENDIAN
+    du_int low;
+    di_int high;
+#else
+    di_int high;
+    du_int low;
+#endif // _YUGA_LITTLE_ENDIAN
+  } s;
+} twords;
+
+typedef union {
+  tu_int all;
+  struct {
+#if _YUGA_LITTLE_ENDIAN
+    du_int low;
+    du_int high;
+#else
+    du_int high;
+    du_int low;
+#endif // _YUGA_LITTLE_ENDIAN
+  } s;
+} utwords;
+
+static __inline ti_int make_ti(di_int h, di_int l) {
+  twords r;
+  r.s.high = h;
+  r.s.low = l;
+  return r.all;
+}
+
+static __inline tu_int make_tu(du_int h, du_int l) {
+  utwords r;
+  r.s.high = h;
+  r.s.low = l;
+  return r.all;
+}
+
+#endif // CRT_HAS_128BIT
+
+typedef union {
+  su_int u;
+  float f;
+} float_bits;
+
+typedef union {
+  udwords u;
+  double f;
+} double_bits;
+
+typedef struct {
+#if _YUGA_LITTLE_ENDIAN
+  udwords low;
+  udwords high;
+#else
+  udwords high;
+  udwords low;
+#endif // _YUGA_LITTLE_ENDIAN
+} uqwords;
+
+// Check if the target supports 80 bit extended precision long doubles.
+// Notably, on x86 Windows, MSVC only provides a 64-bit long double, but GCC
+// still makes it 80 bits. Clang will match whatever compiler it is trying to
+// be compatible with.
+#if ((defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)) ||      \
+    defined(__m68k__) || defined(__ia64__)
+#define HAS_80_BIT_LONG_DOUBLE 1
+#else
+#define HAS_80_BIT_LONG_DOUBLE 0
+#endif
+
+typedef union {
+  uqwords u;
+  long double f;
+} long_double_bits;
+
+#if __STDC_VERSION__ >= 199901L
+typedef float _Complex Fcomplex;
+typedef double _Complex Dcomplex;
+typedef long double _Complex Lcomplex;
+
+#define COMPLEX_REAL(x) __real__(x)
+#define COMPLEX_IMAGINARY(x) __imag__(x)
+#else
+typedef struct {
+  float real, imaginary;
+} Fcomplex;
+
+typedef struct {
+  double real, imaginary;
+} Dcomplex;
+
+typedef struct {
+  long double real, imaginary;
+} Lcomplex;
+
+#define COMPLEX_REAL(x) (x).real
+#define COMPLEX_IMAGINARY(x) (x).imaginary
+#endif
+#endif // INT_TYPES_H
diff --git a/miasm/runtime/int_util.h b/miasm/runtime/int_util.h
new file mode 100644
index 00000000..5fbdfb57
--- /dev/null
+++ b/miasm/runtime/int_util.h
@@ -0,0 +1,31 @@
+//===-- int_util.h - internal utility functions ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is not part of the interface of this library.
+//
+// This file defines non-inline utilities which are available for use in the
+// library. The function definitions themselves are all contained in int_util.c
+// which will always be compiled into any compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INT_UTIL_H
+#define INT_UTIL_H
+
+/// \brief Trigger a program abort (or panic for kernel code).
+#define compilerrt_abort() __compilerrt_abort_impl(__FILE__, __LINE__, __func__)
+
+NORETURN void __compilerrt_abort_impl(const char *file, int line,
+                                      const char *function);
+
+#define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__)
+#define COMPILE_TIME_ASSERT1(expr, cnt) COMPILE_TIME_ASSERT2(expr, cnt)
+#define COMPILE_TIME_ASSERT2(expr, cnt)                                        \
+  typedef char ct_assert_##cnt[(expr) ? 1 : -1] UNUSED
+
+#endif // INT_UTIL_H
diff --git a/miasm/runtime/udivmodti4.c b/miasm/runtime/udivmodti4.c
new file mode 100644
index 00000000..44a43be4
--- /dev/null
+++ b/miasm/runtime/udivmodti4.c
@@ -0,0 +1,196 @@
+//===-- udivmodti4.c - Implement __udivmodti4 -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __udivmodti4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+#include "export.h"
+
+#ifdef CRT_HAS_128BIT
+
+// Effects: if rem != 0, *rem = a % b
+// Returns: a / b
+
+// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
+
+_MIASM_EXPORT tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) {
+  const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
+  const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
+  utwords n;
+  n.all = a;
+  utwords d;
+  d.all = b;
+  utwords q;
+  utwords r;
+  unsigned sr;
+  // special cases, X is unknown, K != 0
+  if (n.s.high == 0) {
+    if (d.s.high == 0) {
+      // 0 X
+      // ---
+      // 0 X
+      if (rem)
+        *rem = n.s.low % d.s.low;
+      return n.s.low / d.s.low;
+    }
+    // 0 X
+    // ---
+    // K X
+    if (rem)
+      *rem = n.s.low;
+    return 0;
+  }
+  // n.s.high != 0
+  if (d.s.low == 0) {
+    if (d.s.high == 0) {
+      // K X
+      // ---
+      // 0 0
+      if (rem)
+        *rem = n.s.high % d.s.low;
+      return n.s.high / d.s.low;
+    }
+    // d.s.high != 0
+    if (n.s.low == 0) {
+      // K 0
+      // ---
+      // K 0
+      if (rem) {
+        r.s.high = n.s.high % d.s.high;
+        r.s.low = 0;
+        *rem = r.all;
+      }
+      return n.s.high / d.s.high;
+    }
+    // K K
+    // ---
+    // K 0
+    if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ {
+      if (rem) {
+        r.s.low = n.s.low;
+        r.s.high = n.s.high & (d.s.high - 1);
+        *rem = r.all;
+      }
+      return n.s.high >> __builtin_ctzll(d.s.high);
+    }
+    // K K
+    // ---
+    // K 0
+    sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
+    // 0 <= sr <= n_udword_bits - 2 or sr large
+    if (sr > n_udword_bits - 2) {
+      if (rem)
+        *rem = n.all;
+      return 0;
+    }
+    ++sr;
+    // 1 <= sr <= n_udword_bits - 1
+    // q.all = n.all << (n_utword_bits - sr);
+    q.s.low = 0;
+    q.s.high = n.s.low << (n_udword_bits - sr);
+    // r.all = n.all >> sr;
+    r.s.high = n.s.high >> sr;
+    r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+  } else /* d.s.low != 0 */ {
+    if (d.s.high == 0) {
+      // K X
+      // ---
+      // 0 K
+      if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ {
+        if (rem)
+          *rem = n.s.low & (d.s.low - 1);
+        if (d.s.low == 1)
+          return n.all;
+        sr = __builtin_ctzll(d.s.low);
+        q.s.high = n.s.high >> sr;
+        q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+        return q.all;
+      }
+      // K X
+      // ---
+      // 0 K
+      sr = 1 + n_udword_bits + __builtin_clzll(d.s.low) -
+           __builtin_clzll(n.s.high);
+      // 2 <= sr <= n_utword_bits - 1
+      // q.all = n.all << (n_utword_bits - sr);
+      // r.all = n.all >> sr;
+      if (sr == n_udword_bits) {
+        q.s.low = 0;
+        q.s.high = n.s.low;
+        r.s.high = 0;
+        r.s.low = n.s.high;
+      } else if (sr < n_udword_bits) /* 2 <= sr <= n_udword_bits - 1 */ {
+        q.s.low = 0;
+        q.s.high = n.s.low << (n_udword_bits - sr);
+        r.s.high = n.s.high >> sr;
+        r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+      } else /* n_udword_bits + 1 <= sr <= n_utword_bits - 1 */ {
+        q.s.low = n.s.low << (n_utword_bits - sr);
+        q.s.high = (n.s.high << (n_utword_bits - sr)) |
+                   (n.s.low >> (sr - n_udword_bits));
+        r.s.high = 0;
+        r.s.low = n.s.high >> (sr - n_udword_bits);
+      }
+    } else {
+      // K X
+      // ---
+      // K K
+      sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
+      // 0 <= sr <= n_udword_bits - 1 or sr large
+      if (sr > n_udword_bits - 1) {
+        if (rem)
+          *rem = n.all;
+        return 0;
+      }
+      ++sr;
+      // 1 <= sr <= n_udword_bits
+      // q.all = n.all << (n_utword_bits - sr);
+      // r.all = n.all >> sr;
+      q.s.low = 0;
+      if (sr == n_udword_bits) {
+        q.s.high = n.s.low;
+        r.s.high = 0;
+        r.s.low = n.s.high;
+      } else {
+        r.s.high = n.s.high >> sr;
+        r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+        q.s.high = n.s.low << (n_udword_bits - sr);
+      }
+    }
+  }
+  // Not a special case
+  // q and r are initialized with:
+  // q.all = n.all << (n_utword_bits - sr);
+  // r.all = n.all >> sr;
+  // 1 <= sr <= n_utword_bits - 1
+  su_int carry = 0;
+  for (; sr > 0; --sr) {
+    // r:q = ((r:q)  << 1) | carry
+    r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1));
+    r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1));
+    q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1));
+    q.s.low = (q.s.low << 1) | carry;
+    // carry = 0;
+    // if (r.all >= d.all)
+    // {
+    //     r.all -= d.all;
+    //      carry = 1;
+    // }
+    const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1);
+    carry = s & 1;
+    r.all -= d.all & s;
+  }
+  q.all = (q.all << 1) | carry;
+  if (rem)
+    *rem = r.all;
+  return q.all;
+}
+
+#endif // CRT_HAS_128BIT
diff --git a/miasm/runtime/udivti3.c b/miasm/runtime/udivti3.c
new file mode 100644
index 00000000..3844dc9d
--- /dev/null
+++ b/miasm/runtime/udivti3.c
@@ -0,0 +1,24 @@
+//===-- udivti3.c - Implement __udivti3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __udivti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+#include "export.h"
+
+#ifdef CRT_HAS_128BIT
+
+// Returns: a / b
+
+_MIASM_EXPORT tu_int __udivti3(tu_int a, tu_int b) {
+  return __udivmodti4(a, b, 0);
+}
+
+#endif // CRT_HAS_128BIT
diff --git a/setup.py b/setup.py
index c85841e4..a20cf9a1 100644
--- a/setup.py
+++ b/setup.py
@@ -11,11 +11,16 @@ import fnmatch
 import io
 import os
 import platform
-from shutil import copy2
+from shutil import copy2, copyfile, rmtree
 import sys
+import tempfile
+import atexit
 
 is_win = platform.system() == "Windows"
 is_mac = platform.system() == "Darwin"
+is_64bit = platform.architecture()[0] == "64bit"
+if is_win:
+    import winreg
 
 def set_extension_compile_args(extension):
     rel_lib_path = extension.name.replace('.', '/')
@@ -23,7 +28,6 @@ def set_extension_compile_args(extension):
     lib_name = abs_lib_path + '.so'
     extension.extra_link_args = [ '-Wl,-install_name,' + lib_name]
 
-
 class smart_install_data(install_data):
     """Replacement for distutils.command.install_data to handle
     configuration files location.
@@ -36,6 +40,48 @@ class smart_install_data(install_data):
         ]
         return install_data.run(self)
 
+def win_get_llvm_reg():
+    REG_PATH = "SOFTWARE\\LLVM\\LLVM"
+    try:
+      return winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, REG_PATH, 0, winreg.KEY_READ | winreg.KEY_WOW64_32KEY)
+    except FileNotFoundError:
+      pass
+    return winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, REG_PATH, 0, winreg.KEY_READ)
+  
+def win_find_clang_path():
+    try:
+        with win_get_llvm_reg() as rkey:
+            return winreg.QueryValueEx(rkey, None)[0]
+    except FileNotFoundError:
+        return None
+
+def win_use_clang():
+    # Recent (>= 8 ?) LLVM versions does not ship anymore a cl.exe binary in
+    # the msbuild-bin directory. Thus, we need to
+    # * copy-paste bin/clang-cl.exe into a temporary directory
+    # * rename it to cl.exe
+    # * add that path first in %Path%
+    # * clean this mess on exit
+    # We could use the build directory created by distutils for this, but it
+    # seems non trivial to gather
+    # (https://stackoverflow.com/questions/12896367/reliable-way-to-get-the-build-directory-from-within-setup-py).
+    clang_path = win_find_clang_path()
+    if clang_path is None:
+        return False
+    tmpdir = tempfile.mkdtemp(prefix="llvm")
+    copyfile(os.path.join(clang_path, "bin", "clang-cl.exe"), os.path.join(tmpdir, "cl.exe"))
+    os.environ['Path'] = "%s;%s" % (tmpdir, os.environ["Path"])
+    atexit.register(lambda dir_: rmtree(dir_), tmpdir)
+
+    return True
+
+win_force_clang = False
+if is_win and is_64bit:
+    # We do not change to clang if under 32 bits, because even with Clang we
+    # don't have uint128_t with the 32 bits ABI.
+    win_force_clang = win_use_clang()
+    if not win_force_clang:
+        print("Warning: couldn't find a Clang/LLVM installation. Some runtime functions needed by the jitter won't be compiled.")
 
 def buil_all():
     packages=[
@@ -154,6 +200,9 @@ def buil_all():
         Extension("miasm.jitter.Jitllvm",
                   ["miasm/jitter/Jitllvm.c",
                    "miasm/jitter/bn.c",
+                   "miasm/runtime/udivmodti4.c",
+                   "miasm/runtime/divti3.c",
+                   "miasm/runtime/udivti3.c"
                   ]),
         Extension("miasm.jitter.Jitgcc",
                   ["miasm/jitter/Jitgcc.c",
@@ -165,6 +214,10 @@ def buil_all():
         # Force setuptools to use whatever msvc version installed
         os.environ['MSSdk'] = '1'
         os.environ['DISTUTILS_USE_SDK'] = '1'
+        if win_force_clang:
+            march = "-m64" if is_64bit else "-m32"
+            for extension in ext_modules_all:
+                extension.extra_compile_args = [march]
     elif is_mac:
         for extension in ext_modules_all:
             set_extension_compile_args(extension)
diff --git a/test/test_all.py b/test/test_all.py
index a8bf5330..71eccc6f 100755
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -17,6 +17,7 @@ from utils import cosmetics, multithread
 from multiprocessing import Queue
 
 is_win = platform.system() == "Windows"
+is_64bit = platform.architecture()[0] == "64bit"
 
 testset = TestSet("../")
 TAGS = {"regression": "REGRESSION", # Regression tests
@@ -112,7 +113,7 @@ for script in ["x86/sem.py",
         if jitter in blacklist.get(script, []):
             continue
         tags = [TAGS[jitter]] if jitter in TAGS else []
-        if is_win and script.endswith("mn_div.py"):
+        if (not is_64bit) and script.endswith("mn_div.py"):
             continue
         testset += ArchUnitTest(script, jitter, base_dir="arch", tags=tags)