linux-x32-abi https://www.e-learn.cn/tag/linux-x32-abi zh-hans How to detect X32 ABI or environment in the preprocessor? https://www.e-learn.cn/topic/2784832 <span>How to detect X32 ABI or environment in the preprocessor?</span> <span><span lang="" about="/user/101" typeof="schema:Person" property="schema:name" datatype="">老子叫甜甜</span></span> <span>2019-12-23 02:58:21</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p><strong><em><code>X32</code></em></strong> is an ABI for <code>amd64</code>/<code>x86_64</code> CPUs using 32-bit pointers. The idea is to combine the larger register set of x86_64 with the smaller memory and cache footprint resulting from 32-bit pointers. It provides up to about a 40% speedup. See Difference between x86, x32, and x64 architectures on Stack Overflow, and the Debian X32 Ports wiki page for details and setting it up as a chroot environment.</p> <p>We have a bug report from a Debian maintainer under the environment. The report is <code>adcq</code> is an illegal instruction. The inline assembly is activated based on preprocessor macros, so we are not detecting X32 properly (or more correctly, not at all until now).</p> <p>The most obvious choice (to me) for a preprocessor macro is something like <code>__X32__</code>, but that's not offered. Based on Clang's patch and Debian's suggestion, it looks like <code>__ILP32__</code> can be used. But I'd like a more canonical answer since <code>_ILP32</code> and <code>__code_model_small__</code> look interesting, too. (And I'm aware of issues with SSE2, where the compiler supported it but the OS did not).</p> <p>What are the preprocessor macros that can be used to reliably detect an X32 ABI and environment when using Clang and GCC?</p> <p>To be clear, I'm not trying to fix the code at this point. I just want to know the macros that can be used in a complete remediation.</p> <hr /><pre><code># cpp -dM &lt; /dev/null | sort #define __amd64 1 #define __amd64__ 1 #define __ATOMIC_ACQ_REL 4 #define __ATOMIC_ACQUIRE 2 #define __ATOMIC_CONSUME 1 #define __ATOMIC_HLE_ACQUIRE 65536 #define __ATOMIC_HLE_RELEASE 131072 #define __ATOMIC_RELAXED 0 #define __ATOMIC_RELEASE 3 #define __ATOMIC_SEQ_CST 5 #define __BIGGEST_ALIGNMENT__ 16 #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ #define __CHAR16_TYPE__ short unsigned int #define __CHAR32_TYPE__ unsigned int #define __CHAR_BIT__ 8 #define __code_model_small__ 1 #define __DBL_DECIMAL_DIG__ 17 #define __DBL_DENORM_MIN__ ((double)4.94065645841246544177e-324L) #define __DBL_DIG__ 15 #define __DBL_EPSILON__ ((double)2.22044604925031308085e-16L) #define __DBL_HAS_DENORM__ 1 #define __DBL_HAS_INFINITY__ 1 #define __DBL_HAS_QUIET_NAN__ 1 #define __DBL_MANT_DIG__ 53 #define __DBL_MAX_10_EXP__ 308 #define __DBL_MAX__ ((double)1.79769313486231570815e+308L) #define __DBL_MAX_EXP__ 1024 #define __DBL_MIN_10_EXP__ (-307) #define __DBL_MIN__ ((double)2.22507385850720138309e-308L) #define __DBL_MIN_EXP__ (-1021) #define __DEC128_EPSILON__ 1E-33DL #define __DEC128_MANT_DIG__ 34 #define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL #define __DEC128_MAX_EXP__ 6145 #define __DEC128_MIN__ 1E-6143DL #define __DEC128_MIN_EXP__ (-6142) #define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL #define __DEC32_EPSILON__ 1E-6DF #define __DEC32_MANT_DIG__ 7 #define __DEC32_MAX__ 9.999999E96DF #define __DEC32_MAX_EXP__ 97 #define __DEC32_MIN__ 1E-95DF #define __DEC32_MIN_EXP__ (-94) #define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF #define __DEC64_EPSILON__ 1E-15DD #define __DEC64_MANT_DIG__ 16 #define __DEC64_MAX__ 9.999999999999999E384DD #define __DEC64_MAX_EXP__ 385 #define __DEC64_MIN__ 1E-383DD #define __DEC64_MIN_EXP__ (-382) #define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD #define __DEC_EVAL_METHOD__ 2 #define __DECIMAL_BID_FORMAT__ 1 #define __DECIMAL_DIG__ 21 #define __ELF__ 1 #define __FINITE_MATH_ONLY__ 0 #define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__ #define __FLT_DECIMAL_DIG__ 9 #define __FLT_DENORM_MIN__ 1.40129846432481707092e-45F #define __FLT_DIG__ 6 #define __FLT_EPSILON__ 1.19209289550781250000e-7F #define __FLT_EVAL_METHOD__ 0 #define __FLT_HAS_DENORM__ 1 #define __FLT_HAS_INFINITY__ 1 #define __FLT_HAS_QUIET_NAN__ 1 #define __FLT_MANT_DIG__ 24 #define __FLT_MAX_10_EXP__ 38 #define __FLT_MAX__ 3.40282346638528859812e+38F #define __FLT_MAX_EXP__ 128 #define __FLT_MIN_10_EXP__ (-37) #define __FLT_MIN__ 1.17549435082228750797e-38F #define __FLT_MIN_EXP__ (-125) #define __FLT_RADIX__ 2 #define __FXSR__ 1 #define __GCC_ATOMIC_BOOL_LOCK_FREE 2 #define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2 #define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2 #define __GCC_ATOMIC_CHAR_LOCK_FREE 2 #define __GCC_ATOMIC_INT_LOCK_FREE 2 #define __GCC_ATOMIC_LLONG_LOCK_FREE 2 #define __GCC_ATOMIC_LONG_LOCK_FREE 2 #define __GCC_ATOMIC_POINTER_LOCK_FREE 2 #define __GCC_ATOMIC_SHORT_LOCK_FREE 2 #define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1 #define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2 #define __GCC_HAVE_DWARF2_CFI_ASM 1 #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1 #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 #define __GCC_IEC_559 2 #define __GCC_IEC_559_COMPLEX 2 #define __GNUC__ 5 #define __GNUC_MINOR__ 2 #define __GNUC_PATCHLEVEL__ 1 #define __GNUC_STDC_INLINE__ 1 #define __gnu_linux__ 1 #define __GXX_ABI_VERSION 1009 #define __has_include_next(STR) __has_include_next__(STR) #define __has_include(STR) __has_include__(STR) #define __ILP32__ 1 #define _ILP32 1 #define __INT16_C(c) c #define __INT16_MAX__ 0x7fff #define __INT16_TYPE__ short int #define __INT32_C(c) c #define __INT32_MAX__ 0x7fffffff #define __INT32_TYPE__ int #define __INT64_C(c) c ## LL #define __INT64_MAX__ 0x7fffffffffffffffLL #define __INT64_TYPE__ long long int #define __INT8_C(c) c #define __INT8_MAX__ 0x7f #define __INT8_TYPE__ signed char #define __INT_FAST16_MAX__ 0x7fffffff #define __INT_FAST16_TYPE__ int #define __INT_FAST32_MAX__ 0x7fffffff #define __INT_FAST32_TYPE__ int #define __INT_FAST64_MAX__ 0x7fffffffffffffffLL #define __INT_FAST64_TYPE__ long long int #define __INT_FAST8_MAX__ 0x7f #define __INT_FAST8_TYPE__ signed char #define __INT_LEAST16_MAX__ 0x7fff #define __INT_LEAST16_TYPE__ short int #define __INT_LEAST32_MAX__ 0x7fffffff #define __INT_LEAST32_TYPE__ int #define __INT_LEAST64_MAX__ 0x7fffffffffffffffLL #define __INT_LEAST64_TYPE__ long long int #define __INT_LEAST8_MAX__ 0x7f #define __INT_LEAST8_TYPE__ signed char #define __INT_MAX__ 0x7fffffff #define __INTMAX_C(c) c ## LL #define __INTMAX_MAX__ 0x7fffffffffffffffLL #define __INTMAX_TYPE__ long long int #define __INTPTR_MAX__ 0x7fffffff #define __INTPTR_TYPE__ int #define __k8 1 #define __k8__ 1 #define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L #define __LDBL_DIG__ 18 #define __LDBL_EPSILON__ 1.08420217248550443401e-19L #define __LDBL_HAS_DENORM__ 1 #define __LDBL_HAS_INFINITY__ 1 #define __LDBL_HAS_QUIET_NAN__ 1 #define __LDBL_MANT_DIG__ 64 #define __LDBL_MAX_10_EXP__ 4932 #define __LDBL_MAX__ 1.18973149535723176502e+4932L #define __LDBL_MAX_EXP__ 16384 #define __LDBL_MIN_10_EXP__ (-4931) #define __LDBL_MIN__ 3.36210314311209350626e-4932L #define __LDBL_MIN_EXP__ (-16381) #define __linux 1 #define __linux__ 1 #define linux 1 #define __LONG_LONG_MAX__ 0x7fffffffffffffffLL #define __LONG_MAX__ 0x7fffffffL #define __MMX__ 1 #define __NO_INLINE__ 1 #define __ORDER_BIG_ENDIAN__ 4321 #define __ORDER_LITTLE_ENDIAN__ 1234 #define __ORDER_PDP_ENDIAN__ 3412 #define __PRAGMA_REDEFINE_EXTNAME 1 #define __PTRDIFF_MAX__ 0x7fffffff #define __PTRDIFF_TYPE__ int #define __REGISTER_PREFIX__ #define __SCHAR_MAX__ 0x7f #define __SHRT_MAX__ 0x7fff #define __SIG_ATOMIC_MAX__ 0x7fffffff #define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1) #define __SIG_ATOMIC_TYPE__ int #define __SIZE_MAX__ 0xffffffffU #define __SIZEOF_DOUBLE__ 8 #define __SIZEOF_FLOAT128__ 16 #define __SIZEOF_FLOAT__ 4 #define __SIZEOF_FLOAT80__ 16 #define __SIZEOF_INT128__ 16 #define __SIZEOF_INT__ 4 #define __SIZEOF_LONG__ 4 #define __SIZEOF_LONG_DOUBLE__ 16 #define __SIZEOF_LONG_LONG__ 8 #define __SIZEOF_POINTER__ 4 #define __SIZEOF_PTRDIFF_T__ 4 #define __SIZEOF_SHORT__ 2 #define __SIZEOF_SIZE_T__ 4 #define __SIZEOF_WCHAR_T__ 4 #define __SIZEOF_WINT_T__ 4 #define __SIZE_TYPE__ unsigned int #define __SSE__ 1 #define __SSE2__ 1 #define __SSE2_MATH__ 1 #define __SSE_MATH__ 1 #define __STDC__ 1 #define __STDC_HOSTED__ 1 #define __STDC_IEC_559__ 1 #define __STDC_IEC_559_COMPLEX__ 1 #define __STDC_ISO_10646__ 201103L #define __STDC_NO_THREADS__ 1 #define _STDC_PREDEF_H 1 #define __STDC_UTF_16__ 1 #define __STDC_UTF_32__ 1 #define __STDC_VERSION__ 201112L #define __UINT16_C(c) c #define __UINT16_MAX__ 0xffff #define __UINT16_TYPE__ short unsigned int #define __UINT32_C(c) c ## U #define __UINT32_MAX__ 0xffffffffU #define __UINT32_TYPE__ unsigned int #define __UINT64_C(c) c ## ULL #define __UINT64_MAX__ 0xffffffffffffffffULL #define __UINT64_TYPE__ long long unsigned int #define __UINT8_C(c) c #define __UINT8_MAX__ 0xff #define __UINT8_TYPE__ unsigned char #define __UINT_FAST16_MAX__ 0xffffffffU #define __UINT_FAST16_TYPE__ unsigned int #define __UINT_FAST32_MAX__ 0xffffffffU #define __UINT_FAST32_TYPE__ unsigned int #define __UINT_FAST64_MAX__ 0xffffffffffffffffULL #define __UINT_FAST64_TYPE__ long long unsigned int #define __UINT_FAST8_MAX__ 0xff #define __UINT_FAST8_TYPE__ unsigned char #define __UINT_LEAST16_MAX__ 0xffff #define __UINT_LEAST16_TYPE__ short unsigned int #define __UINT_LEAST32_MAX__ 0xffffffffU #define __UINT_LEAST32_TYPE__ unsigned int #define __UINT_LEAST64_MAX__ 0xffffffffffffffffULL #define __UINT_LEAST64_TYPE__ long long unsigned int #define __UINT_LEAST8_MAX__ 0xff #define __UINT_LEAST8_TYPE__ unsigned char #define __UINTMAX_C(c) c ## ULL #define __UINTMAX_MAX__ 0xffffffffffffffffULL #define __UINTMAX_TYPE__ long long unsigned int #define __UINTPTR_MAX__ 0xffffffffU #define __UINTPTR_TYPE__ unsigned int #define __unix 1 #define __unix__ 1 #define unix 1 #define __USER_LABEL_PREFIX__ #define __VERSION__ "5.2.1 20150911" #define __WCHAR_MAX__ 0x7fffffffL #define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1) #define __WCHAR_TYPE__ long int #define __WINT_MAX__ 0xffffffffU #define __WINT_MIN__ 0U #define __WINT_TYPE__ unsigned int #define __x86_64 1 #define __x86_64__ 1 </code></pre> <br /><h3>回答1:</h3><br /><p>There doesn't appear to be a predefined macro that explicitly specifies an x32 environment. Comparing the output of <code>cpp -dM</code> and <code>cpp -dM -mx32</code>, the symbols <code>_ILP32</code> and <code>__ILP32__</code> are defined only for x32, and <code>_LP64</code> and <code>__LP64__</code> are defined only for x86_64 without x32. A number of other predefined macros have different values for the two environments.</p> <p>I think the most straightforward way to detect x32 at compile time is to examine the <code>__x86_64__</code> and <code>SIZE_MAX</code> macros. The former is predefined (or not) by gcc, and the latter is defined in <code>&lt;stdint.h&gt;</code>.</p> <p>The following program demonstrates this. It works correctly with <code>gcc -m64</code>, <code>gcc -m32</code>, and <code>gcc -mx32</code> on an x86_64 system,, and with <code>gcc</code> on a non-x86_64 system (SPARC).</p> <pre><code>#include &lt;stdio.h&gt; #include &lt;stdint.h&gt; int main(void) { #ifdef __x86_64__ #if SIZE_MAX == 0xFFFFFFFF puts("This is x32"); #else puts("This is x86_64 but not x32"); #endif #else puts("This is not x64_64"); #endif } </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/32645109/how-to-detect-x32-abi-or-environment-in-the-preprocessor</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c-1" hreflang="zh-hans">c</a></div> <div class="field--item"><a href="/tag/gcc" hreflang="zh-hans">gcc</a></div> <div class="field--item"><a href="/tag/clang" hreflang="zh-hans">clang</a></div> <div class="field--item"><a href="/tag/c-preprocessor" hreflang="zh-hans">c-preprocessor</a></div> <div class="field--item"><a href="/tag/linux-x32-abi" hreflang="zh-hans">linux-x32-abi</a></div> </div> </div> Sun, 22 Dec 2019 18:58:21 +0000 老子叫甜甜 2784832 at https://www.e-learn.cn 64-bit executable runs slower than 32-bit version https://www.e-learn.cn/topic/2660691 <span>64-bit executable runs slower than 32-bit version</span> <span><span lang="" about="/user/172" typeof="schema:Person" property="schema:name" datatype="">无人久伴</span></span> <span>2019-12-20 03:07:17</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I have a 64-bit Ubuntu 13.04 system. I was curious to see how 32-bit applications perform against 64-bit applications on a 64-bit system so I compiled the following C program as 32-bit and 64-bit executable and recorded the time they took to execute. I used gcc flags to compile for 3 different architectures:</p> <ul><li><code>-m32</code>: Intel 80386 architecture (int, long, pointer all set to 32 bits (ILP32))</li> <li><code>-m64</code>: AMD's x86-64 architecture (int 32 bits; long, pointer 64 bits (LP64))</li> <li><code>-mx32</code>: AMD's x86-64 architecture (int, long, pointer all set to 32 bits (ILP32), but CPU in long mode with sixteen 64b registers, and register call ABI)</li> </ul><pre><code>// this program solves the // project euler problem 16. #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;math.h&gt; #include &lt;assert.h&gt; #include &lt;sys/time.h&gt; int sumdigit(int a, int b); int main(void) { int a = 2; int b = 10000; struct timeval start, finish; unsigned int i; gettimeofday(&amp;start, NULL); for(i = 0; i &lt; 1000; i++) (void)sumdigit(a, b); gettimeofday(&amp;finish, NULL); printf("Did %u calls in %.4g seconds\n", i, finish.tv_sec - start.tv_sec + 1E-6 * (finish.tv_usec - start.tv_usec)); return 0; } int sumdigit(int a, int b) { // numlen = number of digit in a^b // pcount = power of 'a' after ith iteration // dcount = number of digit in a^(pcount) int numlen = (int) (b * log10(a)) + 1; char *arr = calloc(numlen, sizeof *arr); int pcount = 0; int dcount = 1; arr[numlen - 1] = 1; int i, sum, carry; while(pcount &lt; b) { pcount += 1; sum = 0; carry = 0; for(i = numlen - 1; i &gt;= numlen - dcount; --i) { sum = arr[i] * a + carry; carry = sum / 10; arr[i] = sum % 10; } while(carry &gt; 0) { dcount += 1; sum = arr[numlen - dcount] + carry; carry = sum / 10; arr[numlen - dcount] = sum % 10; } } int result = 0; for(i = numlen - dcount; i &lt; numlen; ++i) result += arr[i]; free(arr); return result; } </code></pre> <p>The commands I used to get different executable:</p> <pre><code>gcc -std=c99 -Wall -Wextra -Werror -pedantic -pedantic-errors pe16.c -o pe16_x32 -lm -mx32 gcc -std=c99 -Wall -Wextra -Werror -pedantic -pedantic-errors pe16.c -o pe16_32 -lm -m32 gcc -std=c99 -Wall -Wextra -Werror -pedantic -pedantic-errors pe16.c -o pe16_64 -lm </code></pre> <p>Here are the results I got:</p> <pre><code>ajay@ajay:c$ ./pe16_x32 Did 1000 calls in 89.19 seconds ajay@ajay:c$ ./pe16_32 Did 1000 calls in 88.82 seconds ajay@ajay:c$ ./pe16_64 Did 1000 calls in 92.05 seconds </code></pre> <p>Why does the 64-bit version runs slower than the 32-bit one? I read that the 64-bit architecture has improved instruction set and twice more general purpose registers compared to the 32-bit architecture which allows for more optimizations. When can I expect a better performance on a 64-bit system?</p> <p><strong>Edit</strong> I turned on the optimization using <code>-O3</code> flag and now the results are:</p> <pre><code>ajay@ajay:c$ ./pe16_x32 Did 1000 calls in 38.07 seconds ajay@ajay:c$ ./pe16_32 Did 1000 calls in 38.32 seconds ajay@ajay:c$ ./pe16_64 Did 1000 calls in 38.27 seconds </code></pre> <br /><h3>回答1:</h3><br /><p>Comparing performance of code without optimisations is rather pointless. If you care about performance, you'll only ever use optimised code. </p> <p>And when you enable optimisations you find that the performance differences are negligible. That is to be expected. The operations you perform are all integer based operations, using data of the same size in all cases. Since the 32 bit and 64 bit code run on the same integer hardware units you should expect the same performance.</p> <p>You are not using any floating point operations which is one area where there are sometimes differences between 32 and 64 bit code due to different floating point hardware units (x64 uses SSE, x86 may use x87).</p> <p>In short, the results are exactly as expected.</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/21525610/64-bit-executable-runs-slower-than-32-bit-version</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c-1" hreflang="zh-hans">c</a></div> <div class="field--item"><a href="/tag/x86" hreflang="zh-hans">x86</a></div> <div class="field--item"><a href="/tag/32bit-64bit" hreflang="zh-hans">32bit-64bit</a></div> <div class="field--item"><a href="/tag/x86-64" hreflang="zh-hans">x86-64</a></div> <div class="field--item"><a href="/tag/linux-x32-abi" hreflang="zh-hans">linux-x32-abi</a></div> </div> </div> Thu, 19 Dec 2019 19:07:17 +0000 无人久伴 2660691 at https://www.e-learn.cn How should the [u]int_fastN_t types be defined for x86_64, with or without the x32 ABI? https://www.e-learn.cn/topic/2115941 <span>How should the [u]int_fastN_t types be defined for x86_64, with or without the x32 ABI?</span> <span><span lang="" about="/user/157" typeof="schema:Person" property="schema:name" datatype="">梦想的初衷</span></span> <span>2019-12-10 15:13:29</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>The x32 ABI specifies, among other things, 32-bit pointers for code generated for the x86_64 architecture. It combines the advantages of the x86_64 architecture (including 64-bit CPU registers) with the reduced overhead of 32-bit pointers.</p> <p>The <code>&lt;stdint.h&gt;</code> header defines typedefs <code>int_fast8_t</code>, <code>int_fast16_t</code>, <code>int_fast32_t</code>, and <code>int_fast64_t</code> (and corresponding unsigned types <code>uint_fast8_t</code> et al), each of which is:</p> <blockquote> <p>an integer type that is usually fastest to operate with among all integer types that have at least the specified width</p> </blockquote> <p>with a footnote:</p> <blockquote> <p>The designated type is not guaranteed to be fastest for all purposes; if the implementation has no clear grounds for choosing one type over another, it will simply pick some integer type satisfying the signedness and width requirements.</p> </blockquote> <p>(Quoted from the N1570 C11 draft.)</p> <p>The question is, how should <code>[u]int_fast16_t</code> and <code>[u]int_fast32_t</code> types be defined for the x86_64 architecture, with or without the x32 ABI? Is there an x32 document that specifies these types? Should they be compatible with the 32-bit x86 definitions (both 32 bits) or, since x32 has access to 64-bit CPU registers, should they be the same size with or without the x32 ABI? (Note that the x86_64 has 64-bit registers regardless of whether the x32 ABI is in use or not.)</p> <p>Here's a test program (which depends on the gcc-specific <code>__x86_64__</code> macro):</p> <pre><code>#include &lt;stdio.h&gt; #include &lt;stdint.h&gt; #include &lt;limits.h&gt; int main(void) { #if defined __x86_64__ &amp;&amp; SIZE_MAX == 0xFFFFFFFF puts("This is x86_64 with the x32 ABI"); #elif defined __x86_64__ &amp;&amp; SIZE_MAX &gt; 0xFFFFFFFF puts("This is x86_64 without the x32 ABI"); #else puts("This is not x86_64"); #endif printf("uint_fast8_t is %2zu bits\n", CHAR_BIT * sizeof (uint_fast8_t)); printf("uint_fast16_t is %2zu bits\n", CHAR_BIT * sizeof (uint_fast16_t)); printf("uint_fast32_t is %2zu bits\n", CHAR_BIT * sizeof (uint_fast32_t)); printf("uint_fast64_t is %2zu bits\n", CHAR_BIT * sizeof (uint_fast64_t)); } </code></pre> <p>When I compile it with <code>gcc -m64</code>, the output is:</p> <pre class="lang-none prettyprint-override"><code>This is x86_64 without the x32 ABI uint_fast8_t is 8 bits uint_fast16_t is 64 bits uint_fast32_t is 64 bits uint_fast64_t is 64 bits </code></pre> <p>When I compile it with <code>gcc -mx32</code>, the output is:</p> <pre class="lang-none prettyprint-override"><code>This is x86_64 with the x32 ABI uint_fast8_t is 8 bits uint_fast16_t is 32 bits uint_fast32_t is 32 bits uint_fast64_t is 64 bits </code></pre> <p>(which, apart from the first line, matches the output with <code>gcc -m32</code>, which generates 32-bit x86 code).</p> <p>Is this a bug in glibc (which defines the <code>&lt;stdint.h&gt;</code> header), or is it following some x32 ABI requirement? There are no references to the <code>[u]int_fastN_t</code> types in either the x32 ABI document or the x86_64 ABI document, but there could be something else that specifies it. </p> <p>One could argue that the fast16 and fast32 types should be 64 bits with or with x32, since 64-bit registers are available; would that makes more sense that the current behavior?</p> <p>(I've substantially edited the original question, which asked only about the x32 ABI. The question now asks about x86_64 with or without x32.)</p> <br /><h3>回答1:</h3><br /><p>Generally speaking you would expect 32-bit integer types to be marginally faster than 64-bit integer types on x86-64 CPUs. Partly because they use less memory, but also because 64-bit instructions require an extra prefix byte over their 32-bit counterparts. The 32-bit division instruction is significantly faster than 64-bit one, but otherwise instruction execution latencies are the same.</p> <p>It isn't normally necessary to extend 32-bit when loading them into 64-bit registers. While the CPU automatically zero-extends the values in this case, this is usually only a benefit because it avoids partial register stalls. What gets loaded into upper part of the register is less important than the fact that the entire register is modified. The contents of the upper part of the register don't matter because when they're used to hold 32-bit types they're normally only used with 32-bit instructions that only work with the lower 32-bit part of the register.</p> <p>The inconsistency between between the sizes of <code>int_fast32_t</code> types when using the x32 and x86-64 ABIs is probably best justified by the fact that pointers are 64 bits wide. Whenever a 32-bit integer is added to a pointer it would need to be extended, making this a much more likely occurrence when using the x86-64 ABI.</p> <p>Another factor to consider is that whole point of the x32 ABI is to get better performance by using smaller types. Any application that benefits from pointers and related types being smaller should also benefit from <code>int_fast32_t</code> being smaller as well.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>I have compiled the following sample code to check the generated code for a simple sum with different integer types:</p> <pre><code>#include &lt;stdint.h&gt; typedef int16_t INT; //typedef int32_t INT; //typedef int64_t INT; INT foo() { volatile INT a = 1, b = 2; return a + b; } </code></pre> <p>And then I disassembled the code generated with each of the integer types. The compilation command is <code>gcc -Ofast -mx32 -c test.c</code>. Note that in full 64-bit mode the generated code will be almost the same because there are no pointers in my code (only <code>%rsp</code> instead of <code>%esp</code>).</p> <p>With <code>int16_t</code> it emits:</p> <pre><code>00000000 &lt;foo&gt;: 0: b8 01 00 00 00 mov $0x1,%eax 5: ba 02 00 00 00 mov $0x2,%edx a: 67 66 89 44 24 fc mov %ax,-0x4(%esp) 10: 67 66 89 54 24 fe mov %dx,-0x2(%esp) 16: 67 0f b7 54 24 fc movzwl -0x4(%esp),%edx 1c: 67 0f b7 44 24 fe movzwl -0x2(%esp),%eax 22: 01 d0 add %edx,%eax 24: c3 retq </code></pre> <p>With <code>int32_t</code>:</p> <pre><code>00000000 &lt;foo&gt;: 0: 67 c7 44 24 f8 01 00 00 00 movl $0x1,-0x8(%esp) 9: 67 c7 44 24 fc 02 00 00 00 movl $0x2,-0x4(%esp) 12: 67 8b 54 24 f8 mov -0x8(%esp),%edx 17: 67 8b 44 24 fc mov -0x4(%esp),%eax 1c: 01 d0 add %edx,%eax 1e: c3 retq </code></pre> <p>And with <code>int64_t</code>:</p> <pre><code>00000000 &lt;foo&gt;: 0: 67 48 c7 44 24 f0 01 00 00 00 movq $0x1,-0x10(%esp) a: 67 48 c7 44 24 f8 02 00 00 00 movq $0x2,-0x8(%esp) 14: 67 48 8b 54 24 f0 mov -0x10(%esp),%rdx 1a: 67 48 8b 44 24 f8 mov -0x8(%esp),%rax 20: 48 01 d0 add %rdx,%rax 23: c3 retq </code></pre> <p>Now, I don't claim to know exactly why the compiler generated exactly this code (maybe the <code>volatile</code> keyword combined with a non-register-size integer type is not the best choice?). But from that generated code we can draw the following conclusions:</p> <ol><li>The slowest type is <code>int16_t</code>. It needs additional instructions to move the values around.</li> <li>The fastest type is <code>int32_t</code>. Although the 32-bit and the 64-bit versions have the same number of instructions, the 32-bit code is shorter in bytes, so it will be more cache friendly, so faster.</li> </ol><p>So the natural choices for the fast types would be:</p> <ol><li>For <code>int_fast16_t</code>, choose <code>int32_t</code>.</li> <li>For <code>int_fast32_t</code>, choose <code>int32_t</code>.</li> <li>For <code>int_fast64_t</code>, choose <code>int64_t</code> (what else).</li> </ol><br /><br /><br /><h3>回答3:</h3><br /><p>Tough. Let's just take int_fast8_t. If a developer uses a large array to store lots of 8 bit signed integers, then int8_t will be fastest because of caching. I'd declare that using large arrays of int_fast8_t is likely a bad idea. </p> <p>You'd need to take a large codebase, and systematically replace int8_t and signed chars and plain char if it is signed with int_fast8_t. Then benchmark the code using different typedefs for int_fast8_t, and measure what's fastest. </p> <p>Note that undefined behaviour is going to change. For example assigning 255 will give a result of -1 if the type is int8_t and 255 otherwise. </p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/36961100/how-should-the-uint-fastn-t-types-be-defined-for-x86-64-with-or-without-the-x</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c-1" hreflang="zh-hans">c</a></div> <div class="field--item"><a href="/tag/stdint" hreflang="zh-hans">stdint</a></div> <div class="field--item"><a href="/tag/linux-x32-abi" hreflang="zh-hans">linux-x32-abi</a></div> </div> </div> Tue, 10 Dec 2019 07:13:29 +0000 梦想的初衷 2115941 at https://www.e-learn.cn How to detect X32 on Windows? https://www.e-learn.cn/topic/1961941 <span>How to detect X32 on Windows?</span> <span><span lang="" about="/user/229" typeof="schema:Person" property="schema:name" datatype="">喜欢而已</span></span> <span>2019-12-08 03:51:15</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>X32 allows one to write programs using 32-bit integers, longs and pointers that run on x86_64 processors. Using X32 has a number of benefits under certain use cases. (X32 is different than X86 or X64; see Difference between x86, x32, and x64 architectures for more details).</p> <p>It appears some Windows Enterprise Server supports X32, but I'm having trouble finding more information on it. That's based on some Intel PDFs, like Intel® Xeon® Processor E5-2400 Series-based Platforms for Intelligent Systems:</p> <p></p> <p>Microsoft's documentation on Predefined Macros lists the usual suspect, like <code>_M_X64</code> and <code>_M_AMD64</code>. But it does not appear to discuss an architecture option for X32.</p> <p>If Microsoft supports X32, then I suspect it is going to be an option similar to large address space aware or terminal service aware.</p> <p>Does Microsoft <em>actually</em> support X32 (as opposed to X86 and X64)?</p> <ul><li>If so, how can I determine when X32 is being selected under Windows?</li> <li>If not, then why does Intel specifically call out the X32 platform for Windows?</li> </ul><br /><h3>回答1:</h3><br /><h2>The question</h2> <blockquote> <p>Does Microsoft actually support X32 (as opposed to X86 and X64)?</p> </blockquote> <h2>TL;DR answer</h2> <p>The answer is "No, it's not supported by Microsoft." The preprocessor macros don't lead to any identification of X32, the command line options and IDE options don't exist, and the strings identifying such a compiler don't exist.</p> <hr /><h2>The long answer — Part I</h2> <h3>"There are no header strings for X32"</h3> <p>Disregarding the following facts:</p> <ul><li>no official documentation of such a feature exists,</li> <li>no option in Visual Studio or <code>cl.exe /?</code> to enable/disable it exists, and</li> <li><code>strings -el clui.dll</code> shows no sign of such an option,</li> </ul><p><code>strings -el "%VCINSTALLDIR%\bin\1033\clui.dll" | find "Microsoft (R)"</code> shows no sign of a matching header string either:</p> <pre><code>4Microsoft (R) C/C++ Optimizing Compiler Version %s -for Microsoft (R) .NET Framework version %s (Microsoft (R) C/C++ Optimizing Compiler FMicrosoft (R) C/C++ Optimizing Compiler Version %s for MIPS R-Series )Microsoft (R) MIPS Assembler Version %s CMicrosoft (R) C/C++ Optimizing Compiler Version %s for Renesas SH &lt;Microsoft (R) C/C++ Optimizing Compiler Version %s for ARM :Microsoft (R) C/C++ Standard Compiler Version %s for x86 &lt;Microsoft (R) C/C++ Optimizing Compiler Version %s for x86 GMicrosoft (R) 32-bit C/C++ Optimizing Compiler Version %s for PowerPC @Microsoft (R) C/C++ Optimizing Compiler Version %s for Itanium &lt;Microsoft (R) C/C++ Optimizing Compiler Version %s for x64 &gt;Microsoft (R) C/C++ Optimizing Compiler Version %s for ARM64 Microsoft (R) MIPS Assembler </code></pre> <p>The same output is seen in the <code>bin\x86_amd64\1033\clui.dll</code> and <code>bin\x86_arm\1033\clui.dll</code> files, so it's not like that one file simply didn't include it.</p> <hr /><h2>The long answer — Part II</h2> <h3>"Windows doesn't do data models"</h3> <p>Let's suppose it did. How would you detect it? In the case of GLIBC, <code>__ILP32__</code> is defined for x32 and x86 while <code>__LP64__</code> is defined for amd64, denoting the data model used. Additionally, <code>__x86_64__</code> will be defined for the AMD64 architecture. If <code>__x86_64__</code> is defined and <code>__ILP32__</code> is defined, then you're using the X32 ABI, else you're using the AMD64 ABI. For C, that's all that matters. If you're utilizing assembly code, that's where the differentiation between the X32 ABI and the x86 ABI matters, hence checking <code>__x86_64__</code> to determine that the architecture targeted is 64-bit and checking <code>__ILP32__</code> to determine whether the 32-bit or 64-bit ABI is in use. For example:</p> <pre class="lang-c prettyprint-override"><code>#ifdef __x86_64__ # ifdef __ILP32__ // Use X32 version of myfunc(). extern long myfunc_x32 (const char *); long (*myfunc)(const char *) = myfunc_x32; # else /* !__ILP32__ */ // Use AMD64 version of myfunc(). extern long myfunc_amd64 (const char *); long (*myfunc)(const char *) = myfunc_amd64; # endif /* __ILP32__ */ /* !__x86_64__ */ #elif defined __i386__ // Use x86 version of myfunc(). extern long myfunc_x86 (const char *); long (*myfunc)(const char *) = myfunc_x86; /* !__i386__ */ #else // Use generic version of myfunc() since no optimized versions are available. long myfunc(const char *); #endif /* __x86_64__ */ </code></pre> <p>However, there is no macro indicating the data model on Windows. You target one of the following architectures:</p> <ul><li>32-bit x86 (<code>_M_IX86</code>)</li> <li>64-bit AMD64 (<code>_M_AMD64</code>/<code>_M_X64</code>)</li> <li>(32-bit?) ARM (<code>_M_ARM</code>)</li> </ul><p>Theoretically one could use <code>_M_AMD64</code> and <code>_M_X64</code> independently to determine whether X32 exists, but if <code>_M_AMD64</code> is defined, <code>_M_X64</code> is also defined.</p> <hr /><h2>The long answer — Part III</h2> <h3>"The bad news"</h3> <p>In the end, after searching to find anything, perhaps even long forgotten material, there is no evidence that Windows has supported or ever will support coding for an X32 ABI like Linux. The preprocessor macros don't help in identifying X32, the command line options and IDE options don't exist, and the strings identifying such a compiler don't exist.</p> <hr /><h2>The long answer — A new hope dashed</h2> <h3>"These aren't the macros you're looking for"</h3> <p>One could hypothetically use the currently existing macros to check, but it's not like it helps in this case because X32 for Windows doesn't exist. It's not unlike the GLIBC check, though instead of enabling X32 if <code>__ILP32__</code> is defined, you enable it if <code>_M_X64</code> is not defined.</p> <pre class="lang-c prettyprint-override"><code>#ifdef _M_AMD64 # ifndef _M_X64 # define ABI_STR "X32" # else # define ABI_STR "AMD64" # endif #elif defined _M_IX86 # define ABI_STR "X86" #else # error unsupported CPU/architecture #endif </code></pre> <p>Of course, if <code>_M_AMD64</code> is defined, then <code>_M_X64</code> is defined too, further reinforcing the evidence that there is no X32 for Windows.</p> <br /><br /><br /><h3>回答2:</h3><br /><blockquote> <p>Does Microsoft actually support X32 (as opposed to X86 and X64)?</p> </blockquote> <p>No. </p> <br /><br /><br /><h3>回答3:</h3><br /><p>Windows doesn't have an x32 ABI. However it has a feature that gives you memory only in the low 2GB of address space. Just disable the /LARGEADDRESSAWARE flag (by default it's enabled for 64-bit binaries) and then you can use 32-bit pointers inside your 64-bit application</p> <p>User space pointers in those binaries will have the top bits zeroed, so it's essentially just similar to x32 ABI on Linux. <code>long</code> in Windows has always been a 32-bit type, thus it's also the same as in x32 ABI where <code>long</code> and pointers are 32-bit wide</p> <blockquote> <p>By default, 64-bit Microsoft Windows-based applications have a user-mode address space of several terabytes. For precise values, see Memory Limits for Windows and Windows Server Releases. However, applications can specify that the system should allocate all memory for the application below 2 gigabytes. This feature is beneficial for 64-bit applications if the following conditions are true:</p> <ul><li>A 2 GB address space is sufficient.</li> <li>The code has many pointer truncation warnings.</li> <li>Pointers and integers are freely mixed.</li> <li>The code has polymorphism using 32-bit data types.</li> </ul><p>All pointers are still 64-bit pointers, but the system ensures that every memory allocation occurs below the 2 GB limit, so that if the application truncates a pointer, no significant data is lost. <strong>Pointers can be truncated to 32-bit values, then extended to 64-bit values by either sign extension or zero extension.</strong></p> <p>Virtual Address Space</p> </blockquote> <p>But nowadays even on Linux kernel developers are discussing to drop x32 Support</p> <br /><br /><br /><h3>回答4:</h3><br /><p>Sorry about the late answer (and the injustice to David).</p> <p>I was reading on <code>ml64.exe</code> at MASM for x64 (ml64.exe), and I came across <strong><em>32-Bit Address Mode</em></strong> in the assembler. It provides the X32 address size overrides.</p> <p>So it appears Windows tools do provide an X32 related support. It also explains how Intel can produce X32 binaries and drivers. I'm just speculating, but I suspect Intel is probably using a custom allocator or <code>VirtualAlloc</code> to ensure pointer addresses are in a certain range.</p> <p>It also appears that the Windows operating system does not have a custom built kernel, like say Debian 8, where its provided ground-up from the OS. That is, its up to the developer to ensure integers, longs and pointers are also within a 32-bit range.</p> <br /><br /><br /><h3>回答5:</h3><br /><p>Small footnote to phuclv's answer regarding disabling the /LARGEADDRESSAWARE for given process: In certain cases, when data structures are favorable, and one takes steps necessary to actually use 32-bit pointers in 64-bit mode, there is too potential for performance gains on Windows, as it is on Linux, albeit not as large. See: Benchmark of 32-bit pointers in 64-bit code on Windows</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/32675300/how-to-detect-x32-on-windows</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/windows" hreflang="zh-hans">windows</a></div> <div class="field--item"><a href="/tag/c-preprocessor" hreflang="zh-hans">c-preprocessor</a></div> <div class="field--item"><a href="/tag/32bit-64bit" hreflang="zh-hans">32bit-64bit</a></div> <div class="field--item"><a href="/tag/abi" hreflang="zh-hans">abi</a></div> <div class="field--item"><a href="/tag/linux-x32-abi" hreflang="zh-hans">linux-x32-abi</a></div> </div> </div> Sat, 07 Dec 2019 19:51:15 +0000 喜欢而已 1961941 at https://www.e-learn.cn How to detect X32 on Windows? https://www.e-learn.cn/topic/1857803 <span>How to detect X32 on Windows?</span> <span><span lang="" about="/user/203" typeof="schema:Person" property="schema:name" datatype="">眉间皱痕</span></span> <span>2019-12-06 15:51:14</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><div class="alert alert-danger" role="alert"> <p>X32 allows one to write programs using 32-bit integers, longs and pointers that run on x86_64 processors. Using X32 has a number of benefits under certain use cases. (X32 is different than X86 or X64; see <a href="https://stackoverflow.com/q/7635013/608639" rel="nofollow">Difference between x86, x32, and x64 architectures</a> for more details).</p> <p>It appears some Windows Enterprise Server supports X32, but I'm having trouble finding more information on it. That's based on some Intel PDFs, like <a href="https://www-ssl.intel.com/content/dam/www/public/us/en/documents/marketing-briefs/xeon-e5-2400-for-intelligent-systems-brief.pdf" rel="nofollow">Intel® Xeon® Processor E5-2400 Series-based Platforms for Intelligent Systems</a>:</p> <p><a href="https://i.stack.imgur.com/AvDwI.png" rel="nofollow"><p></p><p></p><img class="b-lazy" data-src="https://www.eimg.top/images/2020/03/18/5820e01106ebdf4890d3eb3b37d664d2.png" data-original="https://www.eimg.top/images/2020/03/18/5820e01106ebdf4890d3eb3b37d664d2.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /><p></p><p></p></a></p> <p>Microsoft's documentation on <a href="https://msdn.microsoft.com/en-us/library/b0084kay.aspx" rel="nofollow">Predefined Macros</a> lists the usual suspect, like <code>_M_X64</code> and <code>_M_AMD64</code>. But it does not appear to discuss an architecture option for X32.</p> <p>If Microsoft supports X32, then I suspect it is going to be an option similar to large address space aware or terminal service aware.</p> <p>Does Microsoft <em>actually</em> support X32 (as opposed to X86 and X64)?</p> <ul><li>If so, how can I determine when X32 is being selected under Windows?</li> <li>If not, then why does Intel specifically call out the X32 platform for Windows?</li> </ul></div><div class="panel panel-info"><div class="panel-heading"></div><div class="panel-body"> <h2>The question</h2> <blockquote> <p>Does Microsoft actually support X32 (as opposed to X86 and X64)?</p> </blockquote> <h2>TL;DR answer</h2> <p>The answer is "No, it's not supported by Microsoft." The preprocessor macros don't lead to any identification of X32, the command line options and IDE options don't exist, and the strings identifying such a compiler don't exist.</p> <hr /><h2>The long answer — Part I</h2> <h3>"There are no header strings for X32"</h3> <p>Disregarding the following facts:</p> <ul><li>no official documentation of such a feature exists,</li> <li>no option in Visual Studio or <code>cl.exe /?</code> to enable/disable it exists, and</li> <li><code>strings -el clui.dll</code> shows no sign of such an option,</li> </ul><p><code>strings -el "%VCINSTALLDIR%\bin\1033\clui.dll" | find "Microsoft (R)"</code> shows no sign of a matching header string either:</p> <pre><code>4Microsoft (R) C/C++ Optimizing Compiler Version %s -for Microsoft (R) .NET Framework version %s (Microsoft (R) C/C++ Optimizing Compiler FMicrosoft (R) C/C++ Optimizing Compiler Version %s for MIPS R-Series )Microsoft (R) MIPS Assembler Version %s CMicrosoft (R) C/C++ Optimizing Compiler Version %s for Renesas SH &lt;Microsoft (R) C/C++ Optimizing Compiler Version %s for ARM :Microsoft (R) C/C++ Standard Compiler Version %s for x86 &lt;Microsoft (R) C/C++ Optimizing Compiler Version %s for x86 GMicrosoft (R) 32-bit C/C++ Optimizing Compiler Version %s for PowerPC @Microsoft (R) C/C++ Optimizing Compiler Version %s for Itanium &lt;Microsoft (R) C/C++ Optimizing Compiler Version %s for x64 &gt;Microsoft (R) C/C++ Optimizing Compiler Version %s for ARM64 Microsoft (R) MIPS Assembler </code></pre> <p>The same output is seen in the <code>bin\x86_amd64\1033\clui.dll</code> and <code>bin\x86_arm\1033\clui.dll</code> files, so it's not like that one file simply didn't include it.</p> <hr /><h2>The long answer — Part II</h2> <h3>"Windows doesn't do data models"</h3> <p>Let's suppose it did. How would you detect it? In the case of GLIBC, <code>__ILP32__</code> is defined for x32 and x86 while <code>__LP64__</code> is defined for amd64, denoting <a href="http://sourceforge.net/p/predef/wiki/DataModels/" rel="nofollow">the data model used</a>. Additionally, <code>__x86_64__</code> will be defined for the AMD64 architecture. If <code>__x86_64__</code> is defined and <code>__ILP32__</code> is defined, then you're using the X32 ABI, else you're using the AMD64 ABI. For C, that's all that matters. If you're utilizing assembly code, that's where the differentiation between the X32 ABI and the x86 ABI matters, hence checking <code>__x86_64__</code> to determine that the architecture targeted is 64-bit and checking <code>__ILP32__</code> to determine whether the 32-bit or 64-bit ABI is in use. For example:</p> <pre class="lang-c prettyprint-override"><code>#ifdef __x86_64__ # ifdef __ILP32__ // Use X32 version of myfunc(). extern long myfunc_x32 (const char *); long (*myfunc)(const char *) = myfunc_x32; # else /* !__ILP32__ */ // Use AMD64 version of myfunc(). extern long myfunc_amd64 (const char *); long (*myfunc)(const char *) = myfunc_amd64; # endif /* __ILP32__ */ /* !__x86_64__ */ #elif defined __i386__ // Use x86 version of myfunc(). extern long myfunc_x86 (const char *); long (*myfunc)(const char *) = myfunc_x86; /* !__i386__ */ #else // Use generic version of myfunc() since no optimized versions are available. long myfunc(const char *); #endif /* __x86_64__ */ </code></pre> <p>However, there is no macro indicating the data model on Windows. You target one of the following architectures:</p> <ul><li>32-bit x86 (<code>_M_IX86</code>)</li> <li>64-bit AMD64 (<code>_M_AMD64</code>/<code>_M_X64</code>)</li> <li>(32-bit?) ARM (<code>_M_ARM</code>)</li> </ul><p>Theoretically one could use <code>_M_AMD64</code> and <code>_M_X64</code> independently to determine whether X32 exists, but if <code>_M_AMD64</code> is defined, <code>_M_X64</code> is also defined.</p> <hr /><h2>The long answer — Part III</h2> <h3>"The bad news"</h3> <p>In the end, after searching to find anything, perhaps even long forgotten material, there is no evidence that Windows has supported or ever will support coding for an X32 ABI like Linux. The preprocessor macros don't help in identifying X32, the command line options and IDE options don't exist, and the strings identifying such a compiler don't exist.</p> <hr /><h2>The long answer — A new hope dashed</h2> <h3>"These aren't the macros you're looking for"</h3> <p>One could hypothetically use the currently existing macros to check, but it's not like it helps in this case because X32 for Windows doesn't exist. It's not unlike the GLIBC check, though instead of enabling X32 if <code>__ILP32__</code> is defined, you enable it if <code>_M_X64</code> is not defined.</p> <pre class="lang-c prettyprint-override"><code>#ifdef _M_AMD64 # ifndef _M_X64 # define ABI_STR "X32" # else # define ABI_STR "AMD64" # endif #elif defined _M_IX86 # define ABI_STR "X86" #else # error unsupported CPU/architecture #endif </code></pre> <p>Of course, if <code>_M_AMD64</code> is defined, then <code>_M_X64</code> is defined too, further reinforcing the evidence that there is no X32 for Windows.</p> </div></div><div class="panel panel-info"><div class="panel-heading"></div><div class="panel-body"> <blockquote> <p>Does Microsoft actually support X32 (as opposed to X86 and X64)?</p> </blockquote> <p>No. </p> </div></div><div class="panel panel-info"><div class="panel-heading"></div><div class="panel-body"> <p>Windows doesn't have an <a href="https://en.wikipedia.org/wiki/X32_ABI" rel="nofollow">x32 ABI</a>. However it has a feature that gives you memory only in the low 2GB of address space. Just disable the <a href="https://docs.microsoft.com/en-us/cpp/build/reference/largeaddressaware-handle-large-addresses?view=vs-2017" rel="nofollow"><code>/LARGEADDRESSAWARE</code></a> flag (by default it's enabled for 64-bit binaries) and then you can use 32-bit pointers inside your 64-bit application</p> <p>User space pointers in those binaries will have the top bits zeroed, so it's essentially just similar to x32 ABI on Linux. <code>long</code> in Windows has always been a 32-bit type, thus it's also the same as in x32 ABI where <code>long</code> and pointers are 32-bit wide</p> <blockquote> <p>By default, 64-bit Microsoft Windows-based applications have a user-mode address space of several terabytes. For precise values, see Memory Limits for Windows and Windows Server Releases. However, applications can specify that the system should allocate all memory for the application below 2 gigabytes. This feature is beneficial for 64-bit applications if the following conditions are true:</p> <ul><li>A 2 GB address space is sufficient.</li> <li>The code has many pointer truncation warnings.</li> <li>Pointers and integers are freely mixed.</li> <li>The code has polymorphism using 32-bit data types.</li> </ul><p>All pointers are still 64-bit pointers, but the system ensures that every memory allocation occurs below the 2 GB limit, so that if the application truncates a pointer, no significant data is lost. <strong>Pointers can be truncated to 32-bit values, then extended to 64-bit values by either sign extension or zero extension.</strong></p> <p><a href="https://docs.microsoft.com/en-us/windows/desktop/WinProg64/virtual-address-space" rel="nofollow">Virtual Address Space</a></p> </blockquote> <p>But nowadays even on Linux <a href="https://www.phoronix.com/scan.php?page=news_item&amp;px=Linux-Potentially-Drops-x32" rel="nofollow">kernel developers are discussing to drop x32 Support</a></p> </div></div><div class="panel panel-info"><div class="panel-heading"></div><div class="panel-body"> <p>Sorry about the late answer (and the injustice to David).</p> <p>I was reading on <code>ml64.exe</code> at <a href="https://msdn.microsoft.com/en-us/library/hb5z4sxd.aspx" rel="nofollow">MASM for x64 (ml64.exe)</a>, and I came across <strong><em>32-Bit Address Mode</em></strong> in the assembler. It provides the X32 address size overrides.</p> <p>So it appears Windows tools do provide an X32 related support. It also explains how Intel can produce X32 binaries and drivers. I'm just speculating, but I suspect Intel is probably using a custom allocator or <code>VirtualAlloc</code> to ensure pointer addresses are in a certain range.</p> <p>It also appears that the Windows operating system does not have a custom built kernel, like say Debian 8, where its provided ground-up from the OS. That is, its up to the developer to ensure integers, longs and pointers are also within a 32-bit range.</p> </div></div><div class="panel panel-info"><div class="panel-heading"></div><div class="panel-body"> <p>Small footnote to phuclv's answer regarding disabling the /LARGEADDRESSAWARE for given process: In certain cases, when data structures are favorable, and one takes steps necessary to actually use 32-bit pointers in 64-bit mode, there is too potential for performance gains on Windows, as it is on Linux, albeit not as large. See: <a href="https://github.com/tringi/x32-abi-windows" rel="nofollow">Benchmark of 32-bit pointers in 64-bit code on Windows</a></p> </div></div><div class="alert alert-warning" role="alert"><p>来源:<code>https://stackoverflow.com/questions/32675300/how-to-detect-x32-on-windows</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/windows" hreflang="zh-hans">windows</a></div> <div class="field--item"><a href="/tag/c-preprocessor" hreflang="zh-hans">c-preprocessor</a></div> <div class="field--item"><a href="/tag/32bit-64bit" hreflang="zh-hans">32bit-64bit</a></div> <div class="field--item"><a href="/tag/abi" hreflang="zh-hans">abi</a></div> <div class="field--item"><a href="/tag/linux-x32-abi" hreflang="zh-hans">linux-x32-abi</a></div> </div> </div> Fri, 06 Dec 2019 07:51:14 +0000 眉间皱痕 1857803 at https://www.e-learn.cn