[BFD,LD,AArch64,4/4] Add --pac-plt to enable PLTs protected with PAC.

Message ID b1778c1c-3b4d-39c2-0b0a-4fdac445cec4@arm.com
State New
Headers show
Series
  • Add support for AArch64 BTI and PAC in the linker
Related show

Commit Message

Sudakshina Das March 6, 2019, 10:39 a.m.
Hi

On 06/03/2019 10:36, Sudakshina Das wrote:
> Hi

> 

> On 06/03/2019 10:34, Sudakshina Das wrote:

>> Hi

>>

>> On 06/03/2019 10:30, Sudakshina Das wrote:

>>> Hi

>>>

>>> On 06/03/2019 10:26, Sudakshina Das wrote:

>>>> Hi

>>>>

>>>> This patch series is aimed at giving support for the new Armv8.3-A 

>>>> Pointer Authentication and Armv8.5-A Branch Target Identification 

>>>> feature in the linker.

>>>>

>>>> In order to support these, we propose to make the following changes:

>>>> 1) We have defined .note.gnu.property for AArch64.

>>>> 2) We have defined a new Program Property type

>>>> GNU_PROPERTY_AARCH64_FEATURE_1_AND and used 2 bits to represent

>>>> BTI and PAC respectively.

>>>>    - GNU_PROPERTY_AARCH64_FEATURE_1_BTI

>>>>    - GNU_PROPERTY_AARCH64_FEATURE_1_PAC (We have only reserved this bit

>>>>      for now.)

>>>> 3) We also need custom PLTs when these features are turned on and thus

>>>> we have defined the following processor-specific dynamic array tags:

>>>>    - DT_AARCH64_BTI_PLT

>>>>    - DT_AARCH64_PAC_PLT

>>>> Details of these can be found in the new AArch64 ELF documentation:

>>>> https://developer.arm.com/docs/ihi0056/latest/elf-for-the-arm-64-bit-architecture-aarch64-abi-2018q4 

>>>>

>>>>

>>>> Command line options:

>>>> We introduce a new set of command line options for the linker in 

>>>> order to support the correct PLTs

>>>> 1) --pac-plt : In the presence of this option, the linker uses a PAC 

>>>> enabled PLT. It also uses the dynamic tag DT_AARCH64_PAC_PLT to 

>>>> reflect the same. Other tools like Objdump can use this to determine 

>>>> the size of the PLTs.

>>>> 2) --bti: In the presence of this option, the linker enables BTI 

>>>> with the GNU_PROPERTY_AARCH64_FEATURE_1_BTI feature and also uses a 

>>>> BTI enabled PLT. It also uses the dynamic tag DT_AARCH64_BTI_PLT to 

>>>> reflect the choice of the PLTs. Other tools like Objdump can use 

>>>> this to determine the size of the PLTs. Using this option can give a 

>>>> warning if not all input objects are marked with 

>>>> GNU_PROPERTY_AARCH64_FEATURE_1_BTI.

>>>> 3)--bti-nowarn - Same as above but does not emit any warnings.

>>>>

>>>> In terms of the PLTs, in the presence of both --pac-plt and 

>>>> --bti/--bti-nowarn, the linker chooses the PLTs protected with both 

>>>> BTI and PAC and uses both DT_AARCH64_PAC_PLT and DT_AARCH64_BTI_PLT.

>>>>

>>>> Interaction between Command line arguments and GNU NOTE section

>>>> 1) For PAC, in the presence of --pac-plt along with BIND_NOW, the 

>>>> linker can choose to ignore the pac-plt directive and use smaller 

>>>> PLTs without compromising on security,

>>>> 2) For BTI, the linker must also check for the 

>>>> GNU_PROPERTY_AARCH64_FEATURE_1_BTI in its input. If all inputs have 

>>>> GNU_PROPERTY_AARCH64_FEATURE_1_BTI, the final output will also be 

>>>> marked as such. The PLT should also be protected with a BTI PLT in 

>>>> this case. Thus even if there is no linker option to use BTI PLT, 

>>>> the linker

>>>> should be able to use them depending on the NOTE section. The user 

>>>> can use the linker option --bti, to make sure that their intention 

>>>> of having all input objects (and hence the output) marked with BTI 

>>>> is not disrupted by any stray objects as this option will warn about 

>>>> it.

>>>>

>>>>

>>>> The following patches implement these changes as follows:

>>>> [1/4] Add support for GNU PROPERTIES in AArch64 for BTI and PAC:

>>>> [2/4] Add --bti-nowarn to enable BTI without warning and to select 

>>>> BTI enabled PLTs

>>>> [3/4] Add --bti to enable BTI and select BTI enabled PLTs but also 

>>>> warn for missing NOTE sections.

>>>> [4/4] Add --pac-plt to enable PLTs protected with PAC.

>>>>

>>>> This is my first time making such intrusive changes to the linker. 

>>>> Please be kind :P

>>>>

>>>> Thanks

>>>> Sudi

>>>

>>> This is part of the patch series to add support for BTI and

>>> PAC in AArch64 linker.

>>>

>>> This patch implements the following:

>>> 1) This extends in the gnu property support in the linker for

>>> AArch64 by defining backend hooks for elf_backend_setup_gnu_properties,

>>> elf_backend_merge_gnu_properties and elf_backend_parse_gnu_properties.

