diff mbox series

[v12,14/17] nptl: Introduce RSEQ_GETMEM_VOLATILE and RSEQ_SETMEM

Message ID 20240801-rseq-abi-v11-split-v12-14-0e87479dddc0@efficios.com
State New
Headers show
Series Add rseq extensible ABI support | expand

Commit Message

Michael Jeanson Aug. 5, 2024, 8:48 p.m. UTC
This will be used to access and write to the rseq area in the extra TLS
block.

Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
---
 sysdeps/i386/nptl/tcb-access.h   | 61 ++++++++++++++++++++++++++++++++++++++++
 sysdeps/nptl/tcb-access.h        |  5 ++++
 sysdeps/x86_64/nptl/tcb-access.h | 61 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 127 insertions(+)

Comments

Florian Weimer Sept. 14, 2024, 11:19 a.m. UTC | #1
* Michael Jeanson:

> diff --git a/sysdeps/nptl/tcb-access.h b/sysdeps/nptl/tcb-access.h
> index 600433766f..9532f30022 100644
> --- a/sysdeps/nptl/tcb-access.h
> +++ b/sysdeps/nptl/tcb-access.h
> @@ -30,3 +30,8 @@
>    descr->member = (value)
>  #define THREAD_SETMEM_NC(descr, member, idx, value) \
>    descr->member[idx] = (value)
> +
> +#define RSEQ_GETMEM_VOLATILE(descr, member) \
> +  THREAD_GETMEM_VOLATILE(descr, member)
> +#define RSEQ_SETMEM(descr, member, value) \
> +  THREAD_SETMEM(descr, member, value)

Please add a comments to these macros to explain their use.

I'm not sure if you should use THREAD_GETMEM if you don't use it with
THREAD_SELF.  I assume you instead of passing struct pthread *, you are
going to pass a struct rseq_abi * here.  This is a bit too bit magic.
Maybe use __thread_pointer?  THREAD_GETMEM is only expected to be used
in the context of the thread whose data is being accessed.

Thanks,
Florian
Michael Jeanson Oct. 10, 2024, 8:24 p.m. UTC | #2
On 2024-09-14 13:19, Florian Weimer wrote:
> * Michael Jeanson:
> 
>> diff --git a/sysdeps/nptl/tcb-access.h b/sysdeps/nptl/tcb-access.h
>> index 600433766f..9532f30022 100644
>> --- a/sysdeps/nptl/tcb-access.h
>> +++ b/sysdeps/nptl/tcb-access.h
>> @@ -30,3 +30,8 @@
>>    descr->member = (value)
>>  #define THREAD_SETMEM_NC(descr, member, idx, value) \
>>    descr->member[idx] = (value)
>> +
>> +#define RSEQ_GETMEM_VOLATILE(descr, member) \
>> +  THREAD_GETMEM_VOLATILE(descr, member)
>> +#define RSEQ_SETMEM(descr, member, value) \
>> +  THREAD_SETMEM(descr, member, value)
> 
> Please add a comments to these macros to explain their use.

Ack.

> 
> I'm not sure if you should use THREAD_GETMEM if you don't use it with
> THREAD_SELF.  I assume you instead of passing struct pthread *, you are
> going to pass a struct rseq_abi * here.  This is a bit too bit magic.
> Maybe use __thread_pointer?  THREAD_GETMEM is only expected to be used
> in the context of the thread whose data is being accessed.

Should I split these macros out of tcb-access.h in a new header with a
generic version in 'sysdeps/nptl' and arch specific versions in
'sysdeps/ARCH/nptl' ?
Florian Weimer Oct. 14, 2024, 6:34 a.m. UTC | #3
* Michael Jeanson:

