diff --git a/CHANGES.md b/CHANGES.md index 02b59d1..4941178 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ * Fix sign extensions (#49, @rixed) * `Long_val` returns `intnat`, previously `long` was used (#53, @dra27) * Reduce size of marshalled custom values on 4.08+ (#54, @dra27) +* Store 128-bit ints as structs to prevent unaligned access (#55, @dra27) ## New features: diff --git a/lib/int128.h b/lib/int128.h index 194e1ae..3b7e73e 100644 --- a/lib/int128.h +++ b/lib/int128.h @@ -2,14 +2,27 @@ #define OCAML_INT128_H #if defined(__SIZEOF_INT128__) + #define HAVE_INT128 typedef __int128_t int128; +typedef struct { uint64_t low; int64_t high; } int128_ocaml; + +inline __int128_t get_int128(value v) +{ + int128_ocaml *i = (int128_ocaml *)Data_custom_val(v); + return ((__int128_t)i->high << 64 | i->low); +} + +#define Int128_val(v) get_int128(v) + #else + typedef struct { int64_t high; uint64_t low; } int128; -#endif #define Int128_val(v) (*((int128 *)Data_custom_val(v))) +#endif + CAMLextern value copy_int128(int128 i); #endif diff --git a/lib/int128_stubs.c b/lib/int128_stubs.c index ad85a3d..b48483c 100644 --- a/lib/int128_stubs.c +++ b/lib/int128_stubs.c @@ -147,6 +147,18 @@ struct custom_operations int128_ops = { #endif }; +#ifdef HAVE_INT128 +CAMLprim value +copy_int128(__int128_t i) +{ + CAMLparam0(); + value res = caml_alloc_custom(&int128_ops, 16, 0, 1); + int128_ocaml *v = (int128_ocaml *)Data_custom_val(res); + v->high = (int64_t)(i >> 64); + v->low = (uint64_t)i; + CAMLreturn (res); +} +#else CAMLprim value copy_int128(int128 i) { @@ -155,6 +167,7 @@ copy_int128(int128 i) Int128_val(res) = i; CAMLreturn (res); } +#endif CAMLprim value int128_add(value v1, value v2) diff --git a/lib/uint128.h b/lib/uint128.h index 3f97dab..ae9292f 100644 --- a/lib/uint128.h +++ b/lib/uint128.h @@ -2,14 +2,27 @@ #define OCAML_UINT128_H #if defined(__SIZEOF_INT128__) + #define HAVE_UINT128 typedef __uint128_t uint128; +typedef struct { uint64_t low; uint64_t high; } uint128_ocaml; + +inline __uint128_t get_uint128(value v) +{ + uint128_ocaml *i = (uint128_ocaml *)Data_custom_val(v); + return ((__uint128_t)i->high << 64 | i->low); +} + +#define Uint128_val(v) get_uint128(v) + #else + typedef struct { uint64_t high; uint64_t low; } uint128; -#endif #define Uint128_val(v) (*((uint128 *)Data_custom_val(v))) +#endif + CAMLextern value copy_uint128(uint128 i); CAMLextern value suint128_add(value v1, value v2, CAMLprim value (*)(uint128)); CAMLextern value suint128_sub(value v1, value v2, CAMLprim value (*)(uint128)); @@ -20,4 +33,3 @@ CAMLextern value suint128_xor(value v1, value v2, CAMLprim value (*)(uint128)); CAMLextern value suint128_shift_left(value v1, value v2, CAMLprim value (*)(uint128)); #endif - diff --git a/lib/uint128_stubs.c b/lib/uint128_stubs.c index 3465bd3..bf10a17 100644 --- a/lib/uint128_stubs.c +++ b/lib/uint128_stubs.c @@ -189,6 +189,18 @@ struct custom_operations uint128_ops = { #endif }; +#ifdef HAVE_UINT128 +CAMLprim value +copy_uint128(__uint128_t i) +{ + CAMLparam0(); + value res = caml_alloc_custom(&uint128_ops, 16, 0, 1); + uint128_ocaml *v = (uint128_ocaml *)Data_custom_val(res); + v->high = (uint64_t)(i >> 64); + v->low = (uint64_t)i; + CAMLreturn (res); +} +#else CAMLprim value copy_uint128(uint128 i) { @@ -197,6 +209,7 @@ copy_uint128(uint128 i) Uint128_val(res) = i; CAMLreturn (res); } +#endif CAMLprim value suint128_add(value v1, value v2, CAMLprim value (*copy)(uint128))