RFC [PATCH v2 1/2] <sys/tagged-address.h>: An API for tagged address

Message ID 20210223021725.3224499-2-hjl.tools@gmail.com
State Superseded
Headers
Series RFC [PATCH v2 1/2] <sys/tagged-address.h>: An API for tagged address |

Commit Message

H.J. Lu Feb. 23, 2021, 2:17 a.m. UTC
  By default, the number of the address bits used in address translation
is the number of address bits.  But it can be changed by ARM Top-byte
Ignore (TBI) or Intel Linear Address Masking (LAM).

<sys/tagged-address.h> provides an API for tagged address manipulation:

/* Get the current address bits used in address translation.  */
extern unsigned int get_tagged_address_bits (void);

/* Get the current mask for address bits used in address translation.  */
extern uintptr_t get_tagged_address_mask (void);

/* Set the mask for address bits used in address translation.  Return 0
   on success.  Return -1 on error.  */
extern int set_tagged_address_mask (uintptr_t __mask);

/* Return the tagged address of __ADDR with the tag value __TAG.  */
extern void *tag_address (void *__addr, unsigned int __tag);

/* Return the untagged address of __ADDR.  */
extern void *untag_address (void *__addr);

/* TRUE if constant address BITS is a valid tagged address bits.  */
 #define TAGGED_ADDRESS_VALID_BITS(BITS)

/* A mask for constant address BITS used in address translation.  */
 #define TAGGED_ADDRESS_MASK(BITS)

1. set_tagged_address_mask should be called as early as possible.
2. set_tagged_address_mask shouldn't be allowed after pthread_create is
called.  Otherwise different threads may have different masks for the
same address space.
3. After set_tagged_address_mask is called, don't allow it to be called
again to change the tagged address mask.  Otherwise, the previously
tagged addresses may not work anymore.
---
 NEWS                                          |  2 +
 bits/tagged-address.h                         | 28 +++++++++
 elf/dl-support.c                              |  5 ++
 include/sys/tagged-address.h                  |  9 +++
 manual/Makefile                               |  3 +-
 manual/ctype.texi                             |  2 +-
 manual/memory.texi                            |  2 +-
 manual/tagged-address.texi                    | 58 +++++++++++++++++++
 misc/Makefile                                 | 19 ++++--
 misc/Versions                                 |  7 +++
 misc/set-tagged-address-mask.c                | 42 ++++++++++++++
 misc/sys/tagged-address.h                     | 56 ++++++++++++++++++
 misc/tagged-address.c                         | 55 ++++++++++++++++++
 misc/tst-tagged-address-1-static.c            |  1 +
 misc/tst-tagged-address-1.c                   | 38 ++++++++++++
 misc/tst-tagged-address-2-static.c            |  1 +
 misc/tst-tagged-address-2.c                   | 44 ++++++++++++++
 misc/tst-tagged-address-3-static.c            |  1 +
 misc/tst-tagged-address-3.c                   | 38 ++++++++++++
 nptl/pthread_create.c                         |  4 ++
 sysdeps/generic/inline-tagged-address.h       | 43 ++++++++++++++
 sysdeps/generic/ldsodefs.h                    |  4 ++
 sysdeps/unix/sysv/linux/i386/libc.abilist     |  5 ++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |  5 ++
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |  5 ++
 25 files changed, 470 insertions(+), 7 deletions(-)
 create mode 100644 bits/tagged-address.h
 create mode 100644 include/sys/tagged-address.h
 create mode 100644 manual/tagged-address.texi
 create mode 100644 misc/set-tagged-address-mask.c
 create mode 100644 misc/sys/tagged-address.h
 create mode 100644 misc/tagged-address.c
 create mode 100644 misc/tst-tagged-address-1-static.c
 create mode 100644 misc/tst-tagged-address-1.c
 create mode 100644 misc/tst-tagged-address-2-static.c
 create mode 100644 misc/tst-tagged-address-2.c
 create mode 100644 misc/tst-tagged-address-3-static.c
 create mode 100644 misc/tst-tagged-address-3.c
 create mode 100644 sysdeps/generic/inline-tagged-address.h
  

