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,52 @@ 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
+ } 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
+
540
587
template <class ELFT > void ObjFile<ELFT>::parse(bool ignoreComdats) {
541
588
object::ELFFile<ELFT> obj = this ->getObj ();
542
589
// Read a section table. justSymbols is usually false.
@@ -552,8 +599,31 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
552
599
StringRef shstrtab = CHECK2 (obj.getSectionStringTable (objSections), this );
553
600
uint64_t size = objSections.size ();
554
601
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
+
555
609
for (size_t i = 0 ; i != size; ++i) {
556
610
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
+
557
627
if (LLVM_LIKELY (sec.sh_type == SHT_PROGBITS))
558
628
continue ;
559
629
if (LLVM_LIKELY (sec.sh_type == SHT_GROUP)) {
@@ -637,13 +707,27 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
637
707
}
638
708
break ;
639
709
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
+ }
646
729
sections[i] = &InputSection::discarded;
730
+ }
647
731
// Producing a static binary with MTE globals is not currently supported,
648
732
// remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
649
733
// 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) {
655
739
}
656
740
}
657
741
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
+
658
750
// Read a symbol table.
659
751
initializeSymbols (obj);
660
752
}
@@ -974,8 +1066,8 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
974
1066
// hardware-assisted call flow control;
975
1067
// - AArch64 PAuth ABI core info (16 bytes).
976
1068
template <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) {
979
1071
using Elf_Nhdr = typename ELFT::Nhdr;
980
1072
using Elf_Note = typename ELFT::Note;
981
1073
@@ -992,7 +1084,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
992
1084
featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
993
1085
break ;
994
1086
default :
995
- return ;
1087
+ return GnuPropertiesInfo{} ;
996
1088
}
997
1089
998
1090
ArrayRef<uint8_t > data = sec.content ();
@@ -1007,7 +1099,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
1007
1099
auto *nhdr = reinterpret_cast <const Elf_Nhdr *>(data.data ());
1008
1100
if (data.size () < sizeof (Elf_Nhdr) ||
1009
1101
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{} );
1011
1103
1012
1104
Elf_Note note (*nhdr);
1013
1105
if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName () != " GNU" ) {
@@ -1023,6 +1115,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
1023
1115
// Go to next NOTE record to look for more FEATURE_1_AND descriptions.
1024
1116
data = data.slice (nhdr->getSize (sec.addralign ));
1025
1117
}
1118
+ return GnuPropertiesInfo{f.andFeatures , f.aarch64PauthAbiCoreInfo };
1026
1119
}
1027
1120
1028
1121
template <class ELFT >
0 commit comments