>>> 2) It defines AArch64 specific GNU property

>>> GNU_PROPERTY_AARCH64_FEATURE_1_AND and 2 bit for BTI and PAC in it.

>>> 3) It also adds support in readelf.c to read and print these new

>>> GNU properties in AArch64.

>>> All these are made according to the new AArch64 ELF ABI

>>> https://developer.arm.com/docs/ihi0056/latest/elf-for-the-arm-64-bit-architecture-aarch64-abi-2018q4 

>>>

>>>

>>> Build and regression tests all pass on aarch64-none-linux-gnu and

>>> new tests are added.

>>>

>>> Is this ok for trunk?

>>>

>>> Thanks

>>> Sudi

>>>

>>> *** bfd/ChangeLog ***

>>>

>>> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

>>>

>>>      * elf-properties.c (_bfd_elf_link_setup_gnu_properties): Exclude

>>>      linker created inputs from merge.

>>>      * elfnn-aarch64.c (struct elf_aarch64_obj_tdata): Add field for

>>>      GNU_PROPERTY_AARCH64_FEATURE_1_AND properties.

>>>      (elfNN_aarch64_link_setup_gnu_properties): New.

>>>      (elfNN_aarch64_merge_gnu_properties): New.

>>>      (elf_backend_setup_gnu_properties): Define for AArch64.

>>>      (elf_backend_merge_gnu_properties): Likewise.

>>>      * elfxx-aarch64.c (_bfd_aarch64_elf_link_setup_gnu_properties): 

>>> Define.

>>>      (_bfd_aarch64_elf_parse_gnu_properties): Define.

>>>      (_bfd_aarch64_elf_merge_gnu_properties): Define.

>>>      * elfxx-aarch64.h (_bfd_aarch64_elf_link_setup_gnu_properties): 

>>> Declare.

>>>      (_bfd_aarch64_elf_parse_gnu_properties): Declare.

>>>      (_bfd_aarch64_elf_merge_gnu_properties): Declare.

>>>      (elf_backend_parse_gnu_properties): Define for AArch64.

>>>

>>> *** binutils/ChangeLog ***

>>>

>>> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

>>>

>>>      * readelf.c (decode_aarch64_feature_1_and): New.

>>>      (print_gnu_property_note): Add case for AArch64 gnu notes.

>>>

>>> *** include/ChangeLog ***

>>>

>>> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

>>>

>>>      * elf/common.h (GNU_PROPERTY_AARCH64_FEATURE_1_AND): New.

>>>      (GNU_PROPERTY_AARCH64_FEATURE_1_BTI): New.

>>>      (GNU_PROPERTY_AARCH64_FEATURE_1_PAC): New.

>>>

>>> *** ld/ChangeLog ***

>>>

>>> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

>>>

>>>      * NEWS: Document GNU_PROPERTY_AARCH64_FEATURE_1_BTI and

>>>      GNU_PROPERTY_AARCH64_FEATURE_1_PAC.

>>>      * testsuite/ld-aarch64/aarch64-elf.exp: Add run commands for new 

>>> tests.

>>>      * testsuite/ld-aarch64/property-bti-pac1.d: New test.

>>>      * testsuite/ld-aarch64/property-bti-pac1.s: New test.

>>>      * testsuite/ld-aarch64/property-bti-pac2.d: New test.

>>>      * testsuite/ld-aarch64/property-bti-pac2.s: New test.

>>>      * testsuite/ld-aarch64/property-bti-pac3.d: New test.

>>

>> This is part of the patch series to add support for BTI and

>> PAC in AArch64 linker.

>>

>> 1) This patch adds a new ld command line option: --bti-nowarn.

>> In the presence of this option, the linker enables BTI with the

>> GNU_PROPERTY_AARCH64_FEATURE_1_BTI feature. This gives no warning

>> in case of missing gnu notes for BTI in inputs.

>> 2) It also defines a new set of BTI enabled PLTs. These are used either

>> when all the inputs are marked with GNU_PROPERTY_AARCH64_FEATURE_1_BTI

>> or when the new --bti-nowarn option is used. This required adding new

>> fields in elf_aarch64_link_hash_table so that we could make the PLT

>> related information more generic.

>> 3) It also defines a dynamic tag DT_AARCH64_BTI_PLT. The linker uses

>> this whenever it picks BTI enabled PLTs.

>> All these are made according to the new AArch64 ELF ABI

>> https://developer.arm.com/docs/ihi0056/latest/elf-for-the-arm-64-bit-architecture-aarch64-abi-2018q4 

>>

>>

>> Build and regression tests all pass on aarch64-none-linux-gnu and

>> new tests are added.

>>

>> Is this ok for trunk?

>>

>> Thanks

>> Sudi

>>

>> *** bfd/ChangeLog ***

>>

>> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

>>          Szabolcs Nagy  <szabolcs.nagy@arm.com>

>>

>>      * bfd-in.h (aarch64_plt_type, aarch64_enable_bti_type): New.

>>      (aarch64_bti_pac_info): New.

>>      (bfd_elf64_aarch64_set_options): Add aarch64_bti_pac_info argument.

>>      (bfd_elf32_aarch64_set_options): Likewise.

>>      * bfd-in2.h: Regenerate

>>      * elfnn-aarch64.c (PLT_BTI_ENTRY_SIZE): New.

