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

Message ID 20210822124546.154232-2-hjl.tools@gmail.com
State Committed
Headers
Series RFC: Add <sys/tagged-address.h> |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent
dj/TryBot-32bit success Build for i686

Commit Message

H.J. Lu Aug. 22, 2021, 12:45 p.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
with restrictions:

1. All bits between 0 and N - 1, where N is the number of tagged address
bits, are used in address translation.
2. All pointers participating in a pointer arithmetic operation should have
the same tag if they point to the same memory object so that pointer
equality operation can be performed on tagged pointers.

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

/* Non-zero if constant address BITS is a valid tagged address bits.  */
 #define TRANSLATED_ADDRESS_VALID_BITS(BITS)

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

1. set_translated_address_mask should be called as early as possible.
2. set_translated_address_mask shouldn't be allowed after main or thread
creation.
3. After set_translated_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-valid-bits.h              | 28 ++++++++++
 csu/libc-start.c                              |  3 +
 elf/dl-support.c                              |  5 ++
 include/sys/tagged-address.h                  | 18 ++++++
 manual/Makefile                               |  3 +-
 manual/ctype.texi                             |  2 +-
 manual/memory.texi                            |  2 +-
 manual/tagged-address.texi                    | 48 ++++++++++++++++
 misc/Makefile                                 | 40 ++++++++++++--
 misc/Versions                                 | 10 ++++
 misc/set-translated-address-mask.c            | 41 ++++++++++++++
 misc/sys/tagged-address.h                     | 33 +++++++++++
 misc/tagged-address.c                         | 50 +++++++++++++++++
 misc/tst-tagged-address-1-static.c            |  1 +
 misc/tst-tagged-address-1.c                   | 55 +++++++++++++++++++
 misc/tst-tagged-address-2-static.c            |  1 +
 misc/tst-tagged-address-2.c                   | 45 +++++++++++++++
 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                   | 36 ++++++++++++
 misc/tst-tagged-address-5.c                   | 25 +++++++++
 misc/tst-tagged-address-6.c                   | 34 ++++++++++++
 misc/tst-tagged-address-7.c                   | 41 ++++++++++++++
 misc/tst-tagged-address-mod-5.c               | 47 ++++++++++++++++
 misc/tst-tagged-address-mod-6.c               | 34 ++++++++++++
 misc/tst-tagged-address-mod-7.c               | 35 ++++++++++++
 sysdeps/generic/inline-tagged-address.h       | 43 +++++++++++++++
 sysdeps/generic/ldsodefs.h                    |  4 ++
 sysdeps/unix/sysv/linux/i386/libc.abilist     |  1 +
 .../unix/sysv/linux/x86_64/64/libc.abilist    |  1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |  1 +
 34 files changed, 777 insertions(+), 9 deletions(-)
 create mode 100644 bits/tagged-address-mask.h
 create mode 100644 bits/tagged-address-valid-bits.h
 create mode 100644 include/sys/tagged-address.h
 create mode 100644 manual/tagged-address.texi
 create mode 100644 misc/set-translated-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 Aug. 23, 2021, 9:28 a.m. UTC | #1
* H. J. Lu:

> 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).

