2222#include " llvm/ADT/STLExtras.h"
2323#include " llvm/LTO/LTO.h"
2424#include " llvm/Object/IRObjectFile.h"
25+ #include " llvm/Support/AArch64AttributeParser.h"
2526#include " llvm/Support/ARMAttributeParser.h"
2627#include " llvm/Support/ARMBuildAttributes.h"
2728#include " llvm/Support/Endian.h"
@@ -539,6 +540,43 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const {
539540 this );
540541}
541542
543+ template <class ELFT >
544+ static void
545+ handleAArch64BAAndGnuProperties (ObjFile<ELFT> *file, Ctx &ctx, bool hasGP,
546+ const AArch64BuildAttrSubsections &baInfo,
547+ const GnuPropertiesInfo &gpInfo) {
548+ if (hasGP) {
549+ // Check for data mismatch
550+ if (gpInfo.pauthAbiCoreInfo ) {
551+ if (baInfo.Pauth .TagPlatform != gpInfo.pauthAbiCoreInfo ->platform ||
552+ baInfo.Pauth .TagSchema != gpInfo.pauthAbiCoreInfo ->version )
553+ Err (ctx)
554+ << file
555+ << " Pauth Data mismatch: file contains both GNU properties and "
556+ " AArch64 build attributes sections with different Pauth data" ;
557+ }
558+ if (baInfo.AndFeatures != gpInfo.andFeatures )
559+ Err (ctx) << file
560+ << " Features Data mismatch: file contains both GNU "
561+ " properties and AArch64 build attributes sections with "
562+ " different And Features data" ;
563+ } else {
564+ // Write missing data
565+ // We can only know when Pauth is missing.
566+ // Unlike AArch64 Build Attributes, GNU properties does not give a way to
567+ // distinguish between no-value given to value of '0' given.
568+ if (baInfo.Pauth .TagPlatform || baInfo.Pauth .TagSchema ) {
569+ file->aarch64PauthAbiCoreInfo = {baInfo.Pauth .TagPlatform ,
570+ baInfo.Pauth .TagSchema };
571+ }
572+ file->andFeatures = baInfo.AndFeatures ;
573+ }
574+ }
575+
576+ template <typename ELFT>
577+ static GnuPropertiesInfo readGnuProperty (Ctx &, const InputSection &,
578+ ObjFile<ELFT> &);
579+
542580template <class ELFT > void ObjFile<ELFT>::parse(bool ignoreComdats) {
543581 object::ELFFile<ELFT> obj = this ->getObj ();
544582 // Read a section table. justSymbols is usually false.
@@ -554,8 +592,31 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
554592 StringRef shstrtab = CHECK2 (obj.getSectionStringTable (objSections), this );
555593 uint64_t size = objSections.size ();
556594 sections.resize (size);
595+
596+ // For handling AArch64 Build attributes and GNU properties
597+ AArch64BuildAttrSubsections aarch64BAsubSections;
598+ GnuPropertiesInfo gnuProperty;
599+ bool hasAArch64BuildAttributes = false ;
600+ bool hasGNUProperties = false ;
601+
557602 for (size_t i = 0 ; i != size; ++i) {
558603 const Elf_Shdr &sec = objSections[i];
604+ // Object files that use processor features such as Intel Control-Flow
605+ // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
606+ // .note.gnu.property section containing a bitfield of feature bits like the
607+ // GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
608+ if (check (obj.getSectionName (sec, shstrtab)) == " .note.gnu.property" ) {
609+ gnuProperty = readGnuProperty (
610+ ctx,
611+ InputSection (*this , sec, check (obj.getSectionName (sec, shstrtab))),
612+ *this );
613+ hasGNUProperties = true ;
614+ // Since we merge bitmaps from multiple object files to create a new
615+ // .note.gnu.property containing a single AND'ed bitmap, we discard an
616+ // input file's .note.gnu.property section.
617+ sections[i] = &InputSection::discarded;
618+ }
619+
559620 if (LLVM_LIKELY (sec.sh_type == SHT_PROGBITS))
560621 continue ;
561622 if (LLVM_LIKELY (sec.sh_type == SHT_GROUP)) {
@@ -639,13 +700,27 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
639700 }
640701 break ;
641702 case EM_AARCH64:
642- // FIXME: BuildAttributes have been implemented in llvm, but not yet in
643- // lld. Remove the section so that it does not accumulate in the output
644- // file. When support is implemented we expect not to output a build
645- // attributes section in files of type ET_EXEC or ET_SHARED, but ld -r
646- // ouptut will need a single merged attributes section.
647- if (sec.sh_type == SHT_AARCH64_ATTRIBUTES)
703+ // At this stage AArch64 Build Attributes does not replace GNU Properties.
704+ // When both exists, their values must match.
705+ // When both exists and contain different attributes, they complement each
706+ // other. Currently attributes are represented in the linked object file
707+ // as GNU properties, which are already supported by the Linux kernel and
708+ // the dynamic loader. In the future, when relocatable linking (`-r` flag)
709+ // is performed, a single merged AArch64 Build Attributes section will be
710+ // emitted.
711+ if (sec.sh_type == SHT_AARCH64_ATTRIBUTES) {
712+ ArrayRef<uint8_t > contents = check (obj.getSectionContents (sec));
713+ AArch64AttributeParser attributes;
714+ StringRef name = check (obj.getSectionName (sec, shstrtab));
715+ InputSection isec (*this , sec, name);
716+ if (Error e = attributes.parse (contents, ELFT::Endianness)) {
717+ Warn (ctx) << &isec << " : " << std::move (e);
718+ } else {
719+ aarch64BAsubSections = extractBuildAttributesSubsections (attributes);
720+ hasAArch64BuildAttributes = true ;
721+ }
648722 sections[i] = &InputSection::discarded;
723+ }
649724 // Producing a static binary with MTE globals is not currently supported,
650725 // remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
651726 // medatada, and we don't want them to end up in the output file for
@@ -657,6 +732,14 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
657732 }
658733 }
659734
735+ if (hasAArch64BuildAttributes) {
736+ // Handle AArch64 Build Attributes and GNU properties:
737+ // - Err on mismatched values.
738+ // - Store missing values as GNU properties.
739+ handleAArch64BAAndGnuProperties<ELFT>(this , ctx, hasGNUProperties,
740+ aarch64BAsubSections, gnuProperty);
741+ }
742+
660743 // Read a symbol table.
661744 initializeSymbols (obj);
662745}
@@ -976,8 +1059,8 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
9761059// hardware-assisted call flow control;
9771060// - AArch64 PAuth ABI core info (16 bytes).
9781061template <class ELFT >
979- static void readGnuProperty (Ctx &ctx, const InputSection &sec,
980- ObjFile<ELFT> &f) {
1062+ static GnuPropertiesInfo readGnuProperty (Ctx &ctx, const InputSection &sec,
1063+ ObjFile<ELFT> &f) {
9811064 using Elf_Nhdr = typename ELFT::Nhdr;
9821065 using Elf_Note = typename ELFT::Note;
9831066
@@ -993,7 +1076,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
9931076 auto *nhdr = reinterpret_cast <const Elf_Nhdr *>(data.data ());
9941077 if (data.size () < sizeof (Elf_Nhdr) ||
9951078 data.size () < nhdr->getSize (sec.addralign ))
996- return void (err (data.data ()) << " data is too short" );
1079+ return (err (data.data ()) << " data is too short" , GnuPropertiesInfo{} );
9971080
9981081 Elf_Note note (*nhdr);
9991082 if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName () != " GNU" ) {
@@ -1013,6 +1096,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
10131096 // Go to next NOTE record to look for more FEATURE_1_AND descriptions.
10141097 data = data.slice (nhdr->getSize (sec.addralign ));
10151098 }
1099+ return GnuPropertiesInfo{f.andFeatures , f.aarch64PauthAbiCoreInfo };
10161100}
10171101
10181102template <class ELFT >
0 commit comments