>>      (PLT_BTI_SMALL_ENTRY_SIZE, PLT_BTI_TLSDESC_ENTRY_SIZE): New.

>>      (elfNN_aarch64_small_plt0_bti_entry): New.

>>      (elfNN_aarch64_small_plt_bti_entry): New.

>>      (elfNN_aarch64_tlsdesc_small_plt_bti_entry): New.

>>      (elf_aarch64_obj_tdata): Add no_enable_bti_warn and plt_type fields.

>>      (elf_aarch64_link_hash_table): Add plt0_entry, plt_entry and

>>      tlsdesc_plt_entry_size fields.

>>      (elfNN_aarch64_link_hash_table_create): Initialise the new fields.

>>      (setup_plt_values): New helper function.

>>      (bfd_elfNN_aarch64_set_options): Use new bp_info to set plt sizes 

>> and

>>      bti enable type.

>>      (elfNN_aarch64_allocate_dynrelocs): Use new size members instead of

>>      fixed macros.

>>      (elfNN_aarch64_size_dynamic_sections): Likewise and add checks.

>>      (elfNN_aarch64_create_small_pltn_entry): Use new generic pointers

>>      to plt stubs instead of fixed ones and update filling them according

>>      to the need for bti.

>>      (elfNN_aarch64_init_small_plt0_entry): Likewise.

>>      (elfNN_aarch64_finish_dynamic_sections): Likewise.

>>      (get_plt_type, elfNN_aarch64_get_synthetic_symtab): New.

>>      (elfNN_aarch64_plt_sym_val): Update size accordingly.

>>      (elfNN_aarch64_link_setup_gnu_properties): Set up plts if BTI GNU 

>> NOTE

>>      is set.

>>      (bfd_elfNN_get_synthetic_symtab): Define.

>>

>> *** binutils/ChangeLog ***

>>

>> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

>>          Szabolcs Nagy  <szabolcs.nagy@arm.com>

>>

>>      * readelf.c (get_aarch64_dynamic_type): New.

>>      (get_dynamic_type): Use above for EM_AARCH64.

>>      (dynamic_section_aarch64_val): New.

>>      (process_dynamic_section): Use above for EM_AARCH64.

>>

>> *** include/ChangeLog ***

>>

>> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

>>          Szabolcs Nagy  <szabolcs.nagy@arm.com>

>>

>>      * elf/aarch64.h (DT_AARCH64_BTI_PLT): New.

>>

>> *** ld/ChangeLog ***

>>

>> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

>>          Szabolcs Nagy  <szabolcs.nagy@arm.com>

>>

>>      * NEWS: Document --bti-nowarn.

>>      * emultempl/aarch64elf.em (plt_type, bti_type, 

>> OPTION_BTI_NOWARN): New.

>>      (PARSE_AND_LIST_SHORTOPTS, PARSE_AND_LIST_OPTIONS): Add bti-nowarn.

>>      (PARSE_AND_LIST_ARGS_CASES): Handle OPTION_BTI_NOWARN.

>>      * testsuite/ld-aarch64/aarch64-elf.exp: Add all the tests below.

>>      * testsuite/ld-aarch64/bti-plt-1.d: New test.

>>      * testsuite/ld-aarch64/bti-plt-1.s: New test.

>>      * testsuite/ld-aarch64/bti-plt-2.d: New test.

>>      * testsuite/ld-aarch64/bti-plt-3.d: New test.

>>      * testsuite/ld-aarch64/bti-plt-4.d: New test.

>>      * testsuite/ld-aarch64/bti-plt-5.d: New test.

>>      * testsuite/ld-aarch64/bti-plt-so.s: New test.

>>      * testsuite/ld-aarch64/bti-plt.ld: New test.

> 

> This is part of the patch series to add support for BTI and

> PAC in AArch64 linker.

> 

> This patch adds a new ld command line option: --bti.

> In the presence of this option, the linker enables BTI with the

> GNU_PROPERTY_AARCH64_FEATURE_1_BTI feature. It also uses the BTI

> enabled PLTs and marks with DT_AARCH64_BTI_PLT. This also gives a

> warning in case of missing gnu notes for BTI in inputs.

> All these are made according to the new AArch64 ELF ABI

> https://developer.arm.com/docs/ihi0056/latest/elf-for-the-arm-64-bit-architecture-aarch64-abi-2018q4 

> 

> 

> Build and regression tests all pass on aarch64-none-linux-gnu and

> new tests are added.

> 

> Is this ok for trunk?

> 

> Thanks

> Sudi

> 

> *** bfd/ChangeLog ***

> 

> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

> 

>      * elfnn-aarch64.c (elfNN_aarch64_merge_gnu_properties): Give out

>      warning with --bti and mising BTI NOTE SECTION.

> 

> *** ld/ChangeLog ***

> 

> 2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

> 

>      * NEWS: Document --bti.

>      * emultempl/aarch64elf.em (OPTION_BTI_WARN): Define.

>      (PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS): Add --bti.

>      (PARSE_AND_LIST_ARGS_CASES): Handle OPTION_BTI_WARN.

>      * testsuite/ld-aarch64/aarch64-elf.exp: Add below tests.

>      * testsuite/ld-aarch64/bti-plt-6.d: New test.

>      * testsuite/ld-aarch64/bti-plt-7.d: New test.


This is part of the patch series to add support for BTI and
PAC in AArch64 linker.

