@@ -1030,6 +1030,103 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
10301030 handleSectionGroup<ELFT>(this ->sections , entries);
10311031}
10321032
1033+ template <typename ELFT>
1034+ static void parseGnuPropertyNote (Ctx &ctx, ELFFileBase &f,
1035+ uint32_t featureAndType,
1036+ ArrayRef<uint8_t > &desc, const uint8_t *base,
1037+ ArrayRef<uint8_t > *data) {
1038+ auto err = [&](const uint8_t *place) -> ELFSyncStream {
1039+ auto diag = Err (ctx);
1040+ diag << &f << " :(" << " .note.gnu.property+0x"
1041+ << Twine::utohexstr (place - base) << " ): " ;
1042+ return diag;
1043+ };
1044+
1045+ while (!desc.empty ()) {
1046+ const uint8_t *place = desc.data ();
1047+ if (desc.size () < 8 )
1048+ return void (err (place) << " program property is too short" );
1049+ uint32_t type = read32<ELFT::Endianness>(desc.data ());
1050+ uint32_t size = read32<ELFT::Endianness>(desc.data () + 4 );
1051+ desc = desc.slice (8 );
1052+ if (desc.size () < size)
1053+ return void (err (place) << " program property is too short" );
1054+
1055+ if (type == featureAndType) {
1056+ // We found a FEATURE_1_AND field. There may be more than one of these
1057+ // in a .note.gnu.property section, for a relocatable object we
1058+ // accumulate the bits set.
1059+ if (size < 4 )
1060+ return void (err (place) << " FEATURE_1_AND entry is too short" );
1061+ f.andFeatures |= read32<ELFT::Endianness>(desc.data ());
1062+ } else if (ctx.arg .emachine == EM_AARCH64 &&
1063+ type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
1064+ ArrayRef<uint8_t > contents = data ? *data : desc;
1065+ if (!f.aarch64PauthAbiCoreInfo .empty ()) {
1066+ return void (
1067+ err (contents.data ())
1068+ << " multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH entries are "
1069+ " not supported" );
1070+ } else if (size != 16 ) {
1071+ return void (err (contents.data ())
1072+ << " GNU_PROPERTY_AARCH64_FEATURE_PAUTH entry "
1073+ " is invalid: expected 16 bytes, but got "
1074+ << size);
1075+ }
1076+ f.aarch64PauthAbiCoreInfo = desc;
1077+ }
1078+
1079+ // Padding is present in the note descriptor, if necessary.
1080+ desc = desc.slice (alignTo<(ELFT::Is64Bits ? 8 : 4 )>(size));
1081+ }
1082+ }
1083+
1084+ // Read the following info from the .note.gnu.property section and write it to
1085+ // the corresponding fields in `ObjFile`:
1086+ // - Feature flags (32 bits) representing x86 or AArch64 features for
1087+ // hardware-assisted call flow control;
1088+ // - AArch64 PAuth ABI core info (16 bytes).
1089+ template <class ELFT >
1090+ static gnuPropertiesInfo readGnuProperty (Ctx &ctx, const InputSection &sec,
1091+ ObjFile<ELFT> &f) {
1092+ using Elf_Nhdr = typename ELFT::Nhdr;
1093+ using Elf_Note = typename ELFT::Note;
1094+
1095+ ArrayRef<uint8_t > data = sec.content ();
1096+ auto err = [&](const uint8_t *place) -> ELFSyncStream {
1097+ auto diag = Err (ctx);
1098+ diag << sec.file << " :(" << sec.name << " +0x"
1099+ << Twine::utohexstr (place - sec.content ().data ()) << " ): " ;
1100+ return diag;
1101+ };
1102+ while (!data.empty ()) {
1103+ // Read one NOTE record.
1104+ auto *nhdr = reinterpret_cast <const Elf_Nhdr *>(data.data ());
1105+ if (data.size () < sizeof (Elf_Nhdr) ||
1106+ data.size () < nhdr->getSize (sec.addralign ))
1107+ return (err (data.data ()) << " data is too short" , gnuPropertiesInfo{});
1108+
1109+ Elf_Note note (*nhdr);
1110+ if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName () != " GNU" ) {
1111+ data = data.slice (nhdr->getSize (sec.addralign ));
1112+ continue ;
1113+ }
1114+
1115+ uint32_t featureAndType = ctx.arg .emachine == EM_AARCH64
1116+ ? GNU_PROPERTY_AARCH64_FEATURE_1_AND
1117+ : GNU_PROPERTY_X86_FEATURE_1_AND;
1118+
1119+ // Read a body of a NOTE record, which consists of type-length-value fields.
1120+ ArrayRef<uint8_t > desc = note.getDesc (sec.addralign );
1121+ const uint8_t *base = sec.content ().data ();
1122+ parseGnuPropertyNote<ELFT>(ctx, f, featureAndType, desc, base, &data);
1123+
1124+ // Go to next NOTE record to look for more FEATURE_1_AND descriptions.
1125+ data = data.slice (nhdr->getSize (sec.addralign ));
1126+ }
1127+ return gnuPropertiesInfo{f.andFeatures , f.aarch64PauthAbiCoreInfo };
1128+ }
1129+
10331130template <class ELFT >
10341131InputSectionBase *ObjFile<ELFT>::getRelocTarget(uint32_t idx, uint32_t info) {
10351132 if (info < this ->sections .size ()) {
@@ -1438,103 +1535,6 @@ std::vector<uint32_t> SharedFile::parseVerneed(const ELFFile<ELFT> &obj,
14381535 return verneeds;
14391536}
14401537
1441- template <typename ELFT>
1442- static void parseGnuPropertyNote (Ctx &ctx, ELFFileBase &f,
1443- uint32_t featureAndType,
1444- ArrayRef<uint8_t > &desc, const uint8_t *base,
1445- ArrayRef<uint8_t > *data) {
1446- auto err = [&](const uint8_t *place) -> ELFSyncStream {
1447- auto diag = Err (ctx);
1448- diag << &f << " :(" << " .note.gnu.property+0x"
1449- << Twine::utohexstr (place - base) << " ): " ;
1450- return diag;
1451- };
1452-
1453- while (!desc.empty ()) {
1454- const uint8_t *place = desc.data ();
1455- if (desc.size () < 8 )
1456- return void (err (place) << " program property is too short" );
1457- uint32_t type = read32<ELFT::Endianness>(desc.data ());
1458- uint32_t size = read32<ELFT::Endianness>(desc.data () + 4 );
1459- desc = desc.slice (8 );
1460- if (desc.size () < size)
1461- return void (err (place) << " program property is too short" );
1462-
1463- if (type == featureAndType) {
1464- // We found a FEATURE_1_AND field. There may be more than one of these
1465- // in a .note.gnu.property section, for a relocatable object we
1466- // accumulate the bits set.
1467- if (size < 4 )
1468- return void (err (place) << " FEATURE_1_AND entry is too short" );
1469- f.andFeatures |= read32<ELFT::Endianness>(desc.data ());
1470- } else if (ctx.arg .emachine == EM_AARCH64 &&
1471- type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
1472- ArrayRef<uint8_t > contents = data ? *data : desc;
1473- if (!f.aarch64PauthAbiCoreInfo .empty ()) {
1474- return void (
1475- err (contents.data ())
1476- << " multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH entries are "
1477- " not supported" );
1478- } else if (size != 16 ) {
1479- return void (err (contents.data ())
1480- << " GNU_PROPERTY_AARCH64_FEATURE_PAUTH entry "
1481- " is invalid: expected 16 bytes, but got "
1482- << size);
1483- }
1484- f.aarch64PauthAbiCoreInfo = desc;
1485- }
1486-
1487- // Padding is present in the note descriptor, if necessary.
1488- desc = desc.slice (alignTo<(ELFT::Is64Bits ? 8 : 4 )>(size));
1489- }
1490- }
1491-
1492- // Read the following info from the .note.gnu.property section and write it to
1493- // the corresponding fields in `ObjFile`:
1494- // - Feature flags (32 bits) representing x86 or AArch64 features for
1495- // hardware-assisted call flow control;
1496- // - AArch64 PAuth ABI core info (16 bytes).
1497- template <class ELFT >
1498- static gnuPropertiesInfo readGnuProperty (Ctx &ctx, const InputSection &sec,
1499- ObjFile<ELFT> &f) {
1500- using Elf_Nhdr = typename ELFT::Nhdr;
1501- using Elf_Note = typename ELFT::Note;
1502-
1503- ArrayRef<uint8_t > data = sec.content ();
1504- auto err = [&](const uint8_t *place) -> ELFSyncStream {
1505- auto diag = Err (ctx);
1506- diag << sec.file << " :(" << sec.name << " +0x"
1507- << Twine::utohexstr (place - sec.content ().data ()) << " ): " ;
1508- return diag;
1509- };
1510- while (!data.empty ()) {
1511- // Read one NOTE record.
1512- auto *nhdr = reinterpret_cast <const Elf_Nhdr *>(data.data ());
1513- if (data.size () < sizeof (Elf_Nhdr) ||
1514- data.size () < nhdr->getSize (sec.addralign ))
1515- return (err (data.data ()) << " data is too short" , gnuPropertiesInfo{});
1516-
1517- Elf_Note note (*nhdr);
1518- if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName () != " GNU" ) {
1519- data = data.slice (nhdr->getSize (sec.addralign ));
1520- continue ;
1521- }
1522-
1523- uint32_t featureAndType = ctx.arg .emachine == EM_AARCH64
1524- ? GNU_PROPERTY_AARCH64_FEATURE_1_AND
1525- : GNU_PROPERTY_X86_FEATURE_1_AND;
1526-
1527- // Read a body of a NOTE record, which consists of type-length-value fields.
1528- ArrayRef<uint8_t > desc = note.getDesc (sec.addralign );
1529- const uint8_t *base = sec.content ().data ();
1530- parseGnuPropertyNote<ELFT>(ctx, f, featureAndType, desc, base, &data);
1531-
1532- // Go to next NOTE record to look for more FEATURE_1_AND descriptions.
1533- data = data.slice (nhdr->getSize (sec.addralign ));
1534- }
1535- return gnuPropertiesInfo{f.andFeatures , f.aarch64PauthAbiCoreInfo };
1536- }
1537-
15381538// Parse PT_GNU_PROPERTY segments in DSO. The process is similar to
15391539// readGnuProperty, but we don't have the InputSection information.
15401540template <typename ELFT>
0 commit comments