1 /* THREAD_* accessors. x86_64 version. 2 Copyright (C) 2002-2022 Free Software Foundation, Inc. 3 This file is part of the GNU C Library. 4 5 The GNU C Library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 The GNU C Library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with the GNU C Library; if not, see 17 <https://www.gnu.org/licenses/>. */ 18 19 /* Read member of the thread descriptor directly. */ 20 # define THREAD_GETMEM(descr, member) \ 21 ({ __typeof (descr->member) __value; \ 22 _Static_assert (sizeof (__value) == 1 \ 23 || sizeof (__value) == 4 \ 24 || sizeof (__value) == 8, \ 25 "size of per-thread data"); \ 26 if (sizeof (__value) == 1) \ 27 asm volatile ("movb %%fs:%P2,%b0" \ 28 : "=q" (__value) \ 29 : "0" (0), "i" (offsetof (struct pthread, member))); \ 30 else if (sizeof (__value) == 4) \ 31 asm volatile ("movl %%fs:%P1,%0" \ 32 : "=r" (__value) \ 33 : "i" (offsetof (struct pthread, member))); \ 34 else /* 8 */ \ 35 { \ 36 asm volatile ("movq %%fs:%P1,%q0" \ 37 : "=r" (__value) \ 38 : "i" (offsetof (struct pthread, member))); \ 39 } \ 40 __value; }) 41 42 /* THREAD_GETMEM already forces a read. */ 43 #define THREAD_GETMEM_VOLATILE(descr, member) THREAD_GETMEM (descr, member) 44 45 /* Same as THREAD_GETMEM, but the member offset can be non-constant. */ 46 # define THREAD_GETMEM_NC(descr, member, idx) \ 47 ({ __typeof (descr->member[0]) __value; \ 48 _Static_assert (sizeof (__value) == 1 \ 49 || sizeof (__value) == 4 \ 50 || sizeof (__value) == 8, \ 51 "size of per-thread data"); \ 52 if (sizeof (__value) == 1) \ 53 asm volatile ("movb %%fs:%P2(%q3),%b0" \ 54 : "=q" (__value) \ 55 : "0" (0), "i" (offsetof (struct pthread, member[0])), \ 56 "r" (idx)); \ 57 else if (sizeof (__value) == 4) \ 58 asm volatile ("movl %%fs:%P1(,%q2,4),%0" \ 59 : "=r" (__value) \ 60 : "i" (offsetof (struct pthread, member[0])), "r" (idx));\ 61 else /* 8 */ \ 62 { \ 63 asm volatile ("movq %%fs:%P1(,%q2,8),%q0" \ 64 : "=r" (__value) \ 65 : "i" (offsetof (struct pthread, member[0])), \ 66 "r" (idx)); \ 67 } \ 68 __value; }) 69 70 71 /* Loading addresses of objects on x86-64 needs to be treated special 72 when generating PIC code. */ 73 #ifdef __pic__ 74 # define IMM_MODE "nr" 75 #else 76 # define IMM_MODE "ir" 77 #endif 78 79 80 /* Set member of the thread descriptor directly. */ 81 # define THREAD_SETMEM(descr, member, value) \ 82 ({ \ 83 _Static_assert (sizeof (descr->member) == 1 \ 84 || sizeof (descr->member) == 4 \ 85 || sizeof (descr->member) == 8, \ 86 "size of per-thread data"); \ 87 if (sizeof (descr->member) == 1) \ 88 asm volatile ("movb %b0,%%fs:%P1" : \ 89 : "iq" (value), \ 90 "i" (offsetof (struct pthread, member))); \ 91 else if (sizeof (descr->member) == 4) \ 92 asm volatile ("movl %0,%%fs:%P1" : \ 93 : IMM_MODE (value), \ 94 "i" (offsetof (struct pthread, member))); \ 95 else /* 8 */ \ 96 { \ 97 /* Since movq takes a signed 32-bit immediate or a register source \ 98 operand, use "er" constraint for 32-bit signed integer constant \ 99 or register. */ \ 100 asm volatile ("movq %q0,%%fs:%P1" : \ 101 : "er" ((uint64_t) cast_to_integer (value)), \ 102 "i" (offsetof (struct pthread, member))); \ 103 }}) 104 105 106 /* Same as THREAD_SETMEM, but the member offset can be non-constant. */ 107 # define THREAD_SETMEM_NC(descr, member, idx, value) \ 108 ({ \ 109 _Static_assert (sizeof (descr->member[0]) == 1 \ 110 || sizeof (descr->member[0]) == 4 \ 111 || sizeof (descr->member[0]) == 8, \ 112 "size of per-thread data"); \ 113 if (sizeof (descr->member[0]) == 1) \ 114 asm volatile ("movb %b0,%%fs:%P1(%q2)" : \ 115 : "iq" (value), \ 116 "i" (offsetof (struct pthread, member[0])), \ 117 "r" (idx)); \ 118 else if (sizeof (descr->member[0]) == 4) \ 119 asm volatile ("movl %0,%%fs:%P1(,%q2,4)" : \ 120 : IMM_MODE (value), \ 121 "i" (offsetof (struct pthread, member[0])), \ 122 "r" (idx)); \ 123 else /* 8 */ \ 124 { \ 125 /* Since movq takes a signed 32-bit immediate or a register source \ 126 operand, use "er" constraint for 32-bit signed integer constant \ 127 or register. */ \ 128 asm volatile ("movq %q0,%%fs:%P1(,%q2,8)" : \ 129 : "er" ((uint64_t) cast_to_integer (value)), \ 130 "i" (offsetof (struct pthread, member[0])), \ 131 "r" (idx)); \ 132 }}) 133