1) This patch adds new definitions of PAC enabled PLTs
and both BTI and PAC enabled PLTs.
2) It also defines the new dynamic tag DT_AARCH64_PAC_PLT
for the PAC enabled PLTs.
3) This patch adds a new ld command line option: --pac-plt.
In the presence of this option, the linker uses the PAC
enabled PLTs and marks with DT_AARCH64_PAC_PLT.
4) In case both BTI and PAC are enabled the linker should
pick PLTs enabled with both and also use dynamic tags for both.
All these are made according to the new AArch64 ELF ABI
https://developer.arm.com/docs/ihi0056/latest/elf-for-the-arm-64-bit-architecture-aarch64-abi-2018q4

Build and regression tests all pass on aarch64-none-linux-gnu and
new tests are added.

Is this ok for trunk?

Thanks
Sudi

*** bfd/ChangeLog ***

2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

	* elfnn-aarch64.c (PLT_PAC_ENTRY_SIZE, PLT_PAC_SMALL_ENTRY_SIZE): New.
	(PLT_BTI_PAC_ENTRY_SIZE, PLT_BTI_PAC_SMALL_ENTRY_SIZE): New.
	(setup_plt_values): Account for PAC or PAC and BTI enabled PLTs.
	(elfNN_aarch64_size_dynamic_sections): Add checks for PLT_BTI_PAC
	and PLT_PAC_PLT.
	(elfNN_aarch64_finish_dynamic_sections): Account for PLT_BTI_PAC.
	(get_plt_type): Add case for DT_AARCH64_PAC_PLT.
	(elfNN_aarch64_plt_sym_val): Add cases for PLT_BTI_PAC and PLT_PAC.

*** binutils/ChangeLog ***

2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

	* readelf.c (get_aarch64_dynamic_type): Add case for
	DT_AARCH64_PAC_PLT.
	(dynamic_section_aarch64_val): Likewise.

*** include/ChangeLog ***

2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

	* elf/aarch64.h (DT_AARCH64_PAC_PLT): New.

*** ld/ChangeLog ***

2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

	* NEWS: Document --pac-plt.
	* emultempl/aarch64elf.em (OPTION_PAC_PLT): New.
	(PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS): Add pac-plt.
	(PARSE_AND_LIST_ARGS_CASES): Handle OPTION_PAC_PLT.
	* testsuite/ld-aarch64/aarch64-elf.exp: Add the following tests.
	* testsuite/ld-aarch64/bti-pac-plt-1.d: New test.
	* testsuite/ld-aarch64/bti-pac-plt-2.d: New test.
	* testsuite/ld-aarch64/pac-plt-1.d: New test.
	* testsuite/ld-aarch64/pac-plt-2.d: New test.

Comments

Szabolcs Nagy April 11, 2019, 2:47 p.m. | #1
On 06/03/2019 10:39, Sudakshina Das wrote:
> +static const bfd_byte elfNN_aarch64_small_plt0_pac_entry[PLT_PAC_ENTRY_SIZE] =

> +{

> +  0xf0, 0x7b, 0xbf, 0xa9,	/* stp x16, x30, [sp, #-16]!  */

> +  0x10, 0x00, 0x00, 0x90,	/* adrp x16, (GOT+16)  */

> +#if ARCH_SIZE == 64

> +  0x11, 0x0A, 0x40, 0xf9,	/* ldr x17, [x16, #PLT_GOT+0x10]  */

> +  0x10, 0x42, 0x00, 0x91,	/* add x16, x16,#PLT_GOT+0x10   */

> +#else

> +  0x11, 0x0A, 0x40, 0xb9,	/* ldr w17, [x16, #PLT_GOT+0x8]  */

> +  0x10, 0x22, 0x00, 0x11,	/* add w16, w16,#PLT_GOT+0x8   */

> +#endif

> +  0x9f, 0x21, 0x03, 0xd5,	/* autia1716 */

> +  0x20, 0x02, 0x1f, 0xd6,	/* br x17  */

> +  0x1f, 0x20, 0x03, 0xd5,	/* nop */

> +  0x1f, 0x20, 0x03, 0xd5,	/* nop */

> +  0x1f, 0x20, 0x03, 0xd5,	/* nop */

> +};

> +

> +static const bfd_byte

> +elfNN_aarch64_small_plt0_bti_pac_entry[PLT_BTI_PAC_ENTRY_SIZE] =

> +{

> +  0x5f, 0x24, 0x03, 0xd5,	/* bti c.  */

> +  0xf0, 0x7b, 0xbf, 0xa9,	/* stp x16, x30, [sp, #-16]!  */

> +  0x10, 0x00, 0x00, 0x90,	/* adrp x16, (GOT+16)  */

> +#if ARCH_SIZE == 64

> +  0x11, 0x0A, 0x40, 0xf9,	/* ldr x17, [x16, #PLT_GOT+0x10]  */

> +  0x10, 0x42, 0x00, 0x91,	/* add x16, x16,#PLT_GOT+0x10   */

> +#else

> +  0x11, 0x0A, 0x40, 0xb9,	/* ldr w17, [x16, #PLT_GOT+0x8]  */

> +  0x10, 0x22, 0x00, 0x11,	/* add w16, w16,#PLT_GOT+0x8   */

> +#endif

> +  0x9f, 0x21, 0x03, 0xd5,	/* autia1716 */

> +  0x20, 0x02, 0x1f, 0xd6,	/* br x17  */

> +  0x1f, 0x20, 0x03, 0xd5,	/* nop */

> +  0x1f, 0x20, 0x03, 0xd5,	/* nop */

> +  0x1f, 0x20, 0x03, 0xd5,	/* nop */

> +};


