[v4,1/2] <sys/tagged-address.h>: An API for tagged address

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

Commit Message

H.J. Lu April 20, 2021, 2:18 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 main is called.
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-mask.h                    | 47 +++++++++++++++
 bits/tagged-address.h                         | 28 +++++++++
 csu/libc-start.c                              |  3 +
 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                    | 59 +++++++++++++++++++
 misc/Makefile                                 | 34 +++++++++--
 misc/Versions                                 |  7 +++
 misc/set-tagged-address-mask.c                | 41 +++++++++++++
 misc/sys/tagged-address.h                     | 45 ++++++++++++++
 misc/tagged-address.c                         | 55 +++++++++++++++++
 misc/tst-tagged-address-1-static.c            |  1 +
 misc/tst-tagged-address-1.c                   | 53 +++++++++++++++++
 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                   | 48 +++++++++++++++
 misc/tst-tagged-address-4-static.c            |  1 +
 misc/tst-tagged-address-4.c                   | 35 +++++++++++
 misc/tst-tagged-address-5.c                   | 25 ++++++++
 misc/tst-tagged-address-6.c                   | 34 +++++++++++
 misc/tst-tagged-address-7.c                   | 40 +++++++++++++
 misc/tst-tagged-address-mod-5.c               | 45 ++++++++++++++
 misc/tst-tagged-address-mod-6.c               | 34 +++++++++++
 misc/tst-tagged-address-mod-7.c               | 34 +++++++++++
 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 ++
 34 files changed, 792 insertions(+), 8 deletions(-)
 create mode 100644 bits/tagged-address-mask.h
 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 misc/tst-tagged-address-4-static.c
 create mode 100644 misc/tst-tagged-address-4.c
 create mode 100644 misc/tst-tagged-address-5.c
 create mode 100644 misc/tst-tagged-address-6.c
 create mode 100644 misc/tst-tagged-address-7.c
 create mode 100644 misc/tst-tagged-address-mod-5.c
 create mode 100644 misc/tst-tagged-address-mod-6.c
 create mode 100644 misc/tst-tagged-address-mod-7.c
 create mode 100644 sysdeps/generic/inline-tagged-address.h
  

Comments

Florian Weimer April 21, 2021, 6:36 a.m. UTC | #1
* H. J. Lu:

> diff --git a/manual/tagged-address.texi b/manual/tagged-address.texi
> new file mode 100644
> index 0000000000..ce10f7e752
> --- /dev/null
> +++ b/manual/tagged-address.texi
> @@ -0,0 +1,59 @@
> +@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

I don't under stand the “which is the number of address bits” part.

This section needs to describe under which circumstances it is valid to
alter the tag bits in pointers returned from glibc functions (including
system call wrappers).  I think at least historically, the kernel
required masking tag bits in user space for TBI.

> +@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.  The return
> +value is @code{0} if tag bits are not the highest bits in address.
> +@end deftypefun

“in addresses”?

What is the return value if there are no tag bits available?  The word
width?

> +@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

Mask is ambiguous in this context.  If a bit is set in the return value,
will this bit take part in address translation or not?  Please be
explicit here.

> +@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{main}.  The possible
> +@code{errno} error conditions are @code{ENODEV}, @code{EPERM},
> +@code{EINVAL}, and @code{ENOSYS}.
> +@end deftypefun

Likewise, please clarify if bits set in MASK participate in address
translation or not.

Why before main?  Do you mean it can only be called once per process?

I think this limitation suggests we should use ELF markup for this.
There are definitely compatibility issues to work out here.

Historically, the x86-64 psABI supplement implied that the top 16 bits
are available for application use (without hardware masking obviously).
If e.g. malloc starts returning tagged addresses, that assumption
breaks.

Should glibc allocate tag bits to different libraries within the same
process?  For example, so that malloc could get 2 tag bits, the main
program 3 and some other library 1 bit?

For glibc malloc, it would be a simple enhancement to move the
IS_MMAPPED to a tag bit, and eliminate the malloc header for mmap'ed
chunks, replacing it with a separate data structure.  This would allow
us to preserve page alignment for mmap'ed chunks without wasting an
entire page for each allocation, just to store the malloc header.

> +@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

This should reference the earlier discussion about when it is safe to
tag and untag addresses.