I think the fundamental concern is that we don't really know today how
this API would be used.  Szabolcs has said that Arm doesn't need this
API for HWSAN.  TBI has already other (incompatible) users, I think.
(Although OpenJDK's ZGC garbage collector has moved off it.)

My concern is that this interface essentialyl sets in stone a certain
programming model for LAM, and we really don't know today if that's the
right approach.

I also expect that HWSAN needs to poke at glibc internals, like the
other sanitizers, so I don't see why calling a kernel API behind glibc's
back would be problematic.

As a side effect of the libpthread merge, we freed DF_1_INITFIRST for
other uses, so you should be able to work around initialization ordering
issues, too.

Thanks,
Florian
  
H.J. Lu Aug. 23, 2021, 1:40 p.m. UTC | #2
On Mon, Aug 23, 2021 at 2:28 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu:
>
> > 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).
>
> I think the fundamental concern is that we don't really know today how
> this API would be used.  Szabolcs has said that Arm doesn't need this
> API for HWSAN.  TBI has already other (incompatible) users, I think.
> (Although OpenJDK's ZGC garbage collector has moved off it.)
>
> My concern is that this interface essentialyl sets in stone a certain
> programming model for LAM, and we really don't know today if that's the
> right approach.

My current API has only set_translated_address_mask to enable LAM.
It doesn't specify/know how LAM is used.  I don't see there is an issue
here.

> I also expect that HWSAN needs to poke at glibc internals, like the
> other sanitizers, so I don't see why calling a kernel API behind glibc's
> back would be problematic.

The LAM enabled glibc should support all LAM usages.   memmove
needs to know the LAM bits to work properly.

> As a side effect of the libpthread merge, we freed DF_1_INITFIRST for
> other uses, so you should be able to work around initialization ordering
> issues, too.

The issue here is that LAM should only be enabled ONCE before main
and thread creation.  Neither DF_1_INITFIRST nor kernel API can properly
enforce it.
  
Florian Weimer Aug. 23, 2021, 1:49 p.m. UTC | #3
* H. J. Lu:

> On Mon, Aug 23, 2021 at 2:28 AM Florian Weimer <fweimer@redhat.com> wrote:
>>
>> * H. J. Lu:
>>
>> > 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).
>>
>> I think the fundamental concern is that we don't really know today how
>> this API would be used.  Szabolcs has said that Arm doesn't need this
>> API for HWSAN.  TBI has already other (incompatible) users, I think.
>> (Although OpenJDK's ZGC garbage collector has moved off it.)
>>
>> My concern is that this interface essentialyl sets in stone a certain
>> programming model for LAM, and we really don't know today if that's the
>> right approach.
>
> My current API has only set_translated_address_mask to enable LAM.
> It doesn't specify/know how LAM is used.  I don't see there is an issue
> here.

It's still unclear who owns the tag bits, and if the behavior is
expected to be like the kernel (e.g., glibc masks all tag bits in
dladdr so that they are ignored not just at the hardware level).

>> I also expect that HWSAN needs to poke at glibc internals, like the
>> other sanitizers, so I don't see why calling a kernel API behind glibc's
>> back would be problematic.
>
> The LAM enabled glibc should support all LAM usages.   memmove
> needs to know the LAM bits to work properly.

Only if it is permitted to change the tag on subobjects, which I don't
think is the case.  Otherwise overlaps necessarily have the same tag,
and the existing pointer comparison works as expected.

>> As a side effect of the libpthread merge, we freed DF_1_INITFIRST for
>> other uses, so you should be able to work around initialization ordering
>> issues, too.
>
> The issue here is that LAM should only be enabled ONCE before main
> and thread creation.  Neither DF_1_INITFIRST nor kernel API can properly
> enforce it.

How does AArch64 solve this?  Different kernel API?

Thanks,
Florian
  
H.J. Lu Aug. 23, 2021, 2:15 p.m. UTC | #4
On Mon, Aug 23, 2021 at 6:49 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu:
>
> > On Mon, Aug 23, 2021 at 2:28 AM Florian Weimer <fweimer@redhat.com> wrote:
> >>
> >> * H. J. Lu:
> >>
> >> > 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).
> >>
> >> I think the fundamental concern is that we don't really know today how
> >> this API would be used.  Szabolcs has said that Arm doesn't need this
> >> API for HWSAN.  TBI has already other (incompatible) users, I think.
> >> (Although OpenJDK's ZGC garbage collector has moved off it.)
> >>
> >> My concern is that this interface essentialyl sets in stone a certain
> >> programming model for LAM, and we really don't know today if that's the
> >> right approach.
> >
> > My current API has only set_translated_address_mask to enable LAM.
> > It doesn't specify/know how LAM is used.  I don't see there is an issue
> > here.
>
> It's still unclear who owns the tag bits, and if the behavior is
> expected to be like the kernel (e.g., glibc masks all tag bits in
> dladdr so that they are ignored not just at the hardware level).

We don't have to decide now.  We will learn more with HWASAN.
With set_translated_address_mask, glibc can control/change how
tag bits should be used.  With kernel API, glibc is out of the picture.

> >> I also expect that HWSAN needs to poke at glibc internals, like the
> >> other sanitizers, so I don't see why calling a kernel API behind glibc's
> >> back would be problematic.
> >
> > The LAM enabled glibc should support all LAM usages.   memmove
> > needs to know the LAM bits to work properly.
>
> Only if it is permitted to change the tag on subobjects, which I don't
> think is the case.  Otherwise overlaps necessarily have the same tag,
> and the existing pointer comparison works as expected.

It is not about overlap.  I am concerned about copy direction, like
if (dest > src), will it be a problem?

> >> As a side effect of the libpthread merge, we freed DF_1_INITFIRST for
> >> other uses, so you should be able to work around initialization ordering
> >> issues, too.
> >
> > The issue here is that LAM should only be enabled ONCE before main
> > and thread creation.  Neither DF_1_INITFIRST nor kernel API can properly
> > enforce it.
>
> How does AArch64 solve this?  Different kernel API?

I don't think that AArch64 has addressed this issue at all.
  
Szabolcs Nagy Sept. 3, 2021, 9:12 a.m. UTC | #5
The 08/23/2021 07:15, H.J. Lu via Libc-alpha wrote:
> On Mon, Aug 23, 2021 at 6:49 AM Florian Weimer <fweimer@redhat.com> wrote:
> > * H. J. Lu:
> > > On Mon, Aug 23, 2021 at 2:28 AM Florian Weimer <fweimer@redhat.com> wrote:
> > >> As a side effect of the libpthread merge, we freed DF_1_INITFIRST for
> > >> other uses, so you should be able to work around initialization ordering
> > >> issues, too.
> > >
> > > The issue here is that LAM should only be enabled ONCE before main
> > > and thread creation.  Neither DF_1_INITFIRST nor kernel API can properly
> > > enforce it.
> >
> > How does AArch64 solve this?  Different kernel API?
> 
> I don't think that AArch64 has addressed this issue at all.

i expect the hwasan runtime to have an initializer that
ensures that it runs once, early (e.g. the shadow map
has to be set up very early too: before any instrumented
user code may run)

is there a reason the lam setup cannot use this mechanism?
  
H.J. Lu Sept. 3, 2021, 1:58 p.m. UTC | #6
On Fri, Sep 3, 2021 at 2:12 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
>
> The 08/23/2021 07:15, H.J. Lu via Libc-alpha wrote:
> > On Mon, Aug 23, 2021 at 6:49 AM Florian Weimer <fweimer@redhat.com> wrote:
> > > * H. J. Lu:
> > > > On Mon, Aug 23, 2021 at 2:28 AM Florian Weimer <fweimer@redhat.com> wrote:
> > > >> As a side effect of the libpthread merge, we freed DF_1_INITFIRST for
> > > >> other uses, so you should be able to work around initialization ordering
> > > >> issues, too.
> > > >
> > > > The issue here is that LAM should only be enabled ONCE before main
> > > > and thread creation.  Neither DF_1_INITFIRST nor kernel API can properly
> > > > enforce it.
> > >
> > > How does AArch64 solve this?  Different kernel API?
> >
> > I don't think that AArch64 has addressed this issue at all.
>
> i expect the hwasan runtime to have an initializer that
> ensures that it runs once, early (e.g. the shadow map
> has to be set up very early too: before any instrumented
> user code may run)

There is nothing in glibc to enforce it.  LAM can be used by
HWASAN or others, including glibc itself.   We need to a way
to control it so that

1. LAM can be enabled properly.  For example, if LAM has
been enabled and used by HWASAN,  it can no longer be
used by glibc itself.
2. LAM can't be disabled arbitrarily.  We can't disable LAM
or change LAM_U57 to LAM_U48 when LAM is in use.

Otherwise, we may get crashes, surprises or security issues
when LAM is enabled/disabled at random places.

> is there a reason the lam setup cannot use this mechanism?

See above.
  
Florian Weimer Sept. 6, 2021, 8:52 a.m. UTC | #7
* H. J. Lu:

> On Fri, Sep 3, 2021 at 2:12 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
>>
>> The 08/23/2021 07:15, H.J. Lu via Libc-alpha wrote:
>> > On Mon, Aug 23, 2021 at 6:49 AM Florian Weimer <fweimer@redhat.com> wrote:
>> > > * H. J. Lu:
>> > > > On Mon, Aug 23, 2021 at 2:28 AM Florian Weimer <fweimer@redhat.com> wrote:
>> > > >> As a side effect of the libpthread merge, we freed DF_1_INITFIRST for
>> > > >> other uses, so you should be able to work around initialization ordering
>> > > >> issues, too.
>> > > >
>> > > > The issue here is that LAM should only be enabled ONCE before main
>> > > > and thread creation.  Neither DF_1_INITFIRST nor kernel API can properly
>> > > > enforce it.
>> > >
>> > > How does AArch64 solve this?  Different kernel API?
>> >
>> > I don't think that AArch64 has addressed this issue at all.
>>
>> i expect the hwasan runtime to have an initializer that
>> ensures that it runs once, early (e.g. the shadow map
>> has to be set up very early too: before any instrumented
>> user code may run)
>
> There is nothing in glibc to enforce it.  LAM can be used by
> HWASAN or others, including glibc itself.   We need to a way
> to control it so that
>
> 1. LAM can be enabled properly.  For example, if LAM has
> been enabled and used by HWASAN,  it can no longer be
> used by glibc itself.
> 2. LAM can't be disabled arbitrarily.  We can't disable LAM
> or change LAM_U57 to LAM_U48 when LAM is in use.
>
> Otherwise, we may get crashes, surprises or security issues
> when LAM is enabled/disabled at random places.

But these things are already happening with the software-based Address
Sanitizer.  I doubt these long-standing issues will be fixed by LAM
because they are not a hardware limitation, but the result of a lack of
coordination between projects.

Setting up LAM is just one more issue in a long list of things that can
go wrong.  And if LAM does not have an ABI impact, it can be backported,
which would be nice.

Note that in glibc 2.34, we freed up DF_1_INITFIRST, so you could use
that to set up things really early.

Thanks,
Florian
  
H.J. Lu Sept. 6, 2021, 1:34 p.m. UTC | #8
On Mon, Sep 6, 2021 at 1:52 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu:
>
> > On Fri, Sep 3, 2021 at 2:12 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
> >>
> >> The 08/23/2021 07:15, H.J. Lu via Libc-alpha wrote:
> >> > On Mon, Aug 23, 2021 at 6:49 AM Florian Weimer <fweimer@redhat.com> wrote:
> >> > > * H. J. Lu:
> >> > > > On Mon, Aug 23, 2021 at 2:28 AM Florian Weimer <fweimer@redhat.com> wrote:
> >> > > >> As a side effect of the libpthread merge, we freed DF_1_INITFIRST for
> >> > > >> other uses, so you should be able to work around initialization ordering
> >> > > >> issues, too.
> >> > > >
> >> > > > The issue here is that LAM should only be enabled ONCE before main
> >> > > > and thread creation.  Neither DF_1_INITFIRST nor kernel API can properly
> >> > > > enforce it.
> >> > >
> >> > > How does AArch64 solve this?  Different kernel API?
> >> >
> >> > I don't think that AArch64 has addressed this issue at all.
> >>
> >> i expect the hwasan runtime to have an initializer that
> >> ensures that it runs once, early (e.g. the shadow map
> >> has to be set up very early too: before any instrumented
> >> user code may run)
> >
> > There is nothing in glibc to enforce it.  LAM can be used by
> > HWASAN or others, including glibc itself.   We need to a way
> > to control it so that
> >
> > 1. LAM can be enabled properly.  For example, if LAM has
> > been enabled and used by HWASAN,  it can no longer be
> > used by glibc itself.
> > 2. LAM can't be disabled arbitrarily.  We can't disable LAM
> > or change LAM_U57 to LAM_U48 when LAM is in use.
> >
> > Otherwise, we may get crashes, surprises or security issues
> > when LAM is enabled/disabled at random places.
>
> But these things are already happening with the software-based Address
> Sanitizer.  I doubt these long-standing issues will be fixed by LAM
> because they are not a hardware limitation, but the result of a lack of
> coordination between projects.

But I don't think we should add LAM to the list of the long-standing
issues.  Without an API, we can never safely use LAM in glibc at
all.

> Setting up LAM is just one more issue in a long list of things that can
> go wrong.  And if LAM does not have an ABI impact, it can be backported,
> which would be nice.

I backported it to glibc 2.33:

[hjl@gnu-cfl-2 tmp]$ ar -t /lib64/libc_nonshared.a
elf-init.oS
atexit.oS
at_quick_exit.oS
pthread_atfork.oS
set-translated-address-mask.oS
stack_chk_fail_local.oS
[hjl@gnu-cfl-2 tmp]$ ar -x /lib64/libc_nonshared.a  tagged-address.oS
set-translated-address-mask.oS
[hjl@gnu-cfl-2 tmp]$ nm set-translated-address-mask.oS
                 U errno
                 U _GLOBAL_OFFSET_TABLE_
                 U _rtld_global
0000000000000000 T set_translated_address_mask
                 U __stack_chk_fail_local
[hjl@gnu-cfl-2 tmp]

At least, the same source can compile with glibc 2.33 and the
binary linked against glibc 2.33 will run with newer glibc.

> Note that in glibc 2.34, we freed up DF_1_INITFIRST, so you could use
> that to set up things really early.

What do you have in mind for LAM with DF_1_INITFIRST?  How can it
address the LAM issues I have?

BTW, DF_1_INITFIRST doesn't help backport.

>
> Thanks,
> Florian
>

Thanks.
  
Florian Weimer Sept. 17, 2021, 10:19 a.m. UTC | #9
* H. J. Lu:

> But I don't think we should add LAM to the list of the long-standing
> issues.  Without an API, we can never safely use LAM in glibc at
> all.

Yet you were able to backport it.

>> Setting up LAM is just one more issue in a long list of things that can
>> go wrong.  And if LAM does not have an ABI impact, it can be backported,
>> which would be nice.
>
> I backported it to glibc 2.33:
>
> [hjl@gnu-cfl-2 tmp]$ ar -t /lib64/libc_nonshared.a
> elf-init.oS
> atexit.oS
> at_quick_exit.oS
> pthread_atfork.oS
> set-translated-address-mask.oS
> stack_chk_fail_local.oS
> [hjl@gnu-cfl-2 tmp]$ ar -x /lib64/libc_nonshared.a  tagged-address.oS
> set-translated-address-mask.oS
> [hjl@gnu-cfl-2 tmp]$ nm set-translated-address-mask.oS
>                  U errno
>                  U _GLOBAL_OFFSET_TABLE_
>                  U _rtld_global
> 0000000000000000 T set_translated_address_mask
>                  U __stack_chk_fail_local
> [hjl@gnu-cfl-2 tmp]
>
> At least, the same source can compile with glibc 2.33 and the
> binary linked against glibc 2.33 will run with newer glibc.

Why can't you do this while we experiment with HWSAN?

>> Note that in glibc 2.34, we freed up DF_1_INITFIRST, so you could use
>> that to set up things really early.
>
> What do you have in mind for LAM with DF_1_INITFIRST?  How can it
> address the LAM issues I have?

It can make sure that the constructor runs as early as possible, so that
the appropriate system calls are made before any thread creation.

If the kernel interface does not provide coordination capabilities
between different LAM consumers within the same process (even a minimal
capability, like “has this been enabled yet?”), that sounds like a
serious drawback.

Thanks,
Florian
  

Patch

diff --git a/NEWS b/NEWS
index 79c895e382..4f80340f9f 100644
--- a/NEWS
+++ b/NEWS
@@ -9,7 +9,7 @@  Version 2.35
 
 Major new features:
 
-  [Add new features here]
+* Add <sys/tagged-address.h> to provide an API for tagged address.
 
 Deprecated and removed features, and other changes affecting compatibility:
 
diff --git a/bits/tagged-address-mask.h b/bits/tagged-address-mask.h
new file mode 100644
index 0000000000..8762921083
--- /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-valid-bits.h>
+
+#ifdef __cplusplus
+# if __cplusplus >= 201103L
+#  define TRANSLATED_ADDRESS_ASSERT static_assert
+# else
+#  define TRANSLATED_ADDRESS_ASSERT(expr, msg)
+# endif
+#else
+# define TRANSLATED_ADDRESS_ASSERT _Static_assert
+#endif
+
+/* A mask for constant address BITS used in address translation.  */
+#define TRANSLATED_ADDRESS_MASK(BITS)			\
+  (__extension__					\
+    ({							\
+       TRANSLATED_ADDRESS_ASSERT			\
+         (TRANSLATED_ADDRESS_VALID_BITS (BITS),		\
+	  "Translated address bits must be valid");	\
+       (((uintptr_t) 1) << (BITS)) - 1;			\
+     }))
+
+#endif /* <bits/tagged-address-mask.h> */
diff --git a/bits/tagged-address-valid-bits.h b/bits/tagged-address-valid-bits.h
new file mode 100644
index 0000000000..995bc2899b
--- /dev/null
+++ b/bits/tagged-address-valid-bits.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_VALID_BITS_H
+#define _BITS_TAGGED_ADDRESS_VALID_BITS_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 translated address bits.  */
+#define TRANSLATED_ADDRESS_VALID_BITS(BITS) 0
+
+#endif /* <bits/tagged-address-valid-bits.h> */
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 0350b006fd..6f8ffa08f0 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -402,6 +402,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_translated_address_mask can only be called before main.  */
+  GL(dl_translated_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 0155718175..028db5be37 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_translated_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..a216814655
--- /dev/null
+++ b/include/sys/tagged-address.h
@@ -0,0 +1,18 @@ 
+#include <misc/sys/tagged-address.h>
+
+#ifdef _ISOMAC
+/* Get the current address bits used in address translation.  */
+extern unsigned int __libc_get_translated_address_bits (void);
+
+/* Get the current mask for address bits used in address translation.  */
+extern uintptr_t __libc_get_translated_address_mask (void);
+
+/* Return the tagged address of __ADDR with the tag value __TAG.  */
+extern void *__libc_tag_address (void *__addr, unsigned int __tag);
+
+/* Return the untagged address of __ADDR.  */
+extern void *__libc_untag_address (void *__addr);
+
+#else
+# include <inline-tagged-address.h>
+#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 0b2b9c8795..2e283e41f9 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..d10e67b7e2
--- /dev/null
+++ b/manual/tagged-address.texi
@@ -0,0 +1,48 @@ 
+@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 one function and two macros in the header file
+@file{sys/tagged-address.h} to manipulate translated address bits,
+which is the number of the address bits used in address translation,
+with restrictions:
+
+@itemize @bullet
+@item
+All bits between 0 and N - 1, where N is the number of translated address
+bits, are used in address translation.
+
+@item
+All pointers participating in a pointer arithmetic operation should have
+the same tag if they point to the same memory object so that pointer
+equality operation can be performed on tagged pointers.
+@end itemize
+
+@pindex sys/tagged-address.h
+
+@deftypefun int set_translated_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}.
+Only bits set in @var{mask} will be used in address translation.  The
+return value is @code{0} on success and @code{-1} on failure.  This
+function can be called only once before @code{main} and thread creation.
+The possible @code{errno} error conditions are @code{ENODEV}, @code{EPERM},
+@code{EINVAL}, and @code{ENOSYS}.
+@end deftypefun
+
+@deftypefn Macro int TRANSLATED_ADDRESS_VALID_BITS (@var{bits})
+This macro returns a nonzero value (true) if @var{bits} is a valid
+constant number of the lower address bits which can be used in address
+translation.
+@end deftypefn
+
+@deftypefn Macro {const uintptr_t} TRANSLATED_ADDRESS_MASK (@var{bits})
+This macro returns a nonzero value which can be passed to
+@code{set_translated_address_mask} to specify the lower address
+@var{bits} for address translation.
+@end deftypefn
diff --git a/misc/Makefile b/misc/Makefile
index 1083ba3bfc..bada0cfcc2 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -38,7 +38,10 @@  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-mask.h \
+	   bits/tagged-address-valid-bits.h
 
 routines := brk sbrk sstk ioctl \
 	    readv writev preadv preadv64 pwritev pwritev64 \
@@ -73,7 +76,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-translated-address-mask
 
 generated += tst-error1.mtrace tst-error1-mem.out \
   tst-allocate_once.mtrace tst-allocate_once-mem.out
@@ -89,7 +93,11 @@  tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
 	 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-ioctl
+	 tst-ioctl \
+	 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-time64 := \
   tst-select-time64 \
@@ -99,11 +107,24 @@  tests-time64 := \
 
 # 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 = \
+  tst-tagged-address-mod-5 \
+  tst-tagged-address-mod-6 \
+  tst-tagged-address-mod-7
+modules-names += $(modules-names-tst-tagged-address)
+modules-names-tests += $(modules-names-tst-tagged-address)
 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
@@ -172,3 +193,12 @@  $(objpfx)tst-select: $(librt)
 $(objpfx)tst-select-time64: $(librt)
 $(objpfx)tst-pselect: $(librt)
 $(objpfx)tst-pselect-time64: $(librt)
+
+$(objpfx)tst-tagged-address-2: $(shared-thread-library)
+$(objpfx)tst-tagged-address-2-static: $(static-thread-library)
+$(objpfx)tst-tagged-address-5: $(objpfx)tst-tagged-address-mod-5.so
+$(objpfx)tst-tagged-address-mod-5.so: $(libsupport)
+$(objpfx)tst-tagged-address-6: $(objpfx)tst-tagged-address-mod-6.so
+$(objpfx)tst-tagged-address-mod-6.so: $(libsupport)
+$(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..fb102ca2b3 100644
--- a/misc/Versions
+++ b/misc/Versions
@@ -164,6 +164,10 @@  libc {
   GLIBC_2.32 {
     __libc_single_threaded;
   }
+  GLIBC_2.35 {
+    # Support tagged address.
+    set_translated_address_mask;
+  }
   GLIBC_PRIVATE {
     __madvise;
     __mktemp;
@@ -173,5 +177,11 @@  libc {
     __sched_get_priority_min; __sched_get_priority_max;
     __libc_allocate_once_slow;
     __libc_unwind_link_get;
+
+    # Support tagged address.
+    __libc_get_translated_address_bits;
+    __libc_get_translated_address_mask;
+    __libc_tag_address;
+    __libc_untag_address;
   }
 }
diff --git a/misc/set-translated-address-mask.c b/misc/set-translated-address-mask.c
new file mode 100644
index 0000000000..9a0f6a11cf
--- /dev/null
+++ b/misc/set-translated-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_translated_address_mask (uintptr_t mask)
+{
+  if (GL(dl_translated_address_mask_locked) != 0)
+    __set_errno (EPERM);
+  else
+    {
+      /* set_translated_address_mask can only be called once.  */
+      GL(dl_translated_address_mask_locked) = 1;
+
+      /* Only NOP is allowed.  */
+      if (mask == __get_translated_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..a0a91bad75
--- /dev/null
+++ b/misc/sys/tagged-address.h
@@ -0,0 +1,33 @@ 
+/* 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
+
+/* Set the mask for address bits used in address translation.  Return 0
+   on success.  Return -1 on error.  */
+extern int set_translated_address_mask (uintptr_t __mask);
+
+__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..02d4123c5c
--- /dev/null
+++ b/misc/tagged-address.c
@@ -0,0 +1,50 @@ 
+/* 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>
+
+/* Get the current address bits used in address translation.  */
+
+unsigned int
+__libc_get_translated_address_bits (void)
+{
+  return __get_translated_address_bits ();
+}
+
+/* Get the current mask for address bits used in address translation.  */
+
+uintptr_t
+__libc_get_translated_address_mask (void)
+{
+  return __get_translated_address_mask ();
+}
+
+/* Return the tagged address of ADDR with the tag value TAG.  */
+
+void *
+__libc_tag_address (void *addr, unsigned int tag)
+{
+  return __tag_address (addr, tag);
+}
+
+/* Return the untagged address of ADDR.  */
+
+void *
+__libc_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..0751be9b24
--- /dev/null
+++ b/misc/tst-tagged-address-1.c
@@ -0,0 +1,55 @@ 
+/* Tests for set_translated_address_mask before main.
+   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_translated_address_mask (__libc_get_translated_address_mask ())
+      != 0)
+    FAIL_EXIT1 ("set_translated_address_mask failed: %m");
+}
+
+static void
+init_1 (void)
+{
+  if (set_translated_address_mask (__libc_get_translated_address_mask ())
+      == 0)
+    FAIL_EXIT1 ("set_translated_address_mask should fail");
+
+  if (errno != EPERM)
+    FAIL_EXIT1 ("set_translated_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..00a97148f8
--- /dev/null
+++ b/misc/tst-tagged-address-2.c
@@ -0,0 +1,45 @@ 
+/* Test for set_translated_address_mask before main 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_translated_address_mask (__libc_get_translated_address_mask ())
+      == 0)
+    FAIL_EXIT1 ("set_translated_address_mask should fail");
+
+  if (errno != EPERM)
+    FAIL_EXIT1 ("set_translated_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..04d2f8d3da
--- /dev/null
+++ b/misc/tst-tagged-address-3.c
@@ -0,0 +1,48 @@ 
+/* Tests for set_translated_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_translated_address_mask (mask) != 0)
+    FAIL_EXIT1 ("set_translated_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 = __libc_get_translated_address_mask ();
+  if (curent_mask != mask)
+    FAIL_EXIT1 ("get_translated_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..9131373ba1
--- /dev/null
+++ b/misc/tst-tagged-address-4.c
@@ -0,0 +1,36 @@ 
+/* Test for set_translated_address_mask after main.
+   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_translated_address_mask (__libc_get_translated_address_mask ())
+      == 0)
+    FAIL_EXIT1 ("set_translated_address_mask should fail");
+
+  if (errno != EPERM)
+    FAIL_EXIT1 ("set_translated_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..f3c6ce5935
--- /dev/null
+++ b/misc/tst-tagged-address-5.c
@@ -0,0 +1,25 @@ 
+/* Tests for set_translated_address_mask in a shared library before main.
+   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..60c6497af2
--- /dev/null
+++ b/misc/tst-tagged-address-6.c
@@ -0,0 +1,34 @@ 
+/* Tests for set_translated_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 = __libc_get_translated_address_mask ();
+  if (curent_mask != mask)
+    FAIL_EXIT1 ("get_translated_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..7d987e19e3
--- /dev/null
+++ b/misc/tst-tagged-address-7.c
@@ -0,0 +1,41 @@ 
+/* Test for set_translated_address_mask in a dlopened shared library
+   after main.
+   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..88b8d6a261
--- /dev/null
+++ b/misc/tst-tagged-address-mod-5.c
@@ -0,0 +1,47 @@ 
+/* Tests for set_translated_address_mask in a shared library.
+   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_translated_address_mask (__libc_get_translated_address_mask ())
+      != 0)
+    FAIL_EXIT1 ("set_translated_address_mask failed: %m");
+}
+
+static void
+init_1 (void)
+{
+  if (set_translated_address_mask (__libc_get_translated_address_mask ())
+      == 0)
+    FAIL_EXIT1 ("set_translated_address_mask should fail");
+
+  if (errno != EPERM)
+    FAIL_EXIT1 ("set_translated_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..4d9396425d
--- /dev/null
+++ b/misc/tst-tagged-address-mod-6.c
@@ -0,0 +1,34 @@ 
+/* Tests for set_translated_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_translated_address_mask (mask) != 0)
+    FAIL_EXIT1 ("set_translated_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..7d8f80a232
--- /dev/null
+++ b/misc/tst-tagged-address-mod-7.c
@@ -0,0 +1,35 @@ 
+/* Tests for set_translated_address_mask to turn off tagged address in
+   a shared library.
+   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_translated_address_mask (mask) == 0)
+    FAIL_EXIT1 ("set_translated_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..9fb8eb7ecf
--- /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_translated_address_bits (void)
+{
+  return sizeof (uintptr_t) * 8;
+}
+
+static inline uintptr_t
+__get_translated_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 9c15259236..a77a52567f 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -489,6 +489,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_translated_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 2e7603d9ed..0f314eec3e 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2780,6 +2780,7 @@  GLIBC_2.34 tss_create F
 GLIBC_2.34 tss_delete F
 GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
+GLIBC_2.35 set_translated_address_mask 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 095e914b73..7106aac0ad 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2521,6 +2521,7 @@  GLIBC_2.34 tss_create F
 GLIBC_2.34 tss_delete F
 GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
+GLIBC_2.35 set_translated_address_mask 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 dd910f7fe9..00ff5571be 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2627,3 +2627,4 @@  GLIBC_2.34 tss_create F
 GLIBC_2.34 tss_delete F
 GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
+GLIBC_2.35 set_translated_address_mask F