sorry i hadn't noticed this before,
PLT0 does not need a PAC variant because the
PLTGOT[2] entry that's loaded here is readonly
protected under relro (i think the linker
script magic for relro guarantees this).

in principle using autia here works too
(just additional unnecessary autia in the lazy
resolution code path), however this is ABI
between a dynamic linker and static linker:
with such PLT0 the PLTGOT[2] has to be filled
in with a signed pointer.

it seems our ELF ABI does not describe this
(PLT sequence should be in the SYS V ABI),
i think if we agree that relro always protects
PLTGOT[2] then we can still change this.
(to reduce the number of supported PLT0 entries)

Patch

diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 047ba431f94446e44f54b8cad7b2c83c7a10dba6..773a028eea2f6dfd8ec4fbafaf6322095e8bcb86 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -271,6 +271,12 @@ 
 #define PLT_BTI_ENTRY_SIZE		(36)
 #define PLT_BTI_SMALL_ENTRY_SIZE	(20)
 #define PLT_BTI_TLSDESC_ENTRY_SIZE	(36)
+/* PLT sizes with PAC insn.  */
+#define PLT_PAC_ENTRY_SIZE		(36)
+#define PLT_PAC_SMALL_ENTRY_SIZE	(20)
+/* PLT sizes with BTI and PAC insn.  */
+#define PLT_BTI_PAC_ENTRY_SIZE		(40)
+#define PLT_BTI_PAC_SMALL_ENTRY_SIZE	(24)
 
 /* Encoding of the nop instruction.  */
 #define INSN_NOP 0xd503201f
@@ -319,6 +325,44 @@  static const bfd_byte elfNN_aarch64_small_plt0_bti_entry[PLT_BTI_ENTRY_SIZE] =
   0x1f, 0x20, 0x03, 0xd5,	/* nop */
 };
 
+static const bfd_byte elfNN_aarch64_small_plt0_pac_entry[PLT_PAC_ENTRY_SIZE] =
+{
+  0xf0, 0x7b, 0xbf, 0xa9,	/* stp x16, x30, [sp, #-16]!  */
+  0x10, 0x00, 0x00, 0x90,	/* adrp x16, (GOT+16)  */
+#if ARCH_SIZE == 64
+  0x11, 0x0A, 0x40, 0xf9,	/* ldr x17, [x16, #PLT_GOT+0x10]  */
+  0x10, 0x42, 0x00, 0x91,	/* add x16, x16,#PLT_GOT+0x10   */
+#else
+  0x11, 0x0A, 0x40, 0xb9,	/* ldr w17, [x16, #PLT_GOT+0x8]  */
+  0x10, 0x22, 0x00, 0x11,	/* add w16, w16,#PLT_GOT+0x8   */
+#endif
+  0x9f, 0x21, 0x03, 0xd5,	/* autia1716 */
+  0x20, 0x02, 0x1f, 0xd6,	/* br x17  */
+  0x1f, 0x20, 0x03, 0xd5,	/* nop */
+  0x1f, 0x20, 0x03, 0xd5,	/* nop */
+  0x1f, 0x20, 0x03, 0xd5,	/* nop */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt0_bti_pac_entry[PLT_BTI_PAC_ENTRY_SIZE] =
+{
+  0x5f, 0x24, 0x03, 0xd5,	/* bti c.  */
+  0xf0, 0x7b, 0xbf, 0xa9,	/* stp x16, x30, [sp, #-16]!  */
+  0x10, 0x00, 0x00, 0x90,	/* adrp x16, (GOT+16)  */
+#if ARCH_SIZE == 64
+  0x11, 0x0A, 0x40, 0xf9,	/* ldr x17, [x16, #PLT_GOT+0x10]  */
+  0x10, 0x42, 0x00, 0x91,	/* add x16, x16,#PLT_GOT+0x10   */
+#else
+  0x11, 0x0A, 0x40, 0xb9,	/* ldr w17, [x16, #PLT_GOT+0x8]  */
+  0x10, 0x22, 0x00, 0x11,	/* add w16, w16,#PLT_GOT+0x8   */
+#endif
+  0x9f, 0x21, 0x03, 0xd5,	/* autia1716 */
+  0x20, 0x02, 0x1f, 0xd6,	/* br x17  */
+  0x1f, 0x20, 0x03, 0xd5,	/* nop */
+  0x1f, 0x20, 0x03, 0xd5,	/* nop */
+  0x1f, 0x20, 0x03, 0xd5,	/* nop */
+};
+
 /* Per function entry in a procedure linkage table looks like this
    if the distance between the PLTGOT and the PLT is < 4GB use
    these PLT entries.  Use BTI versions of the PLTs when enabled.  */
@@ -351,6 +395,37 @@  elfNN_aarch64_small_plt_bti_entry[PLT_BTI_SMALL_ENTRY_SIZE] =
 };
 
 static const bfd_byte
