21
21
#include " llvm/ADT/STLExtras.h"
22
22
#include " llvm/LTO/LTO.h"
23
23
#include " llvm/Object/IRObjectFile.h"
24
+ #include " llvm/Support/AArch64AttributeParser.h"
24
25
#include " llvm/Support/ARMAttributeParser.h"
25
26
#include " llvm/Support/ARMBuildAttributes.h"
26
27
#include " llvm/Support/Endian.h"
@@ -537,6 +538,51 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const {
537
538
this );
538
539
}
539
540
541
+ template <class ELFT >
542
+ static void
543
+ handleAArch64BAAndGnuProperties (ObjFile<ELFT> *file, Ctx &ctx, bool hasGP,
544
+ const AArch64BuildAttrSubsections &baInfo,
545
+ const GnuPropertiesInfo &gpInfo) {
546
+ if (hasGP) {
547
+ // Check for data mismatch
548
+ if (gpInfo.pauthAbiCoreInfo ) {
549
+ if (baInfo.Pauth .TagPlatform != gpInfo.pauthAbiCoreInfo ->platform ||
550
+ baInfo.Pauth .TagSchema != gpInfo.pauthAbiCoreInfo ->version )
551
+ Err (ctx)
552
+ << file
553
+ << " Pauth Data mismatch: file contains both GNU properties and "
554
+ " AArch64 build attributes sections with different Pauth data" ;
555
+ }
556
+ if (baInfo.AndFeatures != gpInfo.andFeatures )
557
+ Err (ctx) << file
558
+ << " Features Data mismatch: file contains both GNU "
559
+ " properties and AArch64 build attributes sections with "
560
+ " different And Features data" ;
561
+ } else {
562
+ // Write missing data
563
+ // We can only know when Pauth is missing.
564
+ // Unlike AArch64 Build Attributes, GNU properties does not give a way to
565
+ // distinguish between no-value given to value of '0' given.
566
+ if (baInfo.Pauth .TagPlatform || baInfo.Pauth .TagSchema ) {
567
+ // According to the BuildAttributes specification Build Attributes
568
+ // default to a value of 0 when not present. A (TagPlatform, TagSchema) of
569
+ // (0, 0) maps to 'no PAuth property present'. A (TagPlatform, TagSchema)
570
+ // of (0, 1) maps to an explicit PAuth property of platform = 0, version =
571
+ // 0 ('Invalid').
572
+ if (baInfo.Pauth .TagPlatform == 0 && baInfo.Pauth .TagSchema == 1 ) {
573
+ file->aarch64PauthAbiCoreInfo = {0 , 0 };
574
+ }
575
+ file->aarch64PauthAbiCoreInfo = {baInfo.Pauth .TagPlatform ,
576
+ baInfo.Pauth .TagSchema };
577
+ }
578
+ file->andFeatures = baInfo.AndFeatures ;
579
+ }
580
+ }
581
+
582
+ template <typename ELFT>
583
+ static GnuPropertiesInfo readGnuProperty (Ctx &, const InputSection &,
584
+ ObjFile<ELFT> &);
585
+
540
586
template <class ELFT > void ObjFile<ELFT>::parse(bool ignoreComdats) {
541
587
object::ELFFile<ELFT> obj = this ->getObj ();
542
588
// Read a section table. justSymbols is usually false.
@@ -552,8 +598,31 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
552
598
StringRef shstrtab = CHECK2 (obj.getSectionStringTable (objSections), this );
553
599
uint64_t size = objSections.size ();
554
600
sections.resize (size);
601
+
602
+ // For handling AArch64 Build attributes and GNU properties
603
+ AArch64BuildAttrSubsections aarch64BAsubSections;
604
+ GnuPropertiesInfo gnuProperty;
605
+ bool hasAArch64BuildAttributes = false ;
606
+ bool hasGNUProperties = false ;
607
+
555
608
for (size_t i = 0 ; i != size; ++i) {
556
609
const Elf_Shdr &sec = objSections[i];
610
+ // Object files that use processor features such as Intel Control-Flow
611
+ // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
612
+ // .note.gnu.property section containing a bitfield of feature bits like the
613
+ // GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
614
+ if (check (obj.getSectionName (sec, shstrtab)) == " .note.gnu.property" ) {
615
+ gnuProperty = readGnuProperty (
616
+ ctx,
617
+ InputSection (*this , sec, check (obj.getSectionName (sec, shstrtab))),
618
+ *this );
619
+ hasGNUProperties = true ;
620
+ // Since we merge bitmaps from multiple object files to create a new
621
+ // .note.gnu.property containing a single AND'ed bitmap, we discard an
622
+ // input file's .note.gnu.property section.
623
+ sections[i] = &InputSection::discarded;
624
+ }
625
+
557
626
if (LLVM_LIKELY (sec.sh_type == SHT_PROGBITS))
558
627
continue ;
559
628
if (LLVM_LIKELY (sec.sh_type == SHT_GROUP)) {
@@ -637,13 +706,27 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
637
706
}
638
707
break ;
639
708
case EM_AARCH64:
640
- // FIXME: BuildAttributes have been implemented in llvm, but not yet in
641
- // lld. Remove the section so that it does not accumulate in the output
642
- // file. When support is implemented we expect not to output a build
643
- // attributes section in files of type ET_EXEC or ET_SHARED, but ld -r
644
- // ouptut will need a single merged attributes section.
645
- if (sec.sh_type == SHT_AARCH64_ATTRIBUTES)
709
+ // At this stage AArch64 Build Attributes does not replace GNU Properties.
710
+ // When both exists, their values must match.
711
+ // When both exists and contain different attributes, they complement each
712
+ // other. Currently attributes are represented in the linked object file
713
+ // as GNU properties, which are already supported by the Linux kernel and
714
+ // the dynamic loader. In the future, when relocatable linking (`-r` flag)
715
+ // is performed, a single merged AArch64 Build Attributes section will be
716
+ // emitted.
717
+ if (sec.sh_type == SHT_AARCH64_ATTRIBUTES) {
718
+ ArrayRef<uint8_t > contents = check (obj.getSectionContents (sec));
719
+ AArch64AttributeParser attributes;
720
+ StringRef name = check (obj.getSectionName (sec, shstrtab));
721
+ InputSection isec (*this , sec, name);
722
+ if (Error e = attributes.parse (contents, ELFT::Endianness)) {
723
+ Warn (ctx) << &isec << " : " << std::move (e);
724
+ } else {
725
+ aarch64BAsubSections = extractBuildAttributesSubsections (attributes);
726
+ hasAArch64BuildAttributes = true ;
727
+ }
646
728
sections[i] = &InputSection::discarded;
729
+ }
647
730
// Producing a static binary with MTE globals is not currently supported,
648
731
// remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
649
732
// medatada, and we don't want them to end up in the output file for
@@ -655,6 +738,14 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
655
738
}
656
739
}
657
740
741
+ if (hasAArch64BuildAttributes) {
742
+ // Handle AArch64 Build Attributes and GNU properties:
743
+ // - Err on mismatched values.
744
+ // - Store missing values as GNU properties.
745
+ handleAArch64BAAndGnuProperties<ELFT>(this , ctx, hasGNUProperties,
746
+ aarch64BAsubSections, gnuProperty);
747
+ }
748
+
658
749
// Read a symbol table.
659
750
initializeSymbols (obj);
660
751
}
@@ -974,8 +1065,8 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
974
1065
// hardware-assisted call flow control;
975
1066
// - AArch64 PAuth ABI core info (16 bytes).
976
1067
template <class ELFT >
977
- static void readGnuProperty (Ctx &ctx, const InputSection &sec,
978
- ObjFile<ELFT> &f) {
1068
+ static GnuPropertiesInfo readGnuProperty (Ctx &ctx, const InputSection &sec,
1069
+ ObjFile<ELFT> &f) {
979
1070
using Elf_Nhdr = typename ELFT::Nhdr;
980
1071
using Elf_Note = typename ELFT::Note;
981
1072
@@ -992,7 +1083,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
992
1083
featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
993
1084
break ;
994
1085
default :
995
- return ;
1086
+ return GnuPropertiesInfo{} ;
996
1087
}
997
1088
998
1089
ArrayRef<uint8_t > data = sec.content ();
@@ -1007,7 +1098,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
1007
1098
auto *nhdr = reinterpret_cast <const Elf_Nhdr *>(data.data ());
1008
1099
if (data.size () < sizeof (Elf_Nhdr) ||
1009
1100
data.size () < nhdr->getSize (sec.addralign ))
1010
- return void (err (data.data ()) << " data is too short" );
1101
+ return (err (data.data ()) << " data is too short" , GnuPropertiesInfo{} );
1011
1102
1012
1103
Elf_Note note (*nhdr);
1013
1104
if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName () != " GNU" ) {
@@ -1023,6 +1114,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
1023
1114
// Go to next NOTE record to look for more FEATURE_1_AND descriptions.
1024
1115
data = data.slice (nhdr->getSize (sec.addralign ));
1025
1116
}
1117
+ return GnuPropertiesInfo{f.andFeatures , f.aarch64PauthAbiCoreInfo };
1026
1118
}
1027
1119
1028
1120
template <class ELFT >
0 commit comments