> +@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

“are valid tagged”?

Does “valid” mean in this context that “the CPU can be configured to
ignore bits set in BITS during address translation using
set_tagged_address_mask”?

> +@deftypefn Macro {const uintptr_t} TAGGED_ADDRESS_MASK (@var{bits})
> +This macro returns a nonzero value if it can be used as mask for constant
> +address @var{bits} used in address translation.
> +@end deftypefn

I do not understand the description.

Thanks,
Florian
  
H.J. Lu April 21, 2021, 11:21 p.m. UTC | #2
On Tue, Apr 20, 2021 at 11:36 PM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu:
>
> > diff --git a/manual/tagged-address.texi b/manual/tagged-address.texi
> > new file mode 100644
> > index 0000000000..ce10f7e752
> > --- /dev/null
> > +++ b/manual/tagged-address.texi
> > @@ -0,0 +1,59 @@
> > +@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
>
> I don't under stand the “which is the number of address bits” part.

For tagged addresses, not all bits are used in address translation.
For TBI, only the lower 48 bits are used in address translation.
For LAM, it can be either the lower 48 bits or 57 bits.

> This section needs to describe under which circumstances it is valid to
> alter the tag bits in pointers returned from glibc functions (including

Tagged address is enabled only when get_tagged_address_mask () != -1.

> system call wrappers).  I think at least historically, the kernel
> required masking tag bits in user space for TBI.

I believe this has been fixed in the recent kernel.

> > +@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.  The return
> > +value is @code{0} if tag bits are not the highest bits in address.
> > +@end deftypefun
>
> “in addresses”?

Fixed.

> What is the return value if there are no tag bits available?  The word
> width?

I am adding:

The return value is the number of address bits when tagged address is
unsupported.

>
> > +@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
>
> Mask is ambiguous in this context.  If a bit is set in the return value,
> will this bit take part in address translation or not?  Please be
> explicit here.

Fixed.

> > +@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{main}.  The possible
> > +@code{errno} error conditions are @code{ENODEV}, @code{EPERM},
> > +@code{EINVAL}, and @code{ENOSYS}.
> > +@end deftypefun
>
> Likewise, please clarify if bits set in MASK participate in address
> translation or not.

Fixed.

> Why before main?  Do you mean it can only be called once per process?

The feedback is that it should be called as early as possible:

https://sourceware.org/pipermail/libc-alpha/2021-February/122795.html

> I think this limitation suggests we should use ELF markup for this.
> There are definitely compatibility issues to work out here.

See:

https://gitlab.com/x86-psABIs/x86-64-ABI/-/commits/usr/hjl/lam

> Historically, the x86-64 psABI supplement implied that the top 16 bits
> are available for application use (without hardware masking obviously).
> If e.g. malloc starts returning tagged addresses, that assumption
> breaks.

These applications must be changed to support LAM.

> Should glibc allocate tag bits to different libraries within the same
> process?  For example, so that malloc could get 2 tag bits, the main
> program 3 and some other library 1 bit?

My API proposal doesn't prevent this scheme.

> For glibc malloc, it would be a simple enhancement to move the
> IS_MMAPPED to a tag bit, and eliminate the malloc header for mmap'ed
> chunks, replacing it with a separate data structure.  This would allow
> us to preserve page alignment for mmap'ed chunks without wasting an
> entire page for each allocation, just to store the malloc header.
>
> > +@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
>
> This should reference the earlier discussion about when it is safe to
> tag and untag addresses.
>
> > +@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
>
> “are valid tagged”?
>
> Does “valid” mean in this context that “the CPU can be configured to
> ignore bits set in BITS during address translation using
> set_tagged_address_mask”?
>
> > +@deftypefn Macro {const uintptr_t} TAGGED_ADDRESS_MASK (@var{bits})
> > +This macro returns a nonzero value if it can be used as mask for constant
> > +address @var{bits} used in address translation.
> > +@end deftypefn
>
> I do not understand the description.

Fixed.

I am enclosing the updated tagged-address.texi here.

Thanks.
  