+elfNN_aarch64_small_plt_pac_entry[PLT_PAC_SMALL_ENTRY_SIZE] =
+{
+  0x10, 0x00, 0x00, 0x90,	/* adrp x16, PLTGOT + n * 8  */
+#if ARCH_SIZE == 64
+  0x11, 0x02, 0x40, 0xf9,	/* ldr x17, [x16, PLTGOT + n * 8] */
+  0x10, 0x02, 0x00, 0x91,	/* add x16, x16, :lo12:PLTGOT + n * 8  */
+#else
+  0x11, 0x02, 0x40, 0xb9,	/* ldr w17, [x16, PLTGOT + n * 4] */
+  0x10, 0x02, 0x00, 0x11,	/* add w16, w16, :lo12:PLTGOT + n * 4  */
+#endif
+  0x9f, 0x21, 0x03, 0xd5,	/* autia1716 */
+  0x20, 0x02, 0x1f, 0xd6,	/* br x17.  */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt_bti_pac_entry[PLT_BTI_PAC_SMALL_ENTRY_SIZE] =
+{
+  0x5f, 0x24, 0x03, 0xd5,	/* bti c.  */
+  0x10, 0x00, 0x00, 0x90,	/* adrp x16, PLTGOT + n * 8  */
+#if ARCH_SIZE == 64
+  0x11, 0x02, 0x40, 0xf9,	/* ldr x17, [x16, PLTGOT + n * 8] */
+  0x10, 0x02, 0x00, 0x91,	/* add x16, x16, :lo12:PLTGOT + n * 8  */
+#else
+  0x11, 0x02, 0x40, 0xb9,	/* ldr w17, [x16, PLTGOT + n * 4] */
+  0x10, 0x02, 0x00, 0x11,	/* add w16, w16, :lo12:PLTGOT + n * 4  */
+#endif
+  0x9f, 0x21, 0x03, 0xd5,	/* autia1716 */
+  0x20, 0x02, 0x1f, 0xd6,	/* br x17.  */
+};
+
+static const bfd_byte
 elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] =
 {
   0xe2, 0x0f, 0xbf, 0xa9,	/* stp x2, x3, [sp, #-16]! */
@@ -4681,7 +4756,25 @@  setup_plt_values (struct bfd_link_info *link_info,
   struct elf_aarch64_link_hash_table *globals;
   globals = elf_aarch64_hash_table (link_info);
 
-  if (plt_type == PLT_BTI)
+  if (plt_type == PLT_BTI_PAC)
+    {
+      globals->plt_header_size = PLT_BTI_PAC_ENTRY_SIZE;
+      globals->plt0_entry = elfNN_aarch64_small_plt0_bti_pac_entry;
+      globals->tlsdesc_plt_entry_size = PLT_BTI_TLSDESC_ENTRY_SIZE;
+
+      /* Only in ET_EXEC we need PLTn with BTI.  */
+      if (bfd_link_pde (link_info))
+	{
+	  globals->plt_entry_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE;
+	  globals->plt_entry = elfNN_aarch64_small_plt_bti_pac_entry;
+	}
+      else
+	{
+	  globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE;
+	  globals->plt_entry = elfNN_aarch64_small_plt_pac_entry;
+	}
+    }
+  else if (plt_type == PLT_BTI)
     {
       globals->plt_header_size = PLT_BTI_ENTRY_SIZE;
       globals->plt0_entry = elfNN_aarch64_small_plt0_bti_entry;
@@ -4694,6 +4787,14 @@  setup_plt_values (struct bfd_link_info *link_info,
 	  globals->plt_entry = elfNN_aarch64_small_plt_bti_entry;
 	}
     }
+  else if (plt_type == PLT_PAC)
+    {
+      globals->plt_header_size = PLT_PAC_ENTRY_SIZE;
+      globals->plt0_entry = elfNN_aarch64_small_plt0_pac_entry;
+      globals->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
+      globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE;
+      globals->plt_entry = elfNN_aarch64_small_plt_pac_entry;
+    }
 }
 
 /* Set option values needed during linking.  */
@@ -9083,8 +9184,17 @@  elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 		  || !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
 	    return FALSE;
 
-	  if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI)
-	      && !add_dynamic_entry (DT_AARCH64_BTI_PLT, 0))
+	  if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI_PAC)
+	      && (!add_dynamic_entry (DT_AARCH64_BTI_PLT, 0)
+		  || !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0)))
+	    return FALSE;
+
+	  else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI)
+		   && !add_dynamic_entry (DT_AARCH64_BTI_PLT, 0))
+	    return FALSE;
+
+	  else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_PAC)
+		   && !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0))
 	    return FALSE;
 	}
 
@@ -9610,7 +9720,7 @@  elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
 	  htab->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
 
 	  aarch64_plt_type type = elf_aarch64_tdata (output_bfd)->plt_type;
