22
22
#include " llvm/ADT/STLExtras.h"
23
23
#include " llvm/LTO/LTO.h"
24
24
#include " llvm/Object/IRObjectFile.h"
25
+ #include " llvm/Support/AArch64AttributeParser.h"
25
26
#include " llvm/Support/ARMAttributeParser.h"
26
27
#include " llvm/Support/ARMBuildAttributes.h"
27
28
#include " llvm/Support/Endian.h"
@@ -539,6 +540,42 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const {
539
540
this );
540
541
}
541
542
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
+ Err (ctx)
553
+ << file
554
+ << " Pauth Data mismatch: file contains both GNU properties and "
555
+ " AArch64 build attributes sections with different Pauth data" ;
556
+ }
557
+ if (baInfo.AndFeatures != gpInfo.andFeatures )
558
+ Err (ctx) << file
559
+ << " Features Data mismatch: file contains both GNU "
560
+ " properties and AArch64 build attributes sections with "
561
+ " different And Features data" ;
562
+ } else {
563
+ // Write missing data
564
+ // We can only know when Pauth is missing.
565
+ // Unlike AArch64 Build Attributes, GNU properties does not give a way to
566
+ // distinguish between no-value given to value of '0' given.
567
+ if (baInfo.Pauth .TagPlatform || baInfo.Pauth .TagSchema ) {
568
+ file->aarch64PauthAbiCoreInfo = {baInfo.Pauth .TagPlatform ,
569
+ baInfo.Pauth .TagSchema };
570
+ }
571
+ file->andFeatures = baInfo.AndFeatures ;
572
+ }
573
+ }
574
+
575
+ template <typename ELFT>
576
+ static GnuPropertiesInfo readGnuProperty (Ctx &, const InputSection &,
577
+ ObjFile<ELFT> &);
578
+
542
579
template <class ELFT > void ObjFile<ELFT>::parse(bool ignoreComdats) {
543
580
object::ELFFile<ELFT> obj = this ->getObj ();
544
581
// Read a section table. justSymbols is usually false.
@@ -554,8 +591,31 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
554
591
StringRef shstrtab = CHECK2 (obj.getSectionStringTable (objSections), this );
555
592
uint64_t size = objSections.size ();
556
593
sections.resize (size);
594
+
595
+ // For handling AArch64 Build attributes and GNU properties
596
+ AArch64BuildAttrSubsections aarch64BAsubSections;
597
+ GnuPropertiesInfo gnuProperty;
598
+ bool hasAArch64BuildAttributes = false ;
599
+ bool hasGNUProperties = false ;
600
+
557
601
for (size_t i = 0 ; i != size; ++i) {
558
602
const Elf_Shdr &sec = objSections[i];
603
+ // Object files that use processor features such as Intel Control-Flow
604
+ // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
605
+ // .note.gnu.property section containing a bitfield of feature bits like the
606
+ // GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
607
+ if (check (obj.getSectionName (sec, shstrtab)) == " .note.gnu.property" ) {
608
+ gnuProperty = readGnuProperty (
609
+ ctx,
610
+ InputSection (*this , sec, check (obj.getSectionName (sec, shstrtab))),
611
+ *this );
612
+ hasGNUProperties = true ;
613
+ // Since we merge bitmaps from multiple object files to create a new
614
+ // .note.gnu.property containing a single AND'ed bitmap, we discard an
615
+ // input file's .note.gnu.property section.
616
+ sections[i] = &InputSection::discarded;
617
+ }
618
+
559
619
if (LLVM_LIKELY (sec.sh_type == SHT_PROGBITS))
560
620
continue ;
561
621
if (LLVM_LIKELY (sec.sh_type == SHT_GROUP)) {
@@ -639,13 +699,27 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
639
699
}
640
700
break ;
641
701
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)
702
+ // At this stage AArch64 Build Attributes does not replace GNU Properties.
703
+ // When both exists, their values must match.
704
+ // When both exists and contain different attributes, they complement each
705
+ // other. Currently attributes are represented in the linked object file
706
+ // as GNU properties, which are already supported by the Linux kernel and
707
+ // the dynamic loader. In the future, when relocatable linking (`-r` flag)
708
+ // is performed, a single merged AArch64 Build Attributes section will be
709
+ // emitted.
710
+ if (sec.sh_type == SHT_AARCH64_ATTRIBUTES) {
711
+ ArrayRef<uint8_t > contents = check (obj.getSectionContents (sec));
712
+ AArch64AttributeParser attributes;
713
+ StringRef name = check (obj.getSectionName (sec, shstrtab));
714
+ InputSection isec (*this , sec, name);
715
+ if (Error e = attributes.parse (contents, ELFT::Endianness)) {
716
+ Warn (ctx) << &isec << " : " << std::move (e);
717
+ } else {
718
+ aarch64BAsubSections = extractBuildAttributesSubsections (attributes);
719
+ hasAArch64BuildAttributes = true ;
720
+ }
648
721
sections[i] = &InputSection::discarded;
722
+ }
649
723
// Producing a static binary with MTE globals is not currently supported,
650
724
// remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
651
725
// medatada, and we don't want them to end up in the output file for
@@ -657,6 +731,14 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
657
731
}
658
732
}
659
733
734
+ if (hasAArch64BuildAttributes) {
735
+ // Handle AArch64 Build Attributes and GNU properties:
736
+ // - Err on mismatched values.
737
+ // - Store missing values as GNU properties.
738
+ handleAArch64BAAndGnuProperties<ELFT>(this , ctx, hasGNUProperties,
739
+ aarch64BAsubSections, gnuProperty);
740
+ }
741
+
660
742
// Read a symbol table.
661
743
initializeSymbols (obj);
662
744
}
@@ -976,8 +1058,8 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
976
1058
// hardware-assisted call flow control;
977
1059
// - AArch64 PAuth ABI core info (16 bytes).
978
1060
template <class ELFT >
979
- static void readGnuProperty (Ctx &ctx, const InputSection &sec,
980
- ObjFile<ELFT> &f) {
1061
+ static GnuPropertiesInfo readGnuProperty (Ctx &ctx, const InputSection &sec,
1062
+ ObjFile<ELFT> &f) {
981
1063
using Elf_Nhdr = typename ELFT::Nhdr;
982
1064
using Elf_Note = typename ELFT::Note;
983
1065
@@ -993,7 +1075,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
993
1075
auto *nhdr = reinterpret_cast <const Elf_Nhdr *>(data.data ());
994
1076
if (data.size () < sizeof (Elf_Nhdr) ||
995
1077
data.size () < nhdr->getSize (sec.addralign ))
996
- return void (err (data.data ()) << " data is too short" );
1078
+ return (err (data.data ()) << " data is too short" , GnuPropertiesInfo{} );
997
1079
998
1080
Elf_Note note (*nhdr);
999
1081
if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName () != " GNU" ) {
@@ -1013,6 +1095,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
1013
1095
// Go to next NOTE record to look for more FEATURE_1_AND descriptions.
1014
1096
data = data.slice (nhdr->getSize (sec.addralign ));
1015
1097
}
1098
+ return GnuPropertiesInfo{f.andFeatures , f.aarch64PauthAbiCoreInfo };
1016
1099
}
1017
1100
1018
1101
template <class ELFT >
0 commit comments