Szabolcs Nagy April 22, 2021, 9:43 a.m. UTC | #3
The 04/21/2021 16:21, H.J. Lu via Libc-alpha wrote:
> On Tue, Apr 20, 2021 at 11:36 PM Florian Weimer <fweimer@redhat.com> wrote:
> > * H. J. Lu:
> > > diff --git a/manual/tagged-address.texi b/manual/tagged-address.texi
> > > new file mode 100644
> > > index 0000000000..ce10f7e752
> > > --- /dev/null
> > > +++ b/manual/tagged-address.texi
> > > @@ -0,0 +1,59 @@
> > > +@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
> >
> > I don't under stand the “which is the number of address bits” part.
> 
> For tagged addresses, not all bits are used in address translation.
> For TBI, only the lower 48 bits are used in address translation.
> For LAM, it can be either the lower 48 bits or 57 bits.
> 
> > This section needs to describe under which circumstances it is valid to
> > alter the tag bits in pointers returned from glibc functions (including
> 
> Tagged address is enabled only when get_tagged_address_mask () != -1.
> 


> > system call wrappers).  I think at least historically, the kernel
> > required masking tag bits in user space for TBI.
> 
> I believe this has been fixed in the recent kernel.

on aarch64 we need

prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0);

while single threaded to enable the tagged address syscall abi, see
https://www.kernel.org/doc/html/latest/arm64/tagged-pointers.html

we do this for heap tagging because that depends on it, but we
don't enable it otherwise because previously invalid addresses
now may succeed instead of EFAULT/EINVAL in syscalls.

i think glibc can just enable it by default (always run processes
with tagged address syscall abi), i don't think that would cause
regressions other than different errno in some odd mmap etc usage.
(i think one glibc test fails along this line with heap tagging
enabled, if that's considered risky then we can do some per process
opt-in, but a libc call is problematic as it can be too late)
  

Patch

diff --git a/NEWS b/NEWS
index aa0f10a891..4b7f252b33 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-mask.h b/bits/tagged-address-mask.h
new file mode 100644
index 0000000000..33571af11c
--- /dev/null
+++ b/bits/tagged-address-mask.h
@@ -0,0 +1,47 @@ 
+/* 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_MASK_H
+#define _BITS_TAGGED_ADDRESS_MASK_H 1
+
+#ifndef _SYS_TAGGED_ADDRESS_H
+# error "Never include this file directly.  Use <sys/tagged-address.h> instead"
+#endif
+
+#include <bits/tagged-address.h>
+
+#ifdef __GNUC__
+# if defined __USE_ISOC11 || defined __USE_ISOCXX11
+#  ifdef __USE_ISOCXX11
+#   define TAGGED_ADDRESS_ASSERT static_assert
+#  else
+#   define TAGGED_ADDRESS_ASSERT _Static_assert
+#  endif
+# else
+#  define TAGGED_ADDRESS_ASSERT(expr, msg)
+# endif
+/* A mask for constant address BITS used in address translation.  */
+# define TAGGED_ADDRESS_MASK(BITS)				    \
+  (__extension__						    \
+    ({								    \
+       TAGGED_ADDRESS_ASSERT (TAGGED_ADDRESS_VALID_BITS (BITS),	    \
+			      "Tagged address bits must be valid"); \
+       (((uintptr_t) 1) << (BITS)) - 1;				    \
+     }))
+#endif
+
+#endif /* <bits/tagged-address-mask.h> */
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/csu/libc-start.c b/csu/libc-start.c
index 05ff7afddf..03161c939e 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -410,6 +410,9 @@  LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
     GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
 #endif
 
+  /* set_tagged_address_mask can only be called before main.  */
+  GL(dl_tagged_address_mask_locked) = 1;
+
 #ifndef SHARED
   _dl_debug_initialize (0, LM_ID_BASE);
 #endif
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 28ec2e4e63..829dcbbaa0 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..ce10f7e752
--- /dev/null
+++ b/manual/tagged-address.texi
@@ -0,0 +1,59 @@ 
+@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.  The return
+value is @code{0} if tag bits are not the highest bits in address.
+@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{main}.  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 nonzero value if it can be used as mask for constant
+address @var{bits} used in address translation.
+@end deftypefn
diff --git a/misc/Makefile b/misc/Makefile
index 38dad737f2..ec8b266c2e 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -38,7 +38,9 @@  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 \
+	   bits/tagged-address-mask.h
 
 routines := brk sbrk sstk ioctl \
 	    readv writev preadv preadv64 pwritev pwritev64 \