-	  if (type == PLT_BTI)
+	  if (type == PLT_BTI || type == PLT_BTI_PAC)
 	    {
 	      entry = elfNN_aarch64_tlsdesc_small_plt_bti_entry;
 	      htab->tlsdesc_plt_entry_size = PLT_BTI_TLSDESC_ENTRY_SIZE;
@@ -9750,7 +9860,11 @@  get_plt_type (bfd *abfd)
       switch (tag)
 	{
 	case DT_AARCH64_BTI_PLT:
-	  ret = PLT_BTI;
+	  ret |= PLT_BTI;
+	  break;
+
+	case DT_AARCH64_PAC_PLT:
+	  ret |= PLT_PAC;
 	  break;
 
 	default: break;
@@ -9783,12 +9897,26 @@  elfNN_aarch64_plt_sym_val (bfd_vma i, const asection *plt,
   size_t plt0_size = PLT_ENTRY_SIZE;
   size_t pltn_size = PLT_SMALL_ENTRY_SIZE;
 
-  if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI)
+  if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI_PAC)
+    {
+      plt0_size = PLT_BTI_PAC_ENTRY_SIZE;
+      if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
+	pltn_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE;
+      else
+	pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
+    }
+  else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI)
     {
       plt0_size = PLT_BTI_ENTRY_SIZE;
       if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
 	pltn_size = PLT_BTI_SMALL_ENTRY_SIZE;
     }
+  else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_PAC)
+    {
+      plt0_size = PLT_PAC_ENTRY_SIZE;
+      pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
+    }
+
   return plt->vma + plt0_size + i * pltn_size;
 }
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index f4775b439fc6a14a14699c88af3fe5f07648352e..5a9d9ff433d5438e073e871b9c92d307d9f279d3 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -1803,6 +1803,7 @@  get_aarch64_dynamic_type (unsigned long type)
   switch (type)
     {
     case DT_AARCH64_BTI_PLT:  return "AARCH64_BTI_PLT";
+    case DT_AARCH64_PAC_PLT:  return "AARCH64_PAC_PLT";
     default:
       return NULL;
     }
