@@ -682,6 +682,89 @@ static gnuPropertiesInfo readGnuProperty(Ctx &ctx, const InputSection &sec,
682682 return gnuPropertiesInfo{f.andFeatures , f.aarch64PauthAbiCoreInfo };
683683}
684684
685+ template <class ELFT >
686+ static void
687+ handleAArch64BAAndGnuProperties (const ELFT &tPointer, Ctx &ctx, bool isBE,
688+ bool hasBA, bool hasGP,
689+ const AArch64BuildAttrSubsections &baInfo,
690+ const gnuPropertiesInfo &gpInfo) {
691+ if (hasBA && hasGP) {
692+ if (!gpInfo.aarch64PauthAbiCoreInfo .empty ()) {
693+ // check for a mismatch
694+ auto deserializeArray = [&](size_t offset, bool isBE) {
695+ unsigned value = 0 ;
696+ for (size_t i = 0 ; i < 8 ; ++i) {
697+ if (isBE)
698+ value = (value << 8 ) | gpInfo.aarch64PauthAbiCoreInfo [i + offset];
699+ else
700+ value |= static_cast <uint64_t >(
701+ gpInfo.aarch64PauthAbiCoreInfo [i + offset])
702+ << (8 * i);
703+ };
704+ return value;
705+ };
706+ unsigned gnuPropPauthPlatform = deserializeArray (0 , isBE);
707+ if (baInfo.pauth .tagPlatform != gnuPropPauthPlatform)
708+ ErrAlways (ctx)
709+ << tPointer
710+ << " Pauth Platform mismatch: file contains both GNU properties and "
711+ " AArch64 build attributes sections\n GNU properties: "
712+ << gnuPropPauthPlatform
713+ << " \n AArch64 build attributes: " << baInfo.pauth .tagPlatform ;
714+ unsigned gnuPropPauthScheme = deserializeArray (8 , isBE);
715+ if (baInfo.pauth .tagSchema != gnuPropPauthScheme)
716+ ErrAlways (ctx)
717+ << tPointer
718+ << " Pauth Schema mismatch: file contains both GNU properties and "
719+ " AArch64 build attributes sections\n GNU properties: "
720+ << gnuPropPauthScheme
721+ << " \n AArch64 build attributes: " << baInfo.pauth .tagSchema ;
722+ }
723+ if (baInfo.fAndB .tagBTI != (gpInfo.andFeatures & 0x01 ))
724+ ErrAlways (ctx)
725+ << tPointer
726+ << " Features BTI mismatch: file contains both GNU properties and "
727+ " AArch64 build attributes sections\n GNU properties: "
728+ << (gpInfo.andFeatures & 0x01 )
729+ << " \n AArch64 build attributes: " << baInfo.fAndB .tagBTI ;
730+ if (baInfo.fAndB .tagPAC != ((gpInfo.andFeatures >> 1 ) & 0x01 ))
731+ ErrAlways (ctx)
732+ << tPointer
733+ << " Feature PAC mismatch: file contains both GNU properties and "
734+ " AArch64 build attributes sections\n GNU properties: "
735+ << ((gpInfo.andFeatures >> 1 ) & 0x01 )
736+ << " \n AArch64 build attributes: " << baInfo.fAndB .tagPAC ;
737+ if (baInfo.fAndB .tagGCS != ((gpInfo.andFeatures >> 2 ) & 0x01 ))
738+ ErrAlways (ctx)
739+ << tPointer
740+ << " Feature GCS mismatch: file contains both GNU properties and "
741+ " AArch64 build attributes sections\n GNU properties: "
742+ << ((gpInfo.andFeatures >> 2 ) & 0x01 )
743+ << " \n AArch64 build attributes: " << baInfo.fAndB .tagGCS ;
744+ }
745+
746+ if (hasBA && !hasGP) {
747+ if (baInfo.pauth .tagPlatform || baInfo.pauth .tagSchema ) {
748+ auto serializeUnsigned = [&](unsigned value, size_t offset, bool isBE) {
749+ for (size_t i = 0 ; i < 8 ; ++i) {
750+ tPointer->aarch64PauthAbiCoreInfoStorage [i + offset] =
751+ static_cast <uint8_t >(
752+ (static_cast <uint64_t >(value) >> (8 * (isBE ? (7 - i) : i))) &
753+ 0xFF );
754+ };
755+ };
756+ serializeUnsigned (baInfo.pauth .tagPlatform , 0 , isBE);
757+ serializeUnsigned (baInfo.pauth .tagSchema , 8 , isBE);
758+ tPointer->aarch64PauthAbiCoreInfo =
759+ tPointer->aarch64PauthAbiCoreInfoStorage ;
760+ }
761+ tPointer->andFeatures = 0 ;
762+ tPointer->andFeatures |= (baInfo.fAndB .tagBTI ) << 0 ;
763+ tPointer->andFeatures |= (baInfo.fAndB .tagPAC ) << 1 ;
764+ tPointer->andFeatures |= (baInfo.fAndB .tagGCS ) << 2 ;
765+ }
766+ }
767+
685768template <class ELFT > void ObjFile<ELFT>::parse(bool ignoreComdats) {
686769 object::ELFFile<ELFT> obj = this ->getObj ();
687770 // Read a section table. justSymbols is usually false.
@@ -690,21 +773,27 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
690773 initializeSymbols (obj);
691774 return ;
692775 }
693-
694776 // Handle dependent libraries and selection of section groups as these are not
695777 // done in parallel.
696778 ArrayRef<Elf_Shdr> objSections = getELFShdrs<ELFT>();
697779 StringRef shstrtab = CHECK2 (obj.getSectionStringTable (objSections), this );
698780 uint64_t size = objSections.size ();
699781 sections.resize (size);
700782
701- // Check whether GNU properties section present and store it's data.
702- // This is done in order to compare the content of GNU properties section with
703- // aarch64 build attributes section.
704- bool hasGnuProperties = false ;
783+ // For handling AArch64 Build attributes and GNU properties
784+ AArch64BuildAttrSubsections aarch64BAsubSections;
705785 gnuPropertiesInfo gnuPropertiesInformation;
786+ bool hasAArch64BuildAttributes = false ;
787+ bool hasGNUProperties = false ;
788+
706789 for (size_t i = 0 ; i != size; ++i) {
707790 const Elf_Shdr &sec = objSections[i];
791+
792+ // Collect GNU properties data.
793+ // GNU properties might be processed in this loop, or only later on (e.g. in
794+ // initializeSections) Therefore there is no guarantee that the GNU
795+ // properties data will be read after this loop end, so it is being
796+ // collected here.
708797 if (check (obj.getSectionName (sec, shstrtab)) == " .note.gnu.property" ) {
709798 if (0 == this ->andFeatures && this ->aarch64PauthAbiCoreInfo .empty ()) {
710799 gnuPropertiesInformation = readGnuProperty (
@@ -719,13 +808,9 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
719808 gnuPropertiesInformation.aarch64PauthAbiCoreInfo =
720809 this ->aarch64PauthAbiCoreInfo ;
721810 }
722- hasGnuProperties = true ;
723- break ;
811+ hasGNUProperties = true ;
724812 }
725- }
726813
727- for (size_t i = 0 ; i != size; ++i) {
728- const Elf_Shdr &sec = objSections[i];
729814 if (LLVM_LIKELY (sec.sh_type == SHT_PROGBITS))
730815 continue ;
731816 if (LLVM_LIKELY (sec.sh_type == SHT_GROUP)) {
@@ -809,130 +894,27 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
809894 }
810895 break ;
811896 case EM_AARCH64: {
812- // The specification states that if a file contains both GNU properties
813- // and AArch64 build attributes, they can be assumed to be identical.
814- // Therefore, if a file contains GNU properties, the AArch64 build
815- // attributes are ignored. If a file does not contain GNU properties, we
816- // leverage the existing GNU properties mechanism by populating the
817- // corresponding data structures, which will later be handled by
818- // Driver.cpp::readSecurityNotes. This ensures that AArch64 build
819- // attributes are represented in the linked object file as GNU properties,
820- // which are already supported by the Linux kernel and the dynamic
821- // loader.
897+ // At this stage AArch64 Build Attributes does not replace GNU Properties.
898+ // When both exists, their values must match.
899+ // When both exists and contain different attributes, they complement each
900+ // other. Curently attributes are represented in the linked object file as
901+ // GNU properties, which are already supported by the Linux kernel and the
902+ // dynamic loader. In the future, when relocatable linking (`-r` flag) is
903+ // performed, a single merged AArch64 Build Attributes section will be
904+ // emitted.
905+
822906 if (sec.sh_type == SHT_AARCH64_ATTRIBUTES) {
823- StringRef name = check (obj.getSectionName (sec, shstrtab));
824907 ArrayRef<uint8_t > contents = check (obj.getSectionContents (sec));
825908 AArch64AttributeParser attributes;
826- // For functions that has to warn/err/report.
909+ StringRef name = check (obj. getSectionName (sec, shstrtab));
827910 InputSection isec (*this , sec, name);
828911 if (Error e = attributes.parse (contents, ELFT::Endianness)) {
829912 Warn (ctx) << &isec << " : " << std::move (e);
830913 // uint32_t andFeatures = 0;
831914 // std::array<uint8_t, 16> aarch64PauthAbiCoreInfoStorage;
832915 } else {
833- bool writePauth = false ;
834- bool wrtieFeatures = false ;
835- AArch64BuildAttrSubsections subSections =
836- extractBuildAttributesSubsections (attributes);
837- if (hasGnuProperties) {
838- if (!gnuPropertiesInformation.aarch64PauthAbiCoreInfo .empty ()) {
839- // check for mismatch error
840- auto deserializeArray = [&](size_t offset, bool isBE) {
841- unsigned value = 0 ;
842- for (size_t i = 0 ; i < 8 ; ++i) {
843- value = isBE ? (value << 8 ) |
844- gnuPropertiesInformation
845- .aarch64PauthAbiCoreInfo [i + offset]
846- : value |=
847- static_cast <uint64_t >(
848- gnuPropertiesInformation
849- .aarch64PauthAbiCoreInfo [i + offset])
850- << (8 * i);
851- };
852- return value;
853- };
854- unsigned gnuPropPauthPlatform = deserializeArray (
855- 0 , ELFT::Endianness == llvm::endianness::big);
856- if (subSections.pauth .tagPlatform != gnuPropPauthPlatform)
857- ErrAlways (ctx)
858- << &isec
859- << " Pauth Platform mismatch: file contains both GNU "
860- " properties and AArch64 build attributes sections\n GNU "
861- " properties: "
862- << gnuPropPauthPlatform << " \n AArch64 build attributes: "
863- << subSections.pauth .tagPlatform ;
864- unsigned gnuPropPauthScheme = deserializeArray (
865- 8 , ELFT::Endianness == llvm::endianness::big);
866- if (subSections.pauth .tagSchema != gnuPropPauthScheme)
867- ErrAlways (ctx)
868- << &isec
869- << " Pauth Schema mismatch: file contains both GNU "
870- " properties and AArch64 build attributes sections\n GNU "
871- " properties: "
872- << gnuPropPauthScheme << " \n AArch64 build attributes: "
873- << subSections.pauth .tagSchema ;
874- } else {
875- writePauth = true ;
876- }
877- if (subSections.fAndB .tagBTI !=
878- (gnuPropertiesInformation.andFeatures & 0x01 ))
879- ErrAlways (ctx)
880- << &isec
881- << " Features BTI mismatch: file contains both GNU "
882- " properties and AArch64 build attributes sections\n GNU "
883- " properties: "
884- << (gnuPropertiesInformation.andFeatures & 0x01 )
885- << " \n AArch64 build attributes: " << subSections.fAndB .tagBTI ;
886- if (subSections.fAndB .tagPAC !=
887- ((gnuPropertiesInformation.andFeatures >> 1 ) & 0x01 ))
888- ErrAlways (ctx)
889- << &isec
890- << " Feature PAC mismatch: file contains both GNU "
891- " properties and AArch64 build attributes sections\n GNU "
892- " properties: "
893- << ((gnuPropertiesInformation.andFeatures >> 1 ) & 0x01 )
894- << " \n AArch64 build attributes: " << subSections.fAndB .tagBTI ;
895- if (subSections.fAndB .tagGCS !=
896- ((gnuPropertiesInformation.andFeatures >> 2 ) & 0x01 ))
897- ErrAlways (ctx)
898- << &isec
899- << " Feature GCS mismatch: file contains both GNU "
900- " properties and AArch64 build attributes sections\n GNU "
901- " properties: "
902- << ((gnuPropertiesInformation.andFeatures >> 2 ) & 0x01 )
903- << " \n AArch64 build attributes: " << subSections.fAndB .tagBTI ;
904- } else {
905- // no GNU properties
906- writePauth = true ;
907- wrtieFeatures = true ;
908- }
909- if (writePauth) {
910- // this condition is important in order not to emit section when
911- // data does not exists, same as GNU properties.
912- if (subSections.pauth .tagPlatform || subSections.pauth .tagSchema ) {
913- auto serializeUnsigned = [&](unsigned value, size_t offset,
914- bool isBE) {
915- for (size_t i = 0 ; i < 8 ; ++i) {
916- this ->aarch64PauthAbiCoreInfoStorage [i + offset] =
917- static_cast <uint8_t >((static_cast <uint64_t >(value) >>
918- (8 * (isBE ? (7 - i) : i))) &
919- 0xFF );
920- };
921- };
922- serializeUnsigned (subSections.pauth .tagPlatform , 0 ,
923- ELFT::Endianness == llvm::endianness::big);
924- serializeUnsigned (subSections.pauth .tagSchema , 8 ,
925- ELFT::Endianness == llvm::endianness::big);
926- this ->aarch64PauthAbiCoreInfo =
927- this ->aarch64PauthAbiCoreInfoStorage ;
928- }
929- }
930- if (wrtieFeatures) {
931- this ->andFeatures = 0 ;
932- this ->andFeatures |= (subSections.fAndB .tagBTI ) << 0 ;
933- this ->andFeatures |= (subSections.fAndB .tagPAC ) << 1 ;
934- this ->andFeatures |= (subSections.fAndB .tagGCS ) << 2 ;
935- }
916+ aarch64BAsubSections = extractBuildAttributesSubsections (attributes);
917+ hasAArch64BuildAttributes = true ;
936918 }
937919 sections[i] = &InputSection::discarded;
938920 }
@@ -946,6 +928,15 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
946928 } break ;
947929 }
948930 }
931+
932+ bool isBE = ELFT::Endianness == llvm::endianness::big;
933+ // Handle AArch64 Build Attributes and GNU properties:
934+ // - Err on mismatched values.
935+ // - Store missing values as GNU properties.
936+ handleAArch64BAAndGnuProperties (this , ctx, isBE, hasAArch64BuildAttributes,
937+ hasGNUProperties, aarch64BAsubSections,
938+ gnuPropertiesInformation);
939+
949940 // Read a symbol table.
950941 initializeSymbols (obj);
951942}
@@ -1947,7 +1938,7 @@ BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName,
19471938
19481939 // ThinLTO assumes that all MemoryBufferRefs given to it have a unique
19491940 // name. If two archives define two members with the same name, this
1950- // causes a collision which result in only one of the objects being taken
1941+ // causes a mismatch which result in only one of the objects being taken
19511942 // into consideration at LTO time (which very likely causes undefined
19521943 // symbols later in the link stage). So we append file offset to make
19531944 // filename unique.
0 commit comments