2121#include " llvm/ADT/STLExtras.h"
2222#include " llvm/LTO/LTO.h"
2323#include " llvm/Object/IRObjectFile.h"
24+ #include " llvm/Support/AArch64AttributeParser.h"
2425#include " llvm/Support/ARMAttributeParser.h"
2526#include " llvm/Support/ARMBuildAttributes.h"
2627#include " llvm/Support/Endian.h"
@@ -537,6 +538,52 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const {
537538 this );
538539}
539540
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+ } else {
575+ file->aarch64PauthAbiCoreInfo = {baInfo.Pauth .TagPlatform ,
576+ baInfo.Pauth .TagSchema };
577+ }
578+ }
579+ file->andFeatures = baInfo.AndFeatures ;
580+ }
581+ }
582+
583+ template <typename ELFT>
584+ static GnuPropertiesInfo readGnuProperty (Ctx &, const InputSection &,
585+ ObjFile<ELFT> &);
586+
540587template <class ELFT > void ObjFile<ELFT>::parse(bool ignoreComdats) {
541588 object::ELFFile<ELFT> obj = this ->getObj ();
542589 // Read a section table. justSymbols is usually false.
@@ -552,8 +599,31 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
552599 StringRef shstrtab = CHECK2 (obj.getSectionStringTable (objSections), this );
553600 uint64_t size = objSections.size ();
554601 sections.resize (size);
602+
603+ // For handling AArch64 Build attributes and GNU properties
604+ AArch64BuildAttrSubsections aarch64BAsubSections;
605+ GnuPropertiesInfo gnuProperty;
606+ bool hasAArch64BuildAttributes = false ;
607+ bool hasGNUProperties = false ;
608+
555609 for (size_t i = 0 ; i != size; ++i) {
556610 const Elf_Shdr &sec = objSections[i];
611+ // Object files that use processor features such as Intel Control-Flow
612+ // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
613+ // .note.gnu.property section containing a bitfield of feature bits like the
614+ // GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
615+ if (check (obj.getSectionName (sec, shstrtab)) == " .note.gnu.property" ) {
616+ gnuProperty = readGnuProperty (
617+ ctx,
618+ InputSection (*this , sec, check (obj.getSectionName (sec, shstrtab))),
619+ *this );
620+ hasGNUProperties = true ;
621+ // Since we merge bitmaps from multiple object files to create a new
622+ // .note.gnu.property containing a single AND'ed bitmap, we discard an
623+ // input file's .note.gnu.property section.
624+ sections[i] = &InputSection::discarded;
625+ }
626+
557627 if (LLVM_LIKELY (sec.sh_type == SHT_PROGBITS))
558628 continue ;
559629 if (LLVM_LIKELY (sec.sh_type == SHT_GROUP)) {
@@ -637,13 +707,27 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
637707 }
638708 break ;
639709 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)
710+ // At this stage AArch64 Build Attributes does not replace GNU Properties.
711+ // When both exists, their values must match.
712+ // When both exists and contain different attributes, they complement each
713+ // other. Currently attributes are represented in the linked object file
714+ // as GNU properties, which are already supported by the Linux kernel and
715+ // the dynamic loader. In the future, when relocatable linking (`-r` flag)
716+ // is performed, a single merged AArch64 Build Attributes section will be
717+ // emitted.
718+ if (sec.sh_type == SHT_AARCH64_ATTRIBUTES) {
719+ ArrayRef<uint8_t > contents = check (obj.getSectionContents (sec));
720+ AArch64AttributeParser attributes;
721+ StringRef name = check (obj.getSectionName (sec, shstrtab));
722+ InputSection isec (*this , sec, name);
723+ if (Error e = attributes.parse (contents, ELFT::Endianness)) {
724+ Warn (ctx) << &isec << " : " << std::move (e);
725+ } else {
726+ aarch64BAsubSections = extractBuildAttributesSubsections (attributes);
727+ hasAArch64BuildAttributes = true ;
728+ }
646729 sections[i] = &InputSection::discarded;
730+ }
647731 // Producing a static binary with MTE globals is not currently supported,
648732 // remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
649733 // medatada, and we don't want them to end up in the output file for
@@ -655,6 +739,14 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
655739 }
656740 }
657741
742+ if (hasAArch64BuildAttributes) {
743+ // Handle AArch64 Build Attributes and GNU properties:
744+ // - Err on mismatched values.
745+ // - Store missing values as GNU properties.
746+ handleAArch64BAAndGnuProperties<ELFT>(this , ctx, hasGNUProperties,
747+ aarch64BAsubSections, gnuProperty);
748+ }
749+
658750 // Read a symbol table.
659751 initializeSymbols (obj);
660752}
@@ -974,8 +1066,8 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
9741066// hardware-assisted call flow control;
9751067// - AArch64 PAuth ABI core info (16 bytes).
9761068template <class ELFT >
977- static void readGnuProperty (Ctx &ctx, const InputSection &sec,
978- ObjFile<ELFT> &f) {
1069+ static GnuPropertiesInfo readGnuProperty (Ctx &ctx, const InputSection &sec,
1070+ ObjFile<ELFT> &f) {
9791071 using Elf_Nhdr = typename ELFT::Nhdr;
9801072 using Elf_Note = typename ELFT::Note;
9811073
@@ -992,7 +1084,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
9921084 featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
9931085 break ;
9941086 default :
995- return ;
1087+ return GnuPropertiesInfo{} ;
9961088 }
9971089
9981090 ArrayRef<uint8_t > data = sec.content ();
@@ -1007,7 +1099,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
10071099 auto *nhdr = reinterpret_cast <const Elf_Nhdr *>(data.data ());
10081100 if (data.size () < sizeof (Elf_Nhdr) ||
10091101 data.size () < nhdr->getSize (sec.addralign ))
1010- return void (err (data.data ()) << " data is too short" );
1102+ return (err (data.data ()) << " data is too short" , GnuPropertiesInfo{} );
10111103
10121104 Elf_Note note (*nhdr);
10131105 if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName () != " GNU" ) {
@@ -1023,6 +1115,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
10231115 // Go to next NOTE record to look for more FEATURE_1_AND descriptions.
10241116 data = data.slice (nhdr->getSize (sec.addralign ));
10251117 }
1118+ return GnuPropertiesInfo{f.andFeatures , f.aarch64PauthAbiCoreInfo };
10261119}
10271120
10281121template <class ELFT >
0 commit comments