| 1 | /* |
| 2 | * Internals details of the bignum representation. |
| 3 | */ |
| 4 | |
| 5 | #ifndef PUTTY_BN_INTERNAL_H |
| 6 | #define PUTTY_BN_INTERNAL_H |
| 7 | |
| 8 | /* |
| 9 | * Usage notes: |
| 10 | * * Do not call the DIVMOD_WORD macro with expressions such as array |
| 11 | * subscripts, as some implementations object to this (see below). |
| 12 | * * Note that none of the division methods below will cope if the |
| 13 | * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful |
| 14 | * to avoid this case. |
| 15 | * If this condition occurs, in the case of the x86 DIV instruction, |
| 16 | * an overflow exception will occur, which (according to a correspondent) |
| 17 | * will manifest on Windows as something like |
| 18 | * 0xC0000095: Integer overflow |
| 19 | * The C variant won't give the right answer, either. |
| 20 | */ |
| 21 | |
| 22 | #if defined __GNUC__ && defined __i386__ |
| 23 | typedef unsigned long BignumInt; |
| 24 | typedef unsigned long long BignumDblInt; |
| 25 | #define BIGNUM_INT_MASK 0xFFFFFFFFUL |
| 26 | #define BIGNUM_TOP_BIT 0x80000000UL |
| 27 | #define BIGNUM_INT_BITS 32 |
| 28 | #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2) |
| 29 | #define DIVMOD_WORD(q, r, hi, lo, w) \ |
| 30 | __asm__("div %2" : \ |
| 31 | "=d" (r), "=a" (q) : \ |
| 32 | "r" (w), "d" (hi), "a" (lo)) |
| 33 | #elif defined _MSC_VER && defined _M_IX86 |
| 34 | typedef unsigned __int32 BignumInt; |
| 35 | typedef unsigned __int64 BignumDblInt; |
| 36 | #define BIGNUM_INT_MASK 0xFFFFFFFFUL |
| 37 | #define BIGNUM_TOP_BIT 0x80000000UL |
| 38 | #define BIGNUM_INT_BITS 32 |
| 39 | #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2) |
| 40 | /* Note: MASM interprets array subscripts in the macro arguments as |
| 41 | * assembler syntax, which gives the wrong answer. Don't supply them. |
| 42 | * <http://msdn2.microsoft.com/en-us/library/bf1dw62z.aspx> */ |
| 43 | #define DIVMOD_WORD(q, r, hi, lo, w) do { \ |
| 44 | __asm mov edx, hi \ |
| 45 | __asm mov eax, lo \ |
| 46 | __asm div w \ |
| 47 | __asm mov r, edx \ |
| 48 | __asm mov q, eax \ |
| 49 | } while(0) |
| 50 | #elif defined _LP64 |
| 51 | /* 64-bit architectures can do 32x32->64 chunks at a time */ |
| 52 | typedef unsigned int BignumInt; |
| 53 | typedef unsigned long BignumDblInt; |
| 54 | #define BIGNUM_INT_MASK 0xFFFFFFFFU |
| 55 | #define BIGNUM_TOP_BIT 0x80000000U |
| 56 | #define BIGNUM_INT_BITS 32 |
| 57 | #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2) |
| 58 | #define DIVMOD_WORD(q, r, hi, lo, w) do { \ |
| 59 | BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \ |
| 60 | q = n / w; \ |
| 61 | r = n % w; \ |
| 62 | } while (0) |
| 63 | #elif defined _LLP64 |
| 64 | /* 64-bit architectures in which unsigned long is 32 bits, not 64 */ |
| 65 | typedef unsigned long BignumInt; |
| 66 | typedef unsigned long long BignumDblInt; |
| 67 | #define BIGNUM_INT_MASK 0xFFFFFFFFUL |
| 68 | #define BIGNUM_TOP_BIT 0x80000000UL |
| 69 | #define BIGNUM_INT_BITS 32 |
| 70 | #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2) |
| 71 | #define DIVMOD_WORD(q, r, hi, lo, w) do { \ |
| 72 | BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \ |
| 73 | q = n / w; \ |
| 74 | r = n % w; \ |
| 75 | } while (0) |
| 76 | #else |
| 77 | /* Fallback for all other cases */ |
| 78 | typedef unsigned short BignumInt; |
| 79 | typedef unsigned long BignumDblInt; |
| 80 | #define BIGNUM_INT_MASK 0xFFFFU |
| 81 | #define BIGNUM_TOP_BIT 0x8000U |
| 82 | #define BIGNUM_INT_BITS 16 |
| 83 | #define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2) |
| 84 | #define DIVMOD_WORD(q, r, hi, lo, w) do { \ |
| 85 | BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \ |
| 86 | q = n / w; \ |
| 87 | r = n % w; \ |
| 88 | } while (0) |
| 89 | #endif |
| 90 | |
| 91 | #define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8) |
| 92 | |
| 93 | #define BIGNUM_INTERNAL |
| 94 | typedef BignumInt *Bignum; |
| 95 | |
| 96 | #endif |