@@ -73,7 +75,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 unwind-link
+	    allocate_once fd_to_filename single_threaded unwind-link \
+	    tagged-address set-tagged-address-mask
 
 generated += tst-error1.mtrace tst-error1-mem.out \
   tst-allocate_once.mtrace tst-allocate_once-mem.out
@@ -88,15 +91,30 @@  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-select
+	 tst-mntent-autofs tst-syscalls tst-mntent-escape tst-select \
+	 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 \
+	 tst-tagged-address-4 tst-tagged-address-4-static
 
 # Tests which need libdl.
 ifeq (yes,$(build-shared))
-tests += tst-gethostid
+tests += tst-gethostid \
+  tst-tagged-address-5 \
+  tst-tagged-address-6 \
+  tst-tagged-address-7
+modules-names += \
+  tst-tagged-address-mod-5 \
+  tst-tagged-address-mod-6 \
+  tst-tagged-address-mod-7
 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 \
+  tst-tagged-address-4-static
 
 # Test for the internal, non-exported __fd_to_filename function.
 tests-internal += tst-fd_to_filename
@@ -160,3 +178,9 @@  $(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)
+$(objpfx)tst-tagged-address-7: $(libdl)
+$(objpfx)tst-tagged-address-7.out: $(objpfx)tst-tagged-address-mod-7.so
+$(objpfx)tst-tagged-address-mod-7.so: $(libsupport)
diff --git a/misc/Versions b/misc/Versions
index d5b348e83a..ceb8b0084a 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..2e1e2f2343
--- /dev/null
+++ b/misc/set-tagged-address-mask.c
@@ -0,0 +1,41 @@ 
+/* 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>
+#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 (GL(dl_tagged_address_mask_locked) != 0)
+    __set_errno (EPERM);
+  else
+    {
+      /* set_tagged_address_mask can only be called once.  */
+      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..025a333cac
--- /dev/null
+++ b/misc/sys/tagged-address.h
@@ -0,0 +1,45 @@ 
+/* 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-mask.h>
+
+__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..0bbc214a2f
--- /dev/null
+++ b/misc/tst-tagged-address-1.c
@@ -0,0 +1,53 @@ 
+/* 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 void
+init_0 (void)
+{
+  if (set_tagged_address_mask (get_tagged_address_mask ()) != 0)
+    FAIL_EXIT1 ("set_tagged_address_mask failed: %m");
+}
+
+static void
+init_1 (void)
+{
+  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");
+}
+
+static void (*init_array []) (void)
+  __attribute__ ((used, section (".init_array"), aligned (sizeof (void *)))) =
+{
+  &init_0,
+  &init_1
+};
+
+static int
+do_test (void)
+{
+  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..e241950959
--- /dev/null
+++ b/misc/tst-tagged-address-3.c
@@ -0,0 +1,48 @@ 
+/* 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 <sys/tagged-address.h>
+#include <support/check.h>
+
+static void
+init (void)
+{
+  uintptr_t mask = (uintptr_t) -1;
+  if (set_tagged_address_mask (mask) != 0)
+    FAIL_EXIT1 ("set_tagged_address_mask failed: %m");
+}
+
+static void (*init_array []) (void)
+  __attribute__ ((used, section (".init_array"), aligned (sizeof (void *)))) =
+{
+  &init
+};
+
+static int
+do_test (void)
+{
+  uintptr_t mask = (uintptr_t) -1;
+  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/misc/tst-tagged-address-4-static.c b/misc/tst-tagged-address-4-static.c
new file mode 100644
index 0000000000..b0681f6f9b
--- /dev/null
+++ b/misc/tst-tagged-address-4-static.c
@@ -0,0 +1 @@ 
+#include <tst-tagged-address-4.c>
diff --git a/misc/tst-tagged-address-4.c b/misc/tst-tagged-address-4.c
new file mode 100644
index 0000000000..9843f780af
--- /dev/null
+++ b/misc/tst-tagged-address-4.c
@@ -0,0 +1,35 @@ 
+/* 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 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-5.c b/misc/tst-tagged-address-5.c
new file mode 100644
index 0000000000..e00679a2cb
--- /dev/null
+++ b/misc/tst-tagged-address-5.c
@@ -0,0 +1,25 @@ 
+/* 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/>.  */
+
+static int
+do_test (void)
+{
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-tagged-address-6.c b/misc/tst-tagged-address-6.c
new file mode 100644
index 0000000000..5fdceb1fb4
--- /dev/null
+++ b/misc/tst-tagged-address-6.c
@@ -0,0 +1,34 @@ 
+/* 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 <sys/tagged-address.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  uintptr_t mask = (uintptr_t) -1;
+  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/misc/tst-tagged-address-7.c b/misc/tst-tagged-address-7.c
new file mode 100644
index 0000000000..f0a078188d
--- /dev/null
+++ b/misc/tst-tagged-address-7.c
@@ -0,0 +1,40 @@ 
+/* 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 <stddef.h>
+#include <dlfcn.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  const char *modname = "$ORIGIN/tst-tagged-address-mod-7.so";
+  void *h = dlopen (modname, RTLD_LAZY);
+
+  if (h == NULL)
+    {
+      const char *err = dlerror ();
+      FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err);
+    }
+
+  dlclose (h);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-tagged-address-mod-5.c b/misc/tst-tagged-address-mod-5.c
new file mode 100644
index 0000000000..275ecc406d
--- /dev/null
+++ b/misc/tst-tagged-address-mod-5.c
@@ -0,0 +1,45 @@ 
+/* 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 void
+init_0 (void)
+{
+  if (set_tagged_address_mask (get_tagged_address_mask ()) != 0)
+    FAIL_EXIT1 ("set_tagged_address_mask failed: %m");
+}
+
+static void
+init_1 (void)
+{
+  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");
+}
+
+static void (*init_array []) (void)
+  __attribute__ ((used, section (".init_array"), aligned (sizeof (void *)))) =
+{
+  &init_0,
+  &init_1
+};
diff --git a/misc/tst-tagged-address-mod-6.c b/misc/tst-tagged-address-mod-6.c
new file mode 100644
index 0000000000..75dfe8e8d2
--- /dev/null
+++ b/misc/tst-tagged-address-mod-6.c
@@ -0,0 +1,34 @@ 
+/* 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 <sys/tagged-address.h>
+#include <support/check.h>
+
+static void
+init (void)
+{
+  uintptr_t mask = (uintptr_t) -1;
+  if (set_tagged_address_mask (mask) != 0)
+    FAIL_EXIT1 ("set_tagged_address_mask failed: %m");
+}
+
+static void (*init_array []) (void)
+  __attribute__ ((used, section (".init_array"), aligned (sizeof (void *)))) =
+{
+  &init
+};
diff --git a/misc/tst-tagged-address-mod-7.c b/misc/tst-tagged-address-mod-7.c
new file mode 100644
index 0000000000..c902a4e55e
--- /dev/null
+++ b/misc/tst-tagged-address-mod-7.c
@@ -0,0 +1,34 @@ 
+/* 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 <sys/tagged-address.h>
+#include <support/check.h>
+
+static void
+init (void)
+{
+  uintptr_t mask = (uintptr_t) -1;
+  if (set_tagged_address_mask (mask) == 0)
+    FAIL_EXIT1 ("set_tagged_address_mask should have failed");
+}
+
+static void (*init_array []) (void)
+  __attribute__ ((used, section (".init_array"), aligned (sizeof (void *)))) =
+{
+  &init
+};
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 ea3f7a69d0..ed1d01d88d 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -484,6 +484,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 cfd4e55e57..445f131cd4 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2253,7 +2253,12 @@  GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __isnanf128 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 get_tagged_address_bits F
+GLIBC_2.34 get_tagged_address_mask F
 GLIBC_2.34 pthread_kill 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 da0974f11a..52676b5a6a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2092,7 +2092,12 @@  GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __isnanf128 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 get_tagged_address_bits F
+GLIBC_2.34 get_tagged_address_mask F
 GLIBC_2.34 pthread_kill 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 d3d155e7c0..509f67f780 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2189,4 +2189,9 @@  GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __isnanf128 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 get_tagged_address_bits F
+GLIBC_2.34 get_tagged_address_mask F
 GLIBC_2.34 pthread_kill F
+GLIBC_2.34 set_tagged_address_mask F
+GLIBC_2.34 tag_address F
+GLIBC_2.34 untag_address F