> On 2024-09-14 13:19, Florian Weimer wrote:
>> * Michael Jeanson:
>> 
>>> diff --git a/sysdeps/nptl/tcb-access.h b/sysdeps/nptl/tcb-access.h
>>> index 600433766f..9532f30022 100644
>>> --- a/sysdeps/nptl/tcb-access.h
>>> +++ b/sysdeps/nptl/tcb-access.h
>>> @@ -30,3 +30,8 @@
>>>    descr->member = (value)
>>>  #define THREAD_SETMEM_NC(descr, member, idx, value) \
>>>    descr->member[idx] = (value)
>>> +
>>> +#define RSEQ_GETMEM_VOLATILE(descr, member) \
>>> +  THREAD_GETMEM_VOLATILE(descr, member)
>>> +#define RSEQ_SETMEM(descr, member, value) \
>>> +  THREAD_SETMEM(descr, member, value)
>> 
>> Please add a comments to these macros to explain their use.
>
> Ack.
>
>> 
>> I'm not sure if you should use THREAD_GETMEM if you don't use it with
>> THREAD_SELF.  I assume you instead of passing struct pthread *, you are
>> going to pass a struct rseq_abi * here.  This is a bit too bit magic.
>> Maybe use __thread_pointer?  THREAD_GETMEM is only expected to be used
>> in the context of the thread whose data is being accessed.
>
> Should I split these macros out of tcb-access.h in a new header with a
> generic version in 'sysdeps/nptl' and arch specific versions in
> 'sysdeps/ARCH/nptl' ?

I don't think a new separate header is required if you can re-use an
existing header.  Maybe the generic version should just duplicate the
definitions of THREAD_GETMEM_VOLATILE and THREAD_SETMEM?  So that a
port that changes only the THREAD_* functions does not accidentally
use them for RSEQ_*MEM?
diff mbox series

Patch

diff --git a/sysdeps/i386/nptl/tcb-access.h b/sysdeps/i386/nptl/tcb-access.h
index 4b6221e103..eb40906c48 100644
--- a/sysdeps/i386/nptl/tcb-access.h
+++ b/sysdeps/i386/nptl/tcb-access.h
@@ -123,3 +123,64 @@ 
 			 "i" (offsetof (struct pthread, member)),	      \
 			 "r" (idx));					      \
        }})
+
+
+#if IS_IN (rtld)
+/* Use the hidden symbol in ld.so.  */
+# define rseq_offset_sym _rseq_offset
+#else
+# define rseq_offset_sym __rseq_offset
+#endif
+
+/* Read member of the RSEQ area directly.  */
+#define RSEQ_GETMEM_VOLATILE(descr, member) \
+  ({ __typeof (descr->member) __value;					      \
+     _Static_assert (sizeof (__value) == 1				      \
+		     || sizeof (__value) == 4				      \
+		     || sizeof (__value) == 8,				      \
+		     "size of per-thread data");			      \
+     if (sizeof (__value) == 1)						      \
+       asm volatile ("movb %%gs:%P2(%3),%b0"				      \
+		     : "=q" (__value)					      \
+		     : "0" (0), "i" (offsetof (struct rseq_area, member)),   \
+		     "r" (rseq_offset_sym));					      \
+     else if (sizeof (__value) == 4)					      \
+       asm volatile ("movl %%gs:%P1(%2),%0"				      \
+		     : "=r" (__value)					      \
+		     : "i" (offsetof (struct rseq_area, member)),	      \
+		       "r" (rseq_offset_sym));					      \
+     else /* 8 */							      \
+       {								      \
+	 asm volatile  ("movl %%gs:%P1(%2),%%eax\n\t"			      \
+			"movl %%gs:4+%P1(%2),%%edx"			      \
+			: "=&A" (__value)				      \
+			: "i" (offsetof (struct rseq_area, member)),	      \
+			  "r" (rseq_offset_sym));				      \
+       }								      \
+     __value; })
+
+/* Set member of the RSEQ area directly.  */
+#define RSEQ_SETMEM(descr, member, value) \
+  ({									      \
+     _Static_assert (sizeof (descr->member) == 1			      \
+		     || sizeof (descr->member) == 4			      \
+		     || sizeof (descr->member) == 8,			      \
+		     "size of per-thread data");			      \
+     if (sizeof (descr->member) == 1)					      \
+       asm volatile ("movb %b0,%%gs:%P1(%2)" :				      \
+		     : "iq" (value),					      \
+		       "i" (offsetof (struct rseq_area, member)),	      \
+		       "r" (rseq_offset_sym));					      \
+     else if (sizeof (descr->member) == 4)				      \
+       asm volatile ("movl %0,%%gs:%P1(%2)" :				      \
+		     : "ir" (value),					      \
+		       "i" (offsetof (struct rseq_area, member)),	      \
+		       "r" (rseq_offset_sym));					      \
+     else /* 8 */							      \
+       {								      \
+	 asm volatile ("movl %%eax,%%gs:%P1(%2)\n\t"			      \
+		       "movl %%edx,%%gs:4+%P1(%2)" :			      \
+		       : "A" ((uint64_t) cast_to_integer (value)),	      \
+			 "i" (offsetof (struct rseq_area, member)),	      \
+			 "r" (rseq_offset_sym));				      \
+       }})
diff --git a/sysdeps/nptl/tcb-access.h b/sysdeps/nptl/tcb-access.h
index 600433766f..9532f30022 100644
--- a/sysdeps/nptl/tcb-access.h
+++ b/sysdeps/nptl/tcb-access.h
@@ -30,3 +30,8 @@ 
   descr->member = (value)
 #define THREAD_SETMEM_NC(descr, member, idx, value) \
   descr->member[idx] = (value)
+
+#define RSEQ_GETMEM_VOLATILE(descr, member) \
+  THREAD_GETMEM_VOLATILE(descr, member)
+#define RSEQ_SETMEM(descr, member, value) \
+  THREAD_SETMEM(descr, member, value)
diff --git a/sysdeps/x86_64/nptl/tcb-access.h b/sysdeps/x86_64/nptl/tcb-access.h
index d35948f111..2edead755e 100644
--- a/sysdeps/x86_64/nptl/tcb-access.h
+++ b/sysdeps/x86_64/nptl/tcb-access.h
@@ -130,3 +130,64 @@ 
 			 "i" (offsetof (struct pthread, member[0])),	      \
 			 "r" (idx));					      \
        }})
+
+#if IS_IN (rtld)
+/* Use the hidden symbol in ld.so.  */
+# define rseq_offset_sym _rseq_offset
+#else
+# define rseq_offset_sym __rseq_offset
+#endif
+
+/* Read member of the RSEQ area directly.  */
+# define RSEQ_GETMEM_VOLATILE(descr, member) \
+  ({ __typeof (descr->member) __value;					      \
+     _Static_assert (sizeof (__value) == 1				      \
+		     || sizeof (__value) == 4				      \
+		     || sizeof (__value) == 8,				      \
+		     "size of per-thread data");			      \
+     if (sizeof (__value) == 1)						      \
+       asm volatile ("movb %%fs:%P2(%q3),%b0"				      \
+		     : "=q" (__value)					      \
+		     : "0" (0), "i" (offsetof (struct rseq_area, member)),    \
+		       "r" (rseq_offset_sym));					      \
+     else if (sizeof (__value) == 4)					      \
+       asm volatile ("movl %%fs:%P1(%q2),%0"				      \
+		     : "=r" (__value)					      \
+		     : "i" (offsetof (struct rseq_area, member)),	      \
+		       "r" (rseq_offset_sym));					      \
+     else /* 8 */							      \
+       {								      \
+	 asm volatile ("movq %%fs:%P1(%q2),%q0"				      \
+		       : "=r" (__value)					      \
+		       : "i" (offsetof (struct rseq_area, member)),	      \
+			 "r" (rseq_offset_sym));				      \
+       }								      \
+     __value; })
+
+/* Set member of the RSEQ area directly.  */
+# define RSEQ_SETMEM(descr, member, value) \
+  ({									      \
+     _Static_assert (sizeof (descr->member) == 1			      \
+		     || sizeof (descr->member) == 4			      \
+		     || sizeof (descr->member) == 8,			      \
+		     "size of per-thread data");			      \
+     if (sizeof (descr->member) == 1)					      \
+       asm volatile ("movb %b0,%%fs:%P1(%q2)" :				      \
+		     : "iq" (value),					      \
+		       "i" (offsetof (struct rseq_area, member)),	      \
+		       "r" (rseq_offset_sym));					      \
+     else if (sizeof (descr->member) == 4)				      \
+       asm volatile ("movl %0,%%fs:%P1(%q2)" :				      \
+		     : IMM_MODE (value),				      \
+		       "i" (offsetof (struct rseq_area, member)),	      \
+		       "r" (rseq_offset_sym));					      \
+     else /* 8 */							      \
+       {								      \
+	 /* Since movq takes a signed 32-bit immediate or a register source   \
+	    operand, use "er" constraint for 32-bit signed integer constant   \
+	    or register.  */						      \
+	 asm volatile ("movq %q0,%%fs:%P1(%q2)" :			      \
+		       : "er" ((uint64_t) cast_to_integer (value)),	      \
+			 "i" (offsetof (struct rseq_area, member)),	      \
+			 "r" (rseq_offset_sym));				      \
+       }})