X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/036eddfb3ea7dabc26c17608ce18bb4d3fe8689b..533c7491240f2fd71d026e91f0a940f4729992fd:/sshbn.c diff --git a/sshbn.c b/sshbn.c index 14cdd05e..9742c4ad 100644 --- a/sshbn.c +++ b/sshbn.c @@ -9,6 +9,20 @@ #include "misc.h" +/* + * Usage notes: + * * Do not call the DIVMOD_WORD macro with expressions such as array + * subscripts, as some implementations object to this (see below). + * * Note that none of the division methods below will cope if the + * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful + * to avoid this case. + * If this condition occurs, in the case of the x86 DIV instruction, + * an overflow exception will occur, which (according to a correspondent) + * will manifest on Windows as something like + * 0xC0000095: Integer overflow + * The C variant won't give the right answer, either. + */ + #if defined __GNUC__ && defined __i386__ typedef unsigned long BignumInt; typedef unsigned long long BignumDblInt; @@ -27,26 +41,16 @@ typedef unsigned __int64 BignumDblInt; #define BIGNUM_TOP_BIT 0x80000000UL #define BIGNUM_INT_BITS 32 #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2) -typedef struct { - unsigned __int32 quot; - unsigned __int32 remd; -} msvc_quorem; -static __declspec(naked) msvc_quorem __stdcall msvc_divmod( - unsigned __int32 hi, - unsigned __int32 lo, - unsigned __int32 w) -{ - __asm { - mov edx, dword ptr [esp+4] - mov eax, dword ptr [esp+8] - div dword ptr [esp+12] - ret 12 - }; -} +/* Note: MASM interprets array subscripts in the macro arguments as + * assembler syntax, which gives the wrong answer. Don't supply them. + * */ #define DIVMOD_WORD(q, r, hi, lo, w) do { \ - const msvc_quorem qr = msvc_divmod((hi), (lo), (w)); \ - (q) = qr.quot; (r) = qr.remd; \ -} while (0) + __asm mov edx, hi \ + __asm mov eax, lo \ + __asm div w \ + __asm mov r, edx \ + __asm mov q, eax \ +} while(0) #else typedef unsigned short BignumInt; typedef unsigned long BignumDblInt; @@ -230,7 +234,10 @@ static void internal_mod(BignumInt *a, int alen, */ q = BIGNUM_INT_MASK; } else { - DIVMOD_WORD(q, r, h, a[i], m0); + /* Macro doesn't want an array subscript expression passed + * into it (see definition), so use a temporary. */ + BignumInt tmplo = a[i]; + DIVMOD_WORD(q, r, h, tmplo, m0); /* Refine our estimate of q by looking at h:a[i]:a[i+1] / m0:m1 */ @@ -1030,9 +1037,14 @@ char *bignum_decimal(Bignum x) * round up (rounding down might make it less than x again). * Therefore if we multiply the bit count by 28/93, rounding * up, we will have enough digits. + * + * i=0 (i.e., x=0) is an irritating special case. */ i = bignum_bitcount(x); - ndigits = (28 * i + 92) / 93; /* multiply by 28/93 and round up */ + if (!i) + ndigits = 1; /* x = 0 */ + else + ndigits = (28 * i + 92) / 93; /* multiply by 28/93 and round up */ ndigits++; /* allow for trailing \0 */ ret = snewn(ndigits, char);