Patch

diff --git a/NEWS b/NEWS
index 85e84fe536..16f547a301 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,8 @@  Version 2.34
 
 Major new features:
 
+* Add <sys/tagged-address.h> to provide an API for tagged address.
+
 * Add _SC_MINSIGSTKSZ and _SC_SIGSTKSZ.  When _SC_SIGSTKSZ_SOURCE or
   _GNU_SOURCE are defined, MINSIGSTKSZ and SIGSTKSZ are no longer
   constant on Linux.  MINSIGSTKSZ is redefined to sysconf(_SC_MINSIGSTKSZ)
diff --git a/bits/tagged-address.h b/bits/tagged-address.h
new file mode 100644
index 0000000000..ecd8a2942d
--- /dev/null
+++ b/bits/tagged-address.h
@@ -0,0 +1,28 @@ 
+/* Copyright (C) 2021 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_TAGGED_ADDRESS_H
+#define _BITS_TAGGED_ADDRESS_H 1
+
+#ifndef _SYS_TAGGED_ADDRESS_H
+# error "Never include this file directly.  Use <sys/tagged-address.h> instead"
+#endif
+
+/* Non-zero if constant address BITS is a valid tagged address bits.  */
+#define TAGGED_ADDRESS_VALID_BITS(BITS) 0
+
+#endif /* <bits/tagged-address.h> */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 7fc2ee78e2..ed72720330 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -213,6 +213,11 @@  struct link_map *_dl_sysinfo_map;
 
 # include "get-dynamic-info.h"
 #endif
+
+/* If nonzero, the mask for address bits used in address translation
+   is locked.  */
+int _dl_tagged_address_mask_locked;
+
 #include "setup-vdso.h"
 /* Define the vDSO function pointers.  */
 #include <dl-vdso-setup.c>
