diff options
author | Florian MARGAINE <florian@margaine.com> | 2014-09-20 10:09:21 +0200 |
---|---|---|
committer | Florian MARGAINE <florian@margaine.com> | 2014-09-20 10:09:21 +0200 |
commit | 8eb7e7bf7f63f49e97f112871df47c6d6213e715 (patch) | |
tree | 24b9059118cf6abb5fe0837eaa477b4668b18435 /Zend/zend_multiply.h | |
parent | 58ed832fc99d5c5aeac7849819bbc4e0dc90d698 (diff) | |
parent | 95836a350420cabc2e8e5f5c45131fba46504a3b (diff) | |
download | php-git-8eb7e7bf7f63f49e97f112871df47c6d6213e715.tar.gz |
Merge branch 'master' into issue-67910
Conflicts:
README.PARAMETER_PARSING_API
ext/gmp/tests/001.phpt
Diffstat (limited to 'Zend/zend_multiply.h')
-rw-r--r-- | Zend/zend_multiply.h | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h index 11744c2699..158be22007 100644 --- a/Zend/zend_multiply.h +++ b/Zend/zend_multiply.h @@ -19,6 +19,9 @@ /* $Id$ */ +#ifndef ZEND_MULTIPLY_H +#define ZEND_MULTIPLY_H + #if defined(__i386__) && defined(__GNUC__) #define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \ @@ -108,3 +111,138 @@ } while (0) #endif + +#if defined(__GNUC__) && (defined(__native_client__) || defined(i386)) + +static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow) +{ + size_t res = nmemb; + zend_ulong m_overflow = 0; + + __asm__ ("mull %3\n\taddl %4,%0\n\tadcl $0,%1" + : "=&a"(res), "=&d" (m_overflow) + : "%0"(res), + "rm"(size), + "rm"(offset)); + + if (UNEXPECTED(m_overflow)) { + *overflow = 1; + return 0; + } + *overflow = 0; + return res; +} + +#elif defined(__GNUC__) && defined(__x86_64__) + +static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow) +{ + size_t res = nmemb; + zend_ulong m_overflow = 0; + +#ifdef __ILP32__ /* x32 */ +# define LP_SUFF "l" +#else /* amd64 */ +# define LP_SUFF "q" +#endif + + __asm__ ("mul" LP_SUFF " %3\n\t" + "add %4,%0\n\t" + "adc $0,%1" + : "=&a"(res), "=&d" (m_overflow) + : "%0"(res), + "rm"(size), + "rm"(offset)); + +#undef LP_SUFF + if (UNEXPECTED(m_overflow)) { + *overflow = 1; + return 0; + } + *overflow = 0; + return res; +} + +#elif defined(__GNUC__) && defined(__arm__) + +static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow) +{ + size_t res; + zend_ulong m_overflow; + + __asm__ ("umlal %0,%1,%2,%3" + : "=r"(res), "=r"(m_overflow) + : "r"(nmemb), + "r"(size), + "0"(offset), + "1"(0)); + + if (UNEXPECTED(m_overflow)) { + *overflow = 1; + return 0; + } + *overflow = 0; + return res; +} + +#elif defined(__GNUC__) && defined(__aarch64__) + +static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow) +{ + size_t res; + zend_ulong m_overflow; + + __asm__ ("mul %0,%2,%3\n\tumulh %1,%2,%3\n\tadds %0,%0,%4\n\tadc %1,%1,xzr" + : "=&r"(res), "=&r"(m_overflow) + : "r"(nmemb), + "r"(size), + "r"(offset)); + + if (UNEXPECTED(m_overflow)) { + *overflow = 1; + return 0; + } + *overflow = 0; + return res; +} + +#elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64) + +static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow) +{ + zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset; + + if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) { + *overflow = 1; + return 0; + } + *overflow = 0; + return (size_t) res; +} + +#else + +static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow) +{ + size_t res = nmemb * size + offset; + double _d = (double)nmemb * (double)size + (double)offset; + double _delta = (double)res - _d; + + if (UNEXPECTED((_d + _delta ) != _d)) { + *overflow = 1; + return 0; + } + *overflow = 0; + return res; +} +#endif + +#endif /* ZEND_MULTIPLY_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ |