Message ID | 20230212111044.610942-12-bugaevc@gmail.com |
---|---|
State | New |
Headers | show |
Series | Towards glibc on x86_64-gnu | expand |
Sergey Bugaev, le dim. 12 févr. 2023 14:10:42 +0300, a ecrit: > It seems that GCC expects TLS on x86_64 to be done relative to %fs, not %gs, so > that's what I attempted to do in tls.h. The main thing missing there is the > ability to actually set (and read) the %fs base address of a thread. It is my > understanding (but note that I have no idea what I'm talking about) that on > x86_64 the segment descriptors (as in GDT/LDT) are not used for this, segmentation has somewhat disappeared in x86_64, yes. > and instead the address can be set by writing to a MSR. Linux exposes > the arch_prctl (ARCH_[GS]ET_[FG]S) syscall for this; so maybe GNU Mach > could also have an explicit routine for this, perhaps like this: > > routine i386_set_fgs_base ( > target_thread: thread_t; > which: int; > value: rpc_vm_address_t); Indeed. > We should not need a getter routine, because one can simply inspect the target > thread's state (unless, again, I misunderstand things horribly). For 16bit fs/gs values we could read them from userland yes. But for fs/gs base, the FSGSBASE instruction is not available on all 64bit processors. And ATM in THREAD_TCB we want to be able to get the base of another thread. > diff --git a/sysdeps/mach/hurd/x86_64/static-start.S b/sysdeps/mach/hurd/x86_64/static-start.S > new file mode 100644 > index 00000000..982d3d52 > --- /dev/null > +++ b/sysdeps/mach/hurd/x86_64/static-start.S > @@ -0,0 +1,27 @@ > +/* Type of the TCB. */ > +typedef struct > +{ > + void *tcb; /* Points to this structure. */ > + dtv_t *dtv; /* Vector of pointers to TLS data. */ > + thread_t self; /* This thread's control port. */ > + int __glibc_padding1; > + int multiple_threads; > + int gscope_flag; > + uintptr_t sysinfo; > + uintptr_t stack_guard; > + uintptr_t pointer_guard; > + long __glibc_padding2[2]; > + int private_futex; ? Isn't that rather feature_1 ? > + int __glibc_padding3; > + /* Reservation of some values for the TM ABI. */ > + void *__private_tm[4]; > + /* GCC split stack support. */ > + void *__private_ss; > + /* The lowest address of shadow stack. */ > + unsigned long long int ssp_base; > + > + /* Keep these fields last, so offsets of fields above can continue being > + compatible with the x86_64 NPTL version. */ > + mach_port_t reply_port; /* This thread's reply port. */ > + struct hurd_sigstate *_hurd_sigstate; > + > + /* Used by the exception handling implementation in the dynamic loader. */ > + struct rtld_catch *rtld_catch; > +} tcbhead_t; > + > +/* GCC generates %fs:0x28 to access the stack guard. */ > +_Static_assert (offsetof (tcbhead_t, stack_guard) == 0x28, > + "stack guard offset"); > +/* libgcc uses %fs:0x70 to access the split stack pointer. */ > +_Static_assert (offsetof (tcbhead_t, __private_ss) == 0x70, > + "split stack pointer offset"); Indeed. Could you perhaps also add them to the i386 tls.h? > +/* FIXME */ > +# define __LIBC_NO_TLS() 0 We'll want an efficient way to know whether we have configured TLS indeed. At worse we can make it a global variable. > +/* The TCB can have any size and the memory following the address the > + thread pointer points to is unspecified. Allocate the TCB there. */ > +# define TLS_TCB_AT_TP 1 > +# define TLS_DTV_AT_TP 0 > + Also copy the comment above TCB_ALIGNMENT. > +/* Install new dtv for current thread. */ > +# define INSTALL_NEW_DTV(dtvp) THREAD_SETMEM (THREAD_SELF, dtv, dtvp) > +/* Return the address of the dtv for the current thread. */ > +# define THREAD_DTV() THREAD_GETMEM (THREAD_SELF, dtv) While at it, try to make the i386 version use that too? Samuel
On Sun, Feb 12, 2023 at 7:11 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: > > Sergey Bugaev, le dim. 12 févr. 2023 14:10:42 +0300, a ecrit: > > We should not need a getter routine, because one can simply inspect the target > > thread's state (unless, again, I misunderstand things horribly). > > For 16bit fs/gs values we could read them from userland yes. But for > fs/gs base, the FSGSBASE instruction is not available on all 64bit > processors. And ATM in THREAD_TCB we want to be able to get the base of > another thread. What I've meant is: __thread_get_state (whatever_thread, &state); uintptr_t its_fs_base = state->fs_base; You can't really do the same to *write* [fg]s_base, because doing thread_set_state on your own thread is bound to end badly. > > diff --git a/sysdeps/mach/hurd/x86_64/static-start.S b/sysdeps/mach/hurd/x86_64/static-start.S > > new file mode 100644 > > index 00000000..982d3d52 > > --- /dev/null > > +++ b/sysdeps/mach/hurd/x86_64/static-start.S > > @@ -0,0 +1,27 @@ > > +/* Type of the TCB. */ > > +typedef struct > > +{ > > + void *tcb; /* Points to this structure. */ > > + dtv_t *dtv; /* Vector of pointers to TLS data. */ > > + thread_t self; /* This thread's control port. */ > > + int __glibc_padding1; > > + int multiple_threads; > > + int gscope_flag; > > + uintptr_t sysinfo; > > + uintptr_t stack_guard; > > + uintptr_t pointer_guard; > > + long __glibc_padding2[2]; > > + int private_futex; > > ? Isn't that rather feature_1 ? sysdeps/mach/hurd/i386/tls.h has 'int private_futex;', which is where I stole this from. A quick grep confirms that it's never used, so we might rename both to feature_1, or maybe another instance of __glibc_padding. > > +/* GCC generates %fs:0x28 to access the stack guard. */ > > +_Static_assert (offsetof (tcbhead_t, stack_guard) == 0x28, > > + "stack guard offset"); > > +/* libgcc uses %fs:0x70 to access the split stack pointer. */ > > +_Static_assert (offsetof (tcbhead_t, __private_ss) == 0x70, > > + "split stack pointer offset"); > > Indeed. Could you perhaps also add them to the i386 tls.h? > > +/* Install new dtv for current thread. */ > > +# define INSTALL_NEW_DTV(dtvp) THREAD_SETMEM (THREAD_SELF, dtv, dtvp) > > +/* Return the address of the dtv for the current thread. */ > > +# define THREAD_DTV() THREAD_GETMEM (THREAD_SELF, dtv) > > While at it, try to make the i386 version use that too? Yeah, I have not ported the improvements back to the 32-bit version; maybe I should. Another cool one is doing fs/gs-relative access using GCC's __seg_fs/__seg_gs when supported. Sergey
Sergey Bugaev, le dim. 12 févr. 2023 19:25:11 +0300, a ecrit: > On Sun, Feb 12, 2023 at 7:11 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: > > Sergey Bugaev, le dim. 12 févr. 2023 14:10:42 +0300, a ecrit: > > > We should not need a getter routine, because one can simply inspect the target > > > thread's state (unless, again, I misunderstand things horribly). > > > > For 16bit fs/gs values we could read them from userland yes. But for > > fs/gs base, the FSGSBASE instruction is not available on all 64bit > > processors. And ATM in THREAD_TCB we want to be able to get the base of > > another thread. > > What I've meant is: > > __thread_get_state (whatever_thread, &state); > uintptr_t its_fs_base = state->fs_base; > > You can't really do the same to *write* [fg]s_base, because doing > thread_set_state on your own thread is bound to end badly. ? Well, sure, just like setting fs/gs through thread state was not done for i386. I don't see where you're aiming. Getting fs/gs from __thread_get_state won't actually give you the base, you'll just read something like 0. > > > diff --git a/sysdeps/mach/hurd/x86_64/static-start.S b/sysdeps/mach/hurd/x86_64/static-start.S > > > new file mode 100644 > > > index 00000000..982d3d52 > > > --- /dev/null > > > +++ b/sysdeps/mach/hurd/x86_64/static-start.S > > > @@ -0,0 +1,27 @@ > > > +/* Type of the TCB. */ > > > +typedef struct > > > +{ > > > + void *tcb; /* Points to this structure. */ > > > + dtv_t *dtv; /* Vector of pointers to TLS data. */ > > > + thread_t self; /* This thread's control port. */ > > > + int __glibc_padding1; > > > + int multiple_threads; > > > + int gscope_flag; > > > + uintptr_t sysinfo; > > > + uintptr_t stack_guard; > > > + uintptr_t pointer_guard; > > > + long __glibc_padding2[2]; > > > + int private_futex; > > > > ? Isn't that rather feature_1 ? > > sysdeps/mach/hurd/i386/tls.h has 'int private_futex;', which is where > I stole this from. A quick grep confirms that it's never used, Yes, this was just to align on the nptl tls.h. But apparently that got renamed and hurd's tls wasn't updated. > so we might rename both to feature_1, or maybe another instance of > __glibc_padding. Better stay coherent with the nptl version. > > > +/* GCC generates %fs:0x28 to access the stack guard. */ > > > +_Static_assert (offsetof (tcbhead_t, stack_guard) == 0x28, > > > + "stack guard offset"); > > > +/* libgcc uses %fs:0x70 to access the split stack pointer. */ > > > +_Static_assert (offsetof (tcbhead_t, __private_ss) == 0x70, > > > + "split stack pointer offset"); > > > > Indeed. Could you perhaps also add them to the i386 tls.h? > > > > +/* Install new dtv for current thread. */ > > > +# define INSTALL_NEW_DTV(dtvp) THREAD_SETMEM (THREAD_SELF, dtv, dtvp) > > > +/* Return the address of the dtv for the current thread. */ > > > +# define THREAD_DTV() THREAD_GETMEM (THREAD_SELF, dtv) > > > > While at it, try to make the i386 version use that too? > > Yeah, I have not ported the improvements back to the 32-bit version; > maybe I should. Better always keep things as coherent as possible. Otherwise another you will later wonder why in the hell we have differences between the two versions. > Another cool one is doing fs/gs-relative access using > GCC's __seg_fs/__seg_gs when supported. Yes, that's nice indeed! Samuel
* Samuel Thibault via Libc-alpha: > Sergey Bugaev, le dim. 12 févr. 2023 19:25:11 +0300, a ecrit: >> On Sun, Feb 12, 2023 at 7:11 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: >> > Sergey Bugaev, le dim. 12 févr. 2023 14:10:42 +0300, a ecrit: >> > > We should not need a getter routine, because one can simply inspect the target >> > > thread's state (unless, again, I misunderstand things horribly). >> > >> > For 16bit fs/gs values we could read them from userland yes. But for >> > fs/gs base, the FSGSBASE instruction is not available on all 64bit >> > processors. And ATM in THREAD_TCB we want to be able to get the base of >> > another thread. >> >> What I've meant is: >> >> __thread_get_state (whatever_thread, &state); >> uintptr_t its_fs_base = state->fs_base; >> >> You can't really do the same to *write* [fg]s_base, because doing >> thread_set_state on your own thread is bound to end badly. > > ? Well, sure, just like setting fs/gs through thread state was not done > for i386. > > I don't see where you're aiming. Getting fs/gs from __thread_get_state > won't actually give you the base, you'll just read something like 0. The convention is that the FSBASE address is at %fs:0. The x86-64 TLS ABI assumes this, so that it's possible to compute the global (not thread-specific) address of a TLS variable.
Florian Weimer, le dim. 12 févr. 2023 17:40:58 +0100, a ecrit: > * Samuel Thibault via Libc-alpha: > > > Sergey Bugaev, le dim. 12 févr. 2023 19:25:11 +0300, a ecrit: > >> On Sun, Feb 12, 2023 at 7:11 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: > >> > Sergey Bugaev, le dim. 12 févr. 2023 14:10:42 +0300, a ecrit: > >> > > We should not need a getter routine, because one can simply inspect the target > >> > > thread's state (unless, again, I misunderstand things horribly). > >> > > >> > For 16bit fs/gs values we could read them from userland yes. But for > >> > fs/gs base, the FSGSBASE instruction is not available on all 64bit > >> > processors. And ATM in THREAD_TCB we want to be able to get the base of > >> > another thread. > >> > >> What I've meant is: > >> > >> __thread_get_state (whatever_thread, &state); > >> uintptr_t its_fs_base = state->fs_base; > >> > >> You can't really do the same to *write* [fg]s_base, because doing > >> thread_set_state on your own thread is bound to end badly. > > > > ? Well, sure, just like setting fs/gs through thread state was not done > > for i386. > > > > I don't see where you're aiming. Getting fs/gs from __thread_get_state > > won't actually give you the base, you'll just read something like 0. > > The convention is that the FSBASE address is at %fs:0. Yes, but that works only for reading your own base, not the base of another thread. Samuel
On Sun, Feb 12, 2023 at 7:36 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: > > Sergey Bugaev, le dim. 12 févr. 2023 19:25:11 +0300, a ecrit: > > On Sun, Feb 12, 2023 at 7:11 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: > > > Sergey Bugaev, le dim. 12 févr. 2023 14:10:42 +0300, a ecrit: > > > > We should not need a getter routine, because one can simply inspect the target > > > > thread's state (unless, again, I misunderstand things horribly). > > > > > > For 16bit fs/gs values we could read them from userland yes. But for > > > fs/gs base, the FSGSBASE instruction is not available on all 64bit > > > processors. And ATM in THREAD_TCB we want to be able to get the base of > > > another thread. > > > > What I've meant is: > > > > __thread_get_state (whatever_thread, &state); > > uintptr_t its_fs_base = state->fs_base; > > > > You can't really do the same to *write* [fg]s_base, because doing > > thread_set_state on your own thread is bound to end badly. > > ? Well, sure, just like setting fs/gs through thread state was not done > for i386. > > I don't see where you're aiming. Getting fs/gs from __thread_get_state > won't actually give you the base, you'll just read something like 0. It is my understanding that the actual values of fs/gs (i.e. the index of a descriptor) are not useful on x86_64. But fs_base and gs_base are now things that you have to store in the thread state and save/restore on every context switch. fs_base and gs_base are like registers in their own right (well, MSRs are registers). Thus, it should be easy to read them from the state structure exposed by the kernel. But again, I really have very little understanding of this, so maybe I'm talking nonsense. Sergey
Sergey Bugaev, le dim. 12 févr. 2023 19:51:33 +0300, a ecrit: > On Sun, Feb 12, 2023 at 7:36 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: > > > > Sergey Bugaev, le dim. 12 févr. 2023 19:25:11 +0300, a ecrit: > > > On Sun, Feb 12, 2023 at 7:11 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: > > > > Sergey Bugaev, le dim. 12 févr. 2023 14:10:42 +0300, a ecrit: > > > > > We should not need a getter routine, because one can simply inspect the target > > > > > thread's state (unless, again, I misunderstand things horribly). > > > > > > > > For 16bit fs/gs values we could read them from userland yes. But for > > > > fs/gs base, the FSGSBASE instruction is not available on all 64bit > > > > processors. And ATM in THREAD_TCB we want to be able to get the base of > > > > another thread. > > > > > > What I've meant is: > > > > > > __thread_get_state (whatever_thread, &state); > > > uintptr_t its_fs_base = state->fs_base; > > > > > > You can't really do the same to *write* [fg]s_base, because doing > > > thread_set_state on your own thread is bound to end badly. > > > > ? Well, sure, just like setting fs/gs through thread state was not done > > for i386. > > > > I don't see where you're aiming. Getting fs/gs from __thread_get_state > > won't actually give you the base, you'll just read something like 0. > > It is my understanding that the actual values of fs/gs (i.e. the index > of a descriptor) are not useful on x86_64. But fs_base and gs_base are > now things that you have to store in the thread state and save/restore > on every context switch. fs_base and gs_base are like registers in > their own right (well, MSRs are registers). Thus, it should be easy to > read them from the state structure exposed by the kernel. Ah, so you mean adding the fs/gs bases to the thread_state content. I'd rather make it a separate state content, like we have a separate i386_DEBUG_STATE content. (And thus no need for a new RPC). Samuel
On Sun, Feb 12, 2023 at 8:02 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: > I'd rather make it a separate state content, like we have a separate > i386_DEBUG_STATE content. > > (And thus no need for a new RPC). Makes sense to me! 👍 Sergey
* Samuel Thibault: > Florian Weimer, le dim. 12 févr. 2023 17:40:58 +0100, a ecrit: >> * Samuel Thibault via Libc-alpha: >> >> > Sergey Bugaev, le dim. 12 févr. 2023 19:25:11 +0300, a ecrit: >> >> On Sun, Feb 12, 2023 at 7:11 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: >> >> > Sergey Bugaev, le dim. 12 févr. 2023 14:10:42 +0300, a ecrit: >> >> > > We should not need a getter routine, because one can simply inspect the target >> >> > > thread's state (unless, again, I misunderstand things horribly). >> >> > >> >> > For 16bit fs/gs values we could read them from userland yes. But for >> >> > fs/gs base, the FSGSBASE instruction is not available on all 64bit >> >> > processors. And ATM in THREAD_TCB we want to be able to get the base of >> >> > another thread. >> >> >> >> What I've meant is: >> >> >> >> __thread_get_state (whatever_thread, &state); >> >> uintptr_t its_fs_base = state->fs_base; >> >> >> >> You can't really do the same to *write* [fg]s_base, because doing >> >> thread_set_state on your own thread is bound to end badly. >> > >> > ? Well, sure, just like setting fs/gs through thread state was not done >> > for i386. >> > >> > I don't see where you're aiming. Getting fs/gs from __thread_get_state >> > won't actually give you the base, you'll just read something like 0. >> >> The convention is that the FSBASE address is at %fs:0. > > Yes, but that works only for reading your own base, not the base of > another thread. Well, yes, but how do you identify the other thread? Usually by the address of its TCB.
Florian Weimer, le dim. 12 févr. 2023 20:29:43 +0100, a ecrit: > * Samuel Thibault: > > > Florian Weimer, le dim. 12 févr. 2023 17:40:58 +0100, a ecrit: > >> * Samuel Thibault via Libc-alpha: > >> > >> > Sergey Bugaev, le dim. 12 févr. 2023 19:25:11 +0300, a ecrit: > >> >> On Sun, Feb 12, 2023 at 7:11 PM Samuel Thibault <samuel.thibault@gnu.org> wrote: > >> >> > Sergey Bugaev, le dim. 12 févr. 2023 14:10:42 +0300, a ecrit: > >> >> > > We should not need a getter routine, because one can simply inspect the target > >> >> > > thread's state (unless, again, I misunderstand things horribly). > >> >> > > >> >> > For 16bit fs/gs values we could read them from userland yes. But for > >> >> > fs/gs base, the FSGSBASE instruction is not available on all 64bit > >> >> > processors. And ATM in THREAD_TCB we want to be able to get the base of > >> >> > another thread. > >> >> > >> >> What I've meant is: > >> >> > >> >> __thread_get_state (whatever_thread, &state); > >> >> uintptr_t its_fs_base = state->fs_base; > >> >> > >> >> You can't really do the same to *write* [fg]s_base, because doing > >> >> thread_set_state on your own thread is bound to end badly. > >> > > >> > ? Well, sure, just like setting fs/gs through thread state was not done > >> > for i386. > >> > > >> > I don't see where you're aiming. Getting fs/gs from __thread_get_state > >> > won't actually give you the base, you'll just read something like 0. > >> > >> The convention is that the FSBASE address is at %fs:0. > > > > Yes, but that works only for reading your own base, not the base of > > another thread. > > Well, yes, but how do you identify the other thread? Usually by the > address of its TCB. Yes, but that's not (yet) the case in htl. Samuel
diff --git a/sysdeps/mach/hurd/x86_64/static-start.S b/sysdeps/mach/hurd/x86_64/static-start.S new file mode 100644 index 00000000..982d3d52 --- /dev/null +++ b/sysdeps/mach/hurd/x86_64/static-start.S @@ -0,0 +1,27 @@ +/* Startup code for statically linked Hurd/x86_64 binaries. + Copyright (C) 1998-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + + .text + .globl _start +_start: + call _hurd_stack_setup + xorq %rdx, %rdx + jmp _start1 + +#define _start _start1 +#include <sysdeps/x86_64/start.S> diff --git a/sysdeps/mach/hurd/x86_64/tls.h b/sysdeps/mach/hurd/x86_64/tls.h new file mode 100644 index 00000000..027304d9 --- /dev/null +++ b/sysdeps/mach/hurd/x86_64/tls.h @@ -0,0 +1,182 @@ +/* Definitions for thread-local data handling. Hurd/x86_64 version. + Copyright (C) 2003-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _X86_64_TLS_H +#define _X86_64_TLS_H + + +/* Some things really need not be machine-dependent. */ +#include <sysdeps/mach/hurd/tls.h> + + +#ifndef __ASSEMBLER__ +# include <dl-dtv.h> + +/* Type of the TCB. */ +typedef struct +{ + void *tcb; /* Points to this structure. */ + dtv_t *dtv; /* Vector of pointers to TLS data. */ + thread_t self; /* This thread's control port. */ + int __glibc_padding1; + int multiple_threads; + int gscope_flag; + uintptr_t sysinfo; + uintptr_t stack_guard; + uintptr_t pointer_guard; + long __glibc_padding2[2]; + int private_futex; + int __glibc_padding3; + /* Reservation of some values for the TM ABI. */ + void *__private_tm[4]; + /* GCC split stack support. */ + void *__private_ss; + /* The lowest address of shadow stack. */ + unsigned long long int ssp_base; + + /* Keep these fields last, so offsets of fields above can continue being + compatible with the x86_64 NPTL version. */ + mach_port_t reply_port; /* This thread's reply port. */ + struct hurd_sigstate *_hurd_sigstate; + + /* Used by the exception handling implementation in the dynamic loader. */ + struct rtld_catch *rtld_catch; +} tcbhead_t; + +/* GCC generates %fs:0x28 to access the stack guard. */ +_Static_assert (offsetof (tcbhead_t, stack_guard) == 0x28, + "stack guard offset"); +/* libgcc uses %fs:0x70 to access the split stack pointer. */ +_Static_assert (offsetof (tcbhead_t, __private_ss) == 0x70, + "split stack pointer offset"); + +/* FIXME */ +# define __LIBC_NO_TLS() 0 + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 +# define TLS_DTV_AT_TP 0 + +# define TCB_ALIGNMENT 64 + +# define TLS_INIT_TP(descr) 0 + +# if __GNUC_PREREQ (6, 0) + +# define THREAD_SELF \ + (*(tcbhead_t * __seg_fs *) offsetof (tcbhead_t, tcb)) +# define THREAD_GETMEM(descr, member) \ + (*(__typeof (descr->member) __seg_fs *) offsetof (tcbhead_t, member)) +# define THREAD_SETMEM(descr, member, value) \ + (*(__typeof (descr->member) __seg_fs *) offsetof (tcbhead_t, member) = value) + +# else + +# define THREAD_SELF \ + ({ tcbhead_t *__tcb; \ + asm ("movq %%fs:%c1,%0" : "=r" (__tcb) \ + : "i" (offsetof (tcbhead_t, tcb))); \ + __tcb; }) + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(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,%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (tcbhead_t, member))); \ + else if (sizeof (__value) == 4) \ + asm volatile ("movl %%fs:%P1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (tcbhead_t, member))); \ + else /* 8 */ \ + asm volatile ("movq %%fs:%P1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (tcbhead_t, member))); \ + __value; }) + +/* Write member of the thread descriptor directly. */ +# define THREAD_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" : \ + : "iq" (value), \ + "i" (offsetof (tcbhead_t, member))); \ + else if (sizeof (descr->member) == 4) \ + asm volatile ("movl %0,%%fs:%P1" : \ + : "ir" (value), \ + "i" (offsetof (tcbhead_t, member))); \ + else /* 8 */ \ + asm volatile ("movq %0,%%fs:%P1" : \ + : "ir" (value), \ + "i" (offsetof (tcbhead_t, member))); \ + }) +# endif /* __GNUC_PREREQ (6, 0) */ + +/* Set the stack guard field in TCB head. */ +# define THREAD_SET_STACK_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, stack_guard, value) +# define THREAD_COPY_STACK_GUARD(descr) \ + ((descr)->stack_guard \ + = THREAD_GETMEM (THREAD_SELF, stack_guard)) + +/* Set the pointer guard field in the TCB head. */ +# define THREAD_SET_POINTER_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, pointer_guard, value) +# define THREAD_COPY_POINTER_GUARD(descr) \ + ((descr)->pointer_guard \ + = THREAD_GETMEM (THREAD_SELF, pointer_guard)) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtvp) THREAD_SETMEM (THREAD_SELF, dtv, dtvp) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() THREAD_GETMEM (THREAD_SELF, dtv) + +/* Global scope switch support. */ +# define THREAD_GSCOPE_FLAG_UNUSED 0 +# define THREAD_GSCOPE_FLAG_USED 1 +# define THREAD_GSCOPE_FLAG_WAIT 2 + +# define THREAD_GSCOPE_SET_FLAG() \ + THREAD_SETMEM (THREAD_SELF, gscope_flag, THREAD_GSCOPE_FLAG_USED) + +# define THREAD_GSCOPE_RESET_FLAG() \ + ({ \ + int __flag; \ + asm volatile ("xchgl %0, %%fs:%P1" \ + : "=r" (__flag) \ + : "i" (offsetof (tcbhead_t, gscope_flag)), \ + "0" (THREAD_GSCOPE_FLAG_UNUSED)); \ + if (__flag == THREAD_GSCOPE_FLAG_WAIT) \ + lll_wake (THREAD_SELF->gscope_flag, LLL_PRIVATE); \ + }) + + + +#endif /* __ASSEMBLER__ */ +#endif /* x86_64/tls.h */ diff --git a/sysdeps/mach/hurd/x86_64/tlsdesc.sym b/sysdeps/mach/hurd/x86_64/tlsdesc.sym new file mode 100644 index 00000000..da3b96c1 --- /dev/null +++ b/sysdeps/mach/hurd/x86_64/tlsdesc.sym @@ -0,0 +1,22 @@ +#include <stddef.h> +#include <sysdep.h> +#include <tls.h> +#include <link.h> +#include <dl-tlsdesc.h> + +-- + +-- We have to override sysdeps/x86_64/tlsdesc.sym to adapt to our libpthread. + +-- Abuse tls.h macros to derive offsets relative to the thread register. + +DTV_OFFSET offsetof(tcbhead_t, dtv) + +TLSDESC_ARG offsetof(struct tlsdesc, arg) + +TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count) +TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module) +TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset) + +TI_MODULE_OFFSET offsetof(tls_index, ti_module) +TI_OFFSET_OFFSET offsetof(tls_index, ti_offset) diff --git a/sysdeps/x86_64/htl/bits/pthreadtypes-arch.h b/sysdeps/x86_64/htl/bits/pthreadtypes-arch.h new file mode 100644 index 00000000..c3ac991b --- /dev/null +++ b/sysdeps/x86_64/htl/bits/pthreadtypes-arch.h @@ -0,0 +1,36 @@ +/* Machine-specific pthread type layouts. Hurd x86_64 version. + Copyright (C) 2002-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _BITS_PTHREADTYPES_ARCH_H +#define _BITS_PTHREADTYPES_ARCH_H 1 + +#define __SIZEOF_PTHREAD_MUTEX_T 32 +#define __SIZEOF_PTHREAD_ATTR_T 48 +#define __SIZEOF_PTHREAD_RWLOCK_T 48 +#define __SIZEOF_PTHREAD_BARRIER_T 40 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 16 +#define __SIZEOF_PTHREAD_COND_T 40 +#define __SIZEOF_PTHREAD_CONDATTR_T 8 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 4 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#define __SIZEOF_PTHREAD_ONCE_T 8 + +#define __LOCK_ALIGNMENT __attribute__ ((__aligned__(4))) +#define __ONCE_ALIGNMENT + +#endif /* bits/pthreadtypes.h */ diff --git a/sysdeps/x86_64/htl/machine-sp.h b/sysdeps/x86_64/htl/machine-sp.h new file mode 100644 index 00000000..7ae1c941 --- /dev/null +++ b/sysdeps/x86_64/htl/machine-sp.h @@ -0,0 +1,29 @@ +/* Machine-specific function to return the stack pointer. x86_64 version. + Copyright (C) 1994-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _MACHINE_SP_H +#define _MACHINE_SP_H + +/* Return the current stack pointer. */ + +#define __thread_stack_pointer() ({ \ + register uintptr_t __sp__ asm("rsp"); \ + __sp__; \ +}) + +#endif /* machine-sp.h */ diff --git a/sysdeps/x86_64/htl/pt-machdep.h b/sysdeps/x86_64/htl/pt-machdep.h new file mode 100644 index 00000000..2e2846fa --- /dev/null +++ b/sysdeps/x86_64/htl/pt-machdep.h @@ -0,0 +1,28 @@ +/* Machine dependent pthreads internal defenitions. x86_64 version. + Copyright (C) 2000-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _PT_MACHDEP_H +#define _PT_MACHDEP_H 1 + +struct pthread_mcontext +{ + void *pc; + void *sp; +}; + +#endif /* pt-machdep.h */
tls.h in particular is very unfinished. Signed-off-by: Sergey Bugaev <bugaevc@gmail.com> --- sysdeps/mach/hurd/x86_64/static-start.S | 27 +++ sysdeps/mach/hurd/x86_64/tls.h | 182 ++++++++++++++++++++ sysdeps/mach/hurd/x86_64/tlsdesc.sym | 22 +++ sysdeps/x86_64/htl/bits/pthreadtypes-arch.h | 36 ++++ sysdeps/x86_64/htl/machine-sp.h | 29 ++++ sysdeps/x86_64/htl/pt-machdep.h | 28 +++ 6 files changed, 324 insertions(+) create mode 100644 sysdeps/mach/hurd/x86_64/static-start.S create mode 100644 sysdeps/mach/hurd/x86_64/tls.h create mode 100644 sysdeps/mach/hurd/x86_64/tlsdesc.sym create mode 100644 sysdeps/x86_64/htl/bits/pthreadtypes-arch.h create mode 100644 sysdeps/x86_64/htl/machine-sp.h create mode 100644 sysdeps/x86_64/htl/pt-machdep.h