diff options
Diffstat (limited to 'lld/ELF/InputFiles.cpp')
-rw-r--r-- | lld/ELF/InputFiles.cpp | 41 |
1 files changed, 22 insertions, 19 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 6529ea072fae..1f496026d3ae 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -926,25 +926,18 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats, handleSectionGroup<ELFT>(this->sections, entries); } -// If a source file is compiled with x86 hardware-assisted call flow control -// enabled, the generated object file contains feature flags indicating that -// fact. This function reads the feature flags and returns it. -// -// Essentially we want to read a single 32-bit value in this function, but this -// function is rather complicated because the value is buried deep inside a -// .note.gnu.property section. -// -// The section consists of one or more NOTE records. Each NOTE record consists -// of zero or more type-length-value fields. We want to find a field of a -// certain type. It seems a bit too much to just store a 32-bit value, perhaps -// the ABI is unnecessarily complicated. -template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) { +// Read the following info from the .note.gnu.property section and write it to +// the corresponding fields in `ObjFile`: +// - Feature flags (32 bits) representing x86 or AArch64 features for +// hardware-assisted call flow control; +// - AArch64 PAuth ABI core info (16 bytes). +template <class ELFT> +void readGnuProperty(const InputSection &sec, ObjFile<ELFT> &f) { using Elf_Nhdr = typename ELFT::Nhdr; using Elf_Note = typename ELFT::Note; - uint32_t featuresSet = 0; ArrayRef<uint8_t> data = sec.content(); - auto reportFatal = [&](const uint8_t *place, const char *msg) { + auto reportFatal = [&](const uint8_t *place, const Twine &msg) { fatal(toString(sec.file) + ":(" + sec.name + "+0x" + Twine::utohexstr(place - sec.content().data()) + "): " + msg); }; @@ -983,7 +976,19 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) { // accumulate the bits set. if (size < 4) reportFatal(place, "FEATURE_1_AND entry is too short"); - featuresSet |= read32<ELFT::Endianness>(desc.data()); + f.andFeatures |= read32<ELFT::Endianness>(desc.data()); + } else if (config->emachine == EM_AARCH64 && + type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) { + if (!f.aarch64PauthAbiCoreInfo.empty()) { + reportFatal(data.data(), + "multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH entries are " + "not supported"); + } else if (size != 16) { + reportFatal(data.data(), "GNU_PROPERTY_AARCH64_FEATURE_PAUTH entry " + "is invalid: expected 16 bytes, but got " + + Twine(size)); + } + f.aarch64PauthAbiCoreInfo = desc; } // Padding is present in the note descriptor, if necessary. @@ -993,8 +998,6 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) { // Go to next NOTE record to look for more FEATURE_1_AND descriptions. data = data.slice(nhdr->getSize(sec.addralign)); } - - return featuresSet; } template <class ELFT> @@ -1051,7 +1054,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx, // .note.gnu.property containing a single AND'ed bitmap, we discard an input // file's .note.gnu.property section. if (name == ".note.gnu.property") { - this->andFeatures = readAndFeatures<ELFT>(InputSection(*this, sec, name)); + readGnuProperty<ELFT>(InputSection(*this, sec, name), *this); return &InputSection::discarded; } |