diff --git a/include/sys/tagged-address.h b/include/sys/tagged-address.h
new file mode 100644
index 0000000000..2e902f72b2
--- /dev/null
+++ b/include/sys/tagged-address.h
@@ -0,0 +1,9 @@ 
+#include <misc/sys/tagged-address.h>
+
+#ifndef _ISOMAC
+# include <inline-tagged-address.h>
+# define get_tagged_address_bits()	__get_tagged_address_bits ()
+# define get_tagged_address_mask()	__get_tagged_address_mask ()
+# define tag_address(addr, tag)		__tag_address ((addr), (tag))
+# define untag_address(addr)		__untag_address ((addr))
+#endif
diff --git a/manual/Makefile b/manual/Makefile
index e83444341e..08df2daa6b 100644
--- a/manual/Makefile
+++ b/manual/Makefile
@@ -34,7 +34,8 @@  info: $(objpfx)libc.info
 endif
 
 chapters = $(addsuffix .texi, \
-		       intro errno memory ctype string charset locale	\
+		       intro errno memory tagged-address ctype string	\
+		       charset locale					\
 		       message search pattern io stdio llio filesys	\
 		       pipe socket terminal syslog math arith time	\
 		       resource setjmp signal startup process ipc job	\
diff --git a/manual/ctype.texi b/manual/ctype.texi
index d0618c5c38..28af73ff0e 100644
--- a/manual/ctype.texi
+++ b/manual/ctype.texi
@@ -1,4 +1,4 @@ 
-@node Character Handling, String and Array Utilities, Memory, Top
+@node Character Handling, String and Array Utilities, Tagged Address, Top
 @c %MENU% Character testing and conversion functions
 @chapter Character Handling
 
diff --git a/manual/memory.texi b/manual/memory.texi
index b2cc65228a..4791c7c464 100644
--- a/manual/memory.texi
+++ b/manual/memory.texi
@@ -1,4 +1,4 @@ 
-@node Memory, Character Handling, Error Reporting, Top
+@node Memory, Tagged Address, Error Reporting, Top
 @chapter Virtual Memory Allocation And Paging
 @c %MENU% Allocating virtual memory and controlling paging
 @cindex memory allocation
diff --git a/manual/tagged-address.texi b/manual/tagged-address.texi
new file mode 100644
index 0000000000..f6aa695876
--- /dev/null
+++ b/manual/tagged-address.texi
@@ -0,0 +1,58 @@ 
+@node Tagged Address, Character Handling, Memory, Top
+@c %MENU% Tagged address functions and macros
+@chapter Tagged Address
+
+By default, the number of the address bits used in address translation
+is the number of address bits.  But it can be changed by ARM Top-byte
+Ignore (TBI) or Intel Linear Address Masking (LAM).
+
+@Theglibc{} provides several functions and macros in the header file
+@file{sys/tagged-address.h} to manipulate tagged address bits, which is
+the number of the address bits used in address translation.
+@pindex sys/tagged-address.h
+
+@deftypefun {unsigned int} get_tagged_address_bits (void)
+@standards{GNU, sys/tagged-address.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Get the current address bits used in address translation.
+@end deftypefun
+
+@deftypefun uintptr_t get_tagged_address_mask (void)
+@standards{GNU, sys/tagged-address.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Get the current mask for address bits used in address translation.
+@end deftypefun
+
+@deftypefun int set_tagged_address_mask (uintptr_t @var{mask})
+@standards{GNU, sys/tagged-address.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Set the mask for address bits used in address translation to @var{mask}.
+The return value is @code{0} on success and @code{-1} on failure.  This
+function can be called only once before @code{pthread_create}.  The
+possible @code{errno} error conditions are @code{ENODEV}, @code{EPERM},
+@code{EINVAL}, and @code{ENOSYS}.
+@end deftypefun
+
+@deftypefun {void *} tag_address (void *@var{addr}, unsigned int @var{tag})
+@standards{GNU, sys/tagged-address.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Return the address of @var{addr} with the tag value @var{tag} stored
+in the untranslated bits.  Overflow of @var{tag} in the untranslated
+bits are ignored.
+@end deftypefun
+
+@deftypefun {void *} untag_address (void *@var{addr})
+@standards{GNU, sys/tagged-address.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Return the address of @var{addr} with all zero untranslated bits.
+@end deftypefun
+
+@deftypefn Macro int TAGGED_ADDRESS_VALID_BITS (@var{bits})
+This macro returns a nonzero value (true) if @var{bits} a valid tagged
+address bits.
+@end deftypefn
+
+@deftypefn Macro {const uintptr_t} TAGGED_ADDRESS_MASK (@var{bits})
+This macro returns a mask for constant address @var{bits} used in address
+translation.
+@end deftypefn
diff --git a/misc/Makefile b/misc/Makefile
index b08d7c68ab..9a5a286f40 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -38,7 +38,8 @@  headers	:= sys/uio.h bits/uio-ext.h bits/uio_lim.h \
 	   bits/select2.h bits/hwcap.h sys/auxv.h \
 	   sys/sysmacros.h bits/sysmacros.h bits/types/struct_iovec.h \
 	   bits/err-ldbl.h bits/error-ldbl.h \
-	   sys/single_threaded.h
+	   sys/single_threaded.h \
+	   sys/tagged-address.h bits/tagged-address.h
 
 routines := brk sbrk sstk ioctl \
 	    readv writev preadv preadv64 pwritev pwritev64 \
@@ -73,7 +74,8 @@  routines := brk sbrk sstk ioctl \
 	    fgetxattr flistxattr fremovexattr fsetxattr getxattr \
 	    listxattr lgetxattr llistxattr lremovexattr lsetxattr \
 	    removexattr setxattr getauxval ifunc-impl-list makedev \
-	    allocate_once fd_to_filename single_threaded
+	    allocate_once fd_to_filename single_threaded \
+	    tagged-address set-tagged-address-mask
 
 generated += tst-error1.mtrace tst-error1-mem.out \
   tst-allocate_once.mtrace tst-allocate_once-mem.out
@@ -88,7 +90,10 @@  tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
 	 tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \
 	 tst-preadvwritev2 tst-preadvwritev64v2 tst-warn-wide \
 	 tst-ldbl-warn tst-ldbl-error tst-dbl-efgcvt tst-ldbl-efgcvt \
-	 tst-mntent-autofs tst-syscalls tst-mntent-escape
+	 tst-mntent-autofs tst-syscalls tst-mntent-escape \
+	 tst-tagged-address-1 tst-tagged-address-1-static \
+	 tst-tagged-address-2 tst-tagged-address-2-static \
+	 tst-tagged-address-3 tst-tagged-address-3-static
 
 # Tests which need libdl.
 ifeq (yes,$(build-shared))
@@ -96,7 +101,10 @@  tests += tst-gethostid
 endif
 
 tests-internal := tst-atomic tst-atomic-long tst-allocate_once
-tests-static := tst-empty
+tests-static := tst-empty \
+  tst-tagged-address-1-static \
+  tst-tagged-address-2-static \
+  tst-tagged-address-3-static
 
 # Test for the internal, non-exported __fd_to_filename function.
 tests-internal += tst-fd_to_filename
@@ -160,3 +168,6 @@  $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
 	$(evaluate-test)
 
 $(objpfx)tst-gethostid: $(libdl)
+
+$(objpfx)tst-tagged-address-2: $(shared-thread-library)
+$(objpfx)tst-tagged-address-2-static: $(static-thread-library)
diff --git a/misc/Versions b/misc/Versions
index 95666f6548..9e9ded4d5c 100644
--- a/misc/Versions
+++ b/misc/Versions
@@ -164,6 +164,13 @@  libc {
   GLIBC_2.32 {
     __libc_single_threaded;
   }
+  GLIBC_2.34 {
+    get_tagged_address_bits;
+    get_tagged_address_mask;
+    set_tagged_address_mask;
+    tag_address;
+    untag_address;
+  }
   GLIBC_PRIVATE {
     __madvise;
     __mktemp;
diff --git a/misc/set-tagged-address-mask.c b/misc/set-tagged-address-mask.c
new file mode 100644
index 0000000000..9b88163917
--- /dev/null
+++ b/misc/set-tagged-address-mask.c
@@ -0,0 +1,42 @@ 
+/* Copyright (C) 2021 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/>.  */
+
+#include <atomic.h>
+#include <sys/tagged-address.h>
+#include <ldsodefs.h>
+
+/* Set the mask for address bits used in address translation.  Return 0
+   on success.  Return -1 on error.  */
+
+int
+set_tagged_address_mask (uintptr_t mask)
+{
+  if (atomic_load_relaxed (&GL(dl_tagged_address_mask_locked)) != 0)
+    __set_errno (EPERM);
+  else
+    {
+      /* set_tagged_address_mask can only be called once.  */
+      atomic_store_relaxed (&GL(dl_tagged_address_mask_locked), 1);
+
+      /* Only NOP is allowed.  */
+      if (mask == __get_tagged_address_mask ())
+	return 0;
+
+      __set_errno (ENOSYS);
+    }
+  return -1;
+}
diff --git a/misc/sys/tagged-address.h b/misc/sys/tagged-address.h
new file mode 100644
index 0000000000..c8c1417306
--- /dev/null
+++ b/misc/sys/tagged-address.h
@@ -0,0 +1,56 @@ 
+/* Copyright (C) 2021 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 _SYS_TAGGED_ADDRESS_H
+#define _SYS_TAGGED_ADDRESS_H 1
+
+#include <features.h>
+#include <stdint.h>
+#include <bits/tagged-address.h>
+
+#ifdef __GNUC__
+/* A mask for constant address BITS used in address translation.  */
+# define TAGGED_ADDRESS_MASK(BITS)				\
+  (__extension__						\
+    ({								\
+       _Static_assert (TAGGED_ADDRESS_VALID_BITS (BITS),	\
+		       "Tagged address bits must be valid");	\
+       (((uintptr_t) 1) << (BITS)) - 1;				\
+     }))
+#endif
+
+__BEGIN_DECLS
+
+/* Get the current address bits used in address translation.  */
+extern unsigned int get_tagged_address_bits (void);
+
+/* Get the current mask for address bits used in address translation.  */
+extern uintptr_t get_tagged_address_mask (void);
+
+/* Set the mask for address bits used in address translation.  Return 0
+   on success.  Return -1 on error.  */
+extern int set_tagged_address_mask (uintptr_t __mask);
+
+/* Return the tagged address of __ADDR with the tag value __TAG.  */
+extern void *tag_address (void *__addr, unsigned int __tag);
+
+/* Return the untagged address of __ADDR.  */
+extern void *untag_address (void *__addr);
+
+__END_DECLS
+
+#endif /* <sys/tagged-address.h> */
diff --git a/misc/tagged-address.c b/misc/tagged-address.c
new file mode 100644
index 0000000000..df474f3d0b
--- /dev/null
+++ b/misc/tagged-address.c
@@ -0,0 +1,55 @@ 
+/* Copyright (C) 2021 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/>.  */
+
+#include <sys/tagged-address.h>
+
+#undef get_tagged_address_bits
+#undef get_tagged_address_mask
+#undef tag_address
+#undef untag_address
+
+/* Get the current address bits used in address translation.  */
+
+unsigned int
+get_tagged_address_bits (void)
+{
+  return __get_tagged_address_bits ();
+}
+
+/* Get the current mask for address bits used in address translation.  */
+
+uintptr_t
+get_tagged_address_mask (void)
+{
+  return __get_tagged_address_mask ();
+}
+
+/* Return the tagged address of ADDR with the tag value TAG.  */
+
+void *
+tag_address (void *addr, unsigned int tag)
+{
+  return __tag_address (addr, tag);
+}
+
+/* Return the untagged address of ADDR.  */
+
+void *
+untag_address (void *addr)
+{
+  return __untag_address (addr);
+}
diff --git a/misc/tst-tagged-address-1-static.c b/misc/tst-tagged-address-1-static.c
new file mode 100644
index 0000000000..3ed71a66c2
--- /dev/null
+++ b/misc/tst-tagged-address-1-static.c
@@ -0,0 +1 @@ 
+#include <tst-tagged-address-1.c>
diff --git a/misc/tst-tagged-address-1.c b/misc/tst-tagged-address-1.c
new file mode 100644
index 0000000000..e23482fb94
--- /dev/null
+++ b/misc/tst-tagged-address-1.c
@@ -0,0 +1,38 @@ 
+/* Tests for set_tagged_address_mask.
+   Copyright (C) 2021 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/>.  */
+
+#include <errno.h>
+#include <sys/tagged-address.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  if (set_tagged_address_mask (get_tagged_address_mask ()) != 0)
+    FAIL_EXIT1 ("set_tagged_address_mask failed: %m");
+
+  if (set_tagged_address_mask (get_tagged_address_mask ()) == 0)
+    FAIL_EXIT1 ("set_tagged_address_mask should fail");
+
+  if (errno != EPERM)
+    FAIL_EXIT1 ("set_tagged_address_mask: errno (%m) != EPERM");
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-tagged-address-2-static.c b/misc/tst-tagged-address-2-static.c
new file mode 100644
index 0000000000..ac0d95e6c0
--- /dev/null
+++ b/misc/tst-tagged-address-2-static.c
@@ -0,0 +1 @@ 
+#include <tst-tagged-address-2.c>
diff --git a/misc/tst-tagged-address-2.c b/misc/tst-tagged-address-2.c
new file mode 100644
index 0000000000..76caae4053
--- /dev/null
+++ b/misc/tst-tagged-address-2.c
@@ -0,0 +1,44 @@ 
+/* Test for set_tagged_address_mask with pthread.
+   Copyright (C) 2021 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/>.  */
+
+#include <errno.h>
+#include <sys/tagged-address.h>
+#include <support/xthread.h>
+#include <support/check.h>
+
+static void *
+tf (void *arg)
+{
+  if (set_tagged_address_mask (get_tagged_address_mask ()) == 0)
+    FAIL_EXIT1 ("set_tagged_address_mask should fail");
+
+  if (errno != EPERM)
+    FAIL_EXIT1 ("set_tagged_address_mask: errno (%m) != EPERM");
+
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  pthread_t thr = xpthread_create (NULL, tf, NULL);
+  xpthread_join (thr);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-tagged-address-3-static.c b/misc/tst-tagged-address-3-static.c
new file mode 100644
index 0000000000..1e3591e0d6
--- /dev/null
+++ b/misc/tst-tagged-address-3-static.c
@@ -0,0 +1 @@ 
+#include <tst-tagged-address-3.c>
diff --git a/misc/tst-tagged-address-3.c b/misc/tst-tagged-address-3.c
new file mode 100644
index 0000000000..8447ed3d2f
--- /dev/null
+++ b/misc/tst-tagged-address-3.c
@@ -0,0 +1,38 @@ 
+/* Tests for set_tagged_address_mask to turn off tagged address.
+   Copyright (C) 2021 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/>.  */
+
+#include <errno.h>
+#include <sys/tagged-address.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  uintptr_t mask = (uintptr_t) -1;
+  if (set_tagged_address_mask (mask) != 0)
+    FAIL_EXIT1 ("set_tagged_address_mask failed: %m");
+
+  uintptr_t curent_mask = get_tagged_address_mask ();
+  if (curent_mask != mask)
+    FAIL_EXIT1 ("get_tagged_address_mask failed: %p != %p",
+		(void *) curent_mask, (void *) mask);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 2cc3d25697..422aba4b6a 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -780,6 +780,10 @@  __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr,
       __sigdelset (&pd->sigmask, SIGCANCEL);
     }
 
+  /* Don't allow changing the mask for address bits used in address
+     translation after create_thread is called the first time.  */
+  atomic_store_relaxed (&GL(dl_tagged_address_mask_locked), 1);
+
   /* Start the thread.  */
   if (__glibc_unlikely (report_thread_creation (pd)))
     {
diff --git a/sysdeps/generic/inline-tagged-address.h b/sysdeps/generic/inline-tagged-address.h
new file mode 100644
index 0000000000..a016b16f21
--- /dev/null
+++ b/sysdeps/generic/inline-tagged-address.h
@@ -0,0 +1,43 @@ 
+/* Inline tagged address functions.  Generic version.
+   Copyright (C) 2021 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/>.  */
+
+#include <errno.h>
+
+static inline unsigned int
+__get_tagged_address_bits (void)
+{
+  return sizeof (uintptr_t) * 8;
+}
+
+static inline uintptr_t
+__get_tagged_address_mask (void)
+{
+  return (uintptr_t) -1;
+}
+
+static inline void *
+__tag_address (void *addr, unsigned int tag)
+{
+  return addr;
+}
+
+static inline void *
+__untag_address (void *addr)
+{
+  return addr;
+}
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 9720a4e446..5fc354bba2 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -480,6 +480,10 @@  struct rtld_global
 #else
   EXTERN int _dl_thread_gscope_count;
 #endif
+
+  /* If nonzero, the mask for address bits used in address translation
+     is locked.  */
+  EXTERN int _dl_tagged_address_mask_locked;
 #ifdef SHARED
 };
 # define __rtld_global_attribute__
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index ddc5837059..464c8af2ee 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2241,6 +2241,11 @@  GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 get_tagged_address_bits F
+GLIBC_2.34 get_tagged_address_mask F
+GLIBC_2.34 set_tagged_address_mask F
+GLIBC_2.34 tag_address F
+GLIBC_2.34 untag_address F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 2744bba4af..7486bf09bc 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2088,6 +2088,11 @@  GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 get_tagged_address_bits F
+GLIBC_2.34 get_tagged_address_mask F
+GLIBC_2.34 set_tagged_address_mask F
+GLIBC_2.34 tag_address F
+GLIBC_2.34 untag_address F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index ce2f4fb72b..d88202196f 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2185,3 +2185,8 @@  GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 get_tagged_address_bits F
+GLIBC_2.34 get_tagged_address_mask F
+GLIBC_2.34 set_tagged_address_mask F
+GLIBC_2.34 tag_address F
+GLIBC_2.34 untag_address F