@@ -9364,6 +9365,7 @@  dynamic_section_aarch64_val (Elf_Internal_Dyn * entry)
   switch (entry->d_tag)
     {
     case DT_AARCH64_BTI_PLT:
+    case DT_AARCH64_PAC_PLT:
       break;
     default:
       print_vma (entry->d_un.d_ptr, PREFIX_HEX);
diff --git a/include/elf/aarch64.h b/include/elf/aarch64.h
index b86a1006297891d38f55f0c29d0ac51056b0c6e3..44665476265b8d20c59343dcbafc87766a5444c0 100644
--- a/include/elf/aarch64.h
+++ b/include/elf/aarch64.h
@@ -37,6 +37,7 @@ 
 						in the input to a link step.  */
 /* Processor specific dynamic array tags.  */
 #define DT_AARCH64_BTI_PLT	(DT_LOPROC + 1)
+#define DT_AARCH64_PAC_PLT	(DT_LOPROC + 3)
 
 /* Relocation types.  */
 
diff --git a/ld/NEWS b/ld/NEWS
index ec234dfeb0869a407ee266b476cfdb956de8ceaf..b5ffffa7957e39e03003171b77c8f816273cf465 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -17,6 +17,8 @@  Changes in 2.33:
   on output while warning about missing GNU_PROPERTY_AARCH64_FEATURE_1_BTI
   on inputs and pick BTI enables PLTs.
 
+* Add --pac-plt for AArch64 to pick PAC enabled PLTs.
+
 Changes in 2.32:
 
 * Report property change in linker map file when merging GNU properties.
diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em
index c2db3e9e531930f0659197219369da1ddb04275c..520d621f4eef94956de2f24ccd39917083279a6c 100644
--- a/ld/emultempl/aarch64elf.em
+++ b/ld/emultempl/aarch64elf.em
@@ -374,6 +374,7 @@  PARSE_AND_LIST_PROLOGUE='
 #define OPTION_NO_APPLY_DYNAMIC_RELOCS	315
 #define OPTION_BTI_NOWARN		316
 #define OPTION_BTI_WARN			317
+#define OPTION_PAC_PLT			318
 '
 
 PARSE_AND_LIST_SHORTOPTS=p
@@ -389,6 +390,7 @@  PARSE_AND_LIST_LONGOPTS='
   { "no-apply-dynamic-relocs", no_argument, NULL, OPTION_NO_APPLY_DYNAMIC_RELOCS},
   { "bti-nowarn", no_argument, NULL, OPTION_BTI_NOWARN},
   { "bti", no_argument, NULL, OPTION_BTI_WARN},
+  { "pac-plt", no_argument, NULL, OPTION_PAC_PLT},
 '
 
 PARSE_AND_LIST_OPTIONS='
@@ -411,6 +413,7 @@  PARSE_AND_LIST_OPTIONS='
   fprintf (file, _("  --no-apply-dynamic-relocs    Do not apply link-time values for dynamic relocations\n"));
   fprintf (file, _("  --bti-nowarn                 Turn on Branch Target Identification mechanism and generate PLTs with BTI. Generate no warnings for missing BTI on inputs\n"));
   fprintf (file, _("  --bti                        Turn on Branch Target Identification mechanism and generate PLTs with BTI. Generate warnings for missing BTI on inputs\n"));
+  fprintf (file, _("  --pac-plt                    Protect PLTs with Pointer Authentication.\n"));
 '
 
 PARSE_AND_LIST_ARGS_CASES='
@@ -452,6 +455,10 @@  PARSE_AND_LIST_ARGS_CASES='
       bti_type = BTI_WARN;
       break;
 
+    case OPTION_PAC_PLT:
+      plt_type |= PLT_PAC;
+      break;
+
     case OPTION_STUBGROUP_SIZE:
       {
 	const char *end;
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 906534b230c8905fb97a6739e1c1411683455fe3..12c2d97d53770e886bb913e19aef996a64fc1805 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -402,3 +402,8 @@  run_dump_test "bti-plt-4"
 run_dump_test "bti-plt-5"
 run_dump_test "bti-plt-6"
 run_dump_test "bti-plt-7"
+
+run_dump_test "pac-plt-1"
+run_dump_test "pac-plt-2"
+run_dump_test "bti-pac-plt-1"
+run_dump_test "bti-pac-plt-2"
diff --git a/ld/testsuite/ld-aarch64/bti-pac-plt-1.d b/ld/testsuite/ld-aarch64/bti-pac-plt-1.d
new file mode 100644
index 0000000000000000000000000000000000000000..feebb971228edaf9484782d4e44e59733e88b04a
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-pac-plt-1.d
@@ -0,0 +1,34 @@ 
+#source: bti-plt-1.s
+#as: -mabi=lp64
+#ld: -shared --bti --pac-plt -T bti-plt.ld
+#objdump: -dr -j .plt
+
+[^:]*: *file format elf64-.*aarch64
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <.*>:
+.*:	d503245f 	bti	c
+.*:	a9bf7bf0 	stp	x16, x30, \[sp, #-16\]!
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9400e11 	ldr	x17, \[x16, #24\]
+.*:	91006210 	add	x16, x16, #0x18
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+
+[0-9a-f]+ <.*>:
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9401211 	ldr	x17, \[x16, #32\]
+.*:	91008210 	add	x16, x16, #0x20
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
+
+[0-9a-f]+ <.*>:
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9401611 	ldr	x17, \[x16, #40\]
+.*:	9100a210 	add	x16, x16, #0x28
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
diff --git a/ld/testsuite/ld-aarch64/bti-pac-plt-2.d b/ld/testsuite/ld-aarch64/bti-pac-plt-2.d
new file mode 100644
index 0000000000000000000000000000000000000000..2d9fab8101b129b8ebfef1a2abc2e01b98bf06e5
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-pac-plt-2.d
@@ -0,0 +1,36 @@ 
+#source: bti-plt-1.s
+#as: -mabi=lp64
+#ld: --bti --pac-plt -e _start -T bti-plt.ld -L./tmpdir -lbti-plt-so
+#objdump: -dr -j .plt
+
+[^:]*: *file format elf64-.*aarch64
+
+Disassembly of section \.plt:
+
+[0-9]+ <.*>:
+.*:	d503245f 	bti	c
+.*:	a9bf7bf0 	stp	x16, x30, \[sp, #-16\]!
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9400e11 	ldr	x17, \[x16, #24\]
+.*:	91006210 	add	x16, x16, #0x18
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+
+[0-9]+ <.*>:
+.*:	d503245f 	bti	c
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9401211 	ldr	x17, \[x16, #32\]
+.*:	91008210 	add	x16, x16, #0x20
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
+
+[0-9]+ <.*>:
+.*:	d503245f 	bti	c
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9401611 	ldr	x17, \[x16, #40\]
+.*:	9100a210 	add	x16, x16, #0x28
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
diff --git a/ld/testsuite/ld-aarch64/pac-plt-1.d b/ld/testsuite/ld-aarch64/pac-plt-1.d
new file mode 100644
index 0000000000000000000000000000000000000000..09a07f907e5f4ddedc628f9474713ddb696de2a0
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/pac-plt-1.d
@@ -0,0 +1,33 @@ 
+#source: bti-plt-1.s
+#as: -mabi=lp64
+#ld: -shared --pac-plt -T bti-plt.ld
+#objdump: -dr -j .plt
+
+[^:]*: *file format elf64-.*aarch64
+
+Disassembly of section \.plt:
+
+[0-9]+ <.*>:
+.*:	a9bf7bf0 	stp	x16, x30, \[sp, #-16\]!
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9400e11 	ldr	x17, \[x16, #24\]
+.*:	91006210 	add	x16, x16, #0x18
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+
+[0-9]+ <.*>:
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9401211 	ldr	x17, \[x16, #32\]
+.*:	91008210 	add	x16, x16, #0x20
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
+
+[0-9]+ <.*>:
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9401611 	ldr	x17, \[x16, #40\]
+.*:	9100a210 	add	x16, x16, #0x28
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
diff --git a/ld/testsuite/ld-aarch64/pac-plt-2.d b/ld/testsuite/ld-aarch64/pac-plt-2.d
new file mode 100644
index 0000000000000000000000000000000000000000..42bfdca6218d191de846ce482f23b5f627e55034
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/pac-plt-2.d
@@ -0,0 +1,24 @@ 
+#source: tls-desc-ie.s
+#ld: -shared --pac-plt -T bti-plt.ld
+#objdump: -dr -j .plt
+#...
+Disassembly of section .plt:
+
+0000000000018000 \<.plt\>:
+.*:	a9bf7bf0 	stp	x16, x30, \[sp, #-16\]!
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9401a11 	ldr	x17, \[x16, #48\]
+.*:	9100c210 	add	x16, x16, #0x30
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+
+
+0000000000018024 \<__tls_get_addr@plt\>:
+.*:	90000090 	adrp	x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*:	f9401e11 	ldr	x17, \[x16, #56\]
+.*:	9100e210 	add	x16, x16, #0x38
+.*:	d503219f 	autia1716
+.*:	d61f0220 	br	x17