Skip to content

Commit f39ea06

Browse files
committed
Support GNU_PROPERTY_AARCH64_FEATURE_PAUTH
1 parent 908da16 commit f39ea06

File tree

19 files changed

+291
-65
lines changed

19 files changed

+291
-65
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,20 @@ void CodeGenModule::Release() {
10751075
if (!LangOpts.isSignReturnAddressWithAKey())
10761076
getModule().addModuleFlag(llvm::Module::Min,
10771077
"sign-return-address-with-bkey", 1);
1078+
1079+
if (getTriple().isOSBinFormatELF()) {
1080+
uint64_t PAuthABIVersion =
1081+
(LangOpts.PointerAuthCalls << 0) |
1082+
(LangOpts.PointerAuthReturns << 1) |
1083+
(LangOpts.PointerAuthVTPtrAddressDiscrimination << 2) |
1084+
(LangOpts.PointerAuthVTPtrTypeDiscrimination << 3) |
1085+
(LangOpts.PointerAuthInitFini << 4);
1086+
if (PAuthABIVersion != 0) {
1087+
getModule().addModuleFlag(llvm::Module::Error, "pauthabi-platform", 2);
1088+
getModule().addModuleFlag(llvm::Module::Error, "pauthabi-version",
1089+
PAuthABIVersion);
1090+
}
1091+
}
10781092
}
10791093

10801094
if (!CodeGenOpts.MemoryProfileOutput.empty()) {

lld/ELF/Config.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "llvm/Support/FileSystem.h"
2828
#include "llvm/Support/GlobPattern.h"
2929
#include "llvm/Support/PrettyStackTrace.h"
30+
#include <array>
3031
#include <atomic>
3132
#include <memory>
3233
#include <optional>
@@ -492,7 +493,7 @@ struct Ctx {
492493

493494
llvm::raw_fd_ostream openAuxiliaryFile(llvm::StringRef, std::error_code &);
494495

495-
SmallVector<uint8_t, 0> aarch64PauthAbiTag;
496+
std::optional<std::array<uint8_t, 16>> aarch64PauthAbiTag;
496497
};
497498

498499
LLVM_LIBRARY_VISIBILITY extern Ctx ctx;

lld/ELF/Driver.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2662,17 +2662,17 @@ static void getAarch64PauthInfo() {
26622662

26632663
auto NonEmptyIt = std::find_if(
26642664
ctx.objectFiles.begin(), ctx.objectFiles.end(),
2665-
[](const ELFFileBase *f) { return !f->aarch64PauthAbiTag.empty(); });
2665+
[](const ELFFileBase *f) { return f->aarch64PauthAbiTag.has_value(); });
26662666
if (NonEmptyIt == ctx.objectFiles.end())
26672667
return;
26682668

26692669
ctx.aarch64PauthAbiTag = (*NonEmptyIt)->aarch64PauthAbiTag;
26702670
StringRef F1 = (*NonEmptyIt)->getName();
26712671
for (ELFFileBase *F : ArrayRef(ctx.objectFiles)) {
26722672
StringRef F2 = F->getName();
2673-
const SmallVector<uint8_t, 0> &D1 = ctx.aarch64PauthAbiTag;
2674-
const SmallVector<uint8_t, 0> &D2 = F->aarch64PauthAbiTag;
2675-
if (D1.empty() != D2.empty()) {
2673+
std::optional<std::array<uint8_t, 16>> D1 = ctx.aarch64PauthAbiTag;
2674+
std::optional<std::array<uint8_t, 16>> D2 = F->aarch64PauthAbiTag;
2675+
if (D1.has_value() != D2.has_value()) {
26762676
auto Helper = [](StringRef Report, const Twine &Msg) {
26772677
if (Report == "warning")
26782678
warn(Msg);
@@ -2681,19 +2681,19 @@ static void getAarch64PauthInfo() {
26812681
};
26822682

26832683
Helper(config->zPauthReport,
2684-
(D1.empty() ? F1.str() : F2.str()) +
2684+
(D1.has_value() ? F2.str() : F1.str()) +
26852685
" has no AArch64 PAuth compatibility info while " +
2686-
(D1.empty() ? F2.str() : F1.str()) +
2686+
(D1.has_value() ? F1.str() : F2.str()) +
26872687
" has one; either all or no input files must have it");
26882688
}
26892689

2690-
if (!D1.empty() && !D2.empty() &&
2691-
!std::equal(D1.begin(), D1.end(), D2.begin(), D2.end()))
2690+
if (!D1.has_value() && !D2.has_value() &&
2691+
!std::equal(D1->begin(), D1->end(), D2->begin(), D2->end()))
26922692
errorOrWarn(
26932693
"incompatible values of AArch64 PAuth compatibility info found"
26942694
"\n" +
2695-
F1 + ": 0x" + toHex(ArrayRef(D1.data(), D1.size())) + "\n" + F2 +
2696-
": 0x" + toHex(ArrayRef(D2.data(), D2.size())));
2695+
F1 + ": 0x" + toHex(ArrayRef(D1->data(), D1->size())) + "\n" + F2 +
2696+
": 0x" + toHex(ArrayRef(D2->data(), D2->size())));
26972697
}
26982698
}
26992699

lld/ELF/InputFiles.cpp

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "llvm/Support/TarWriter.h"
3232
#include "llvm/Support/raw_ostream.h"
3333

34+
#include <tuple>
35+
3436
using namespace llvm;
3537
using namespace llvm::ELF;
3638
using namespace llvm::object;
@@ -878,11 +880,14 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
878880
// of zero or more type-length-value fields. We want to find a field of a
879881
// certain type. It seems a bit too much to just store a 32-bit value, perhaps
880882
// the ABI is unnecessarily complicated.
881-
template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
883+
template <class ELFT>
884+
static std::pair<uint32_t, std::optional<std::array<uint8_t, 16>>>
885+
readGnuProperty(const InputSection &sec) {
882886
using Elf_Nhdr = typename ELFT::Nhdr;
883887
using Elf_Note = typename ELFT::Note;
884888

885889
uint32_t featuresSet = 0;
890+
std::optional<std::array<uint8_t, 16>> aarch64PauthAbiTag;
886891
ArrayRef<uint8_t> data = sec.content();
887892
auto reportFatal = [&](const uint8_t *place, const char *msg) {
888893
fatal(toString(sec.file) + ":(" + sec.name + "+0x" +
@@ -924,6 +929,19 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
924929
if (size < 4)
925930
reportFatal(place, "FEATURE_1_AND entry is too short");
926931
featuresSet |= read32<ELFT::TargetEndianness>(desc.data());
932+
} else if (config->emachine == EM_AARCH64 &&
933+
type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
934+
if (aarch64PauthAbiTag != std::nullopt)
935+
reportFatal(data.data(),
936+
"multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH properties "
937+
"are not allowed");
938+
if (size != 16)
939+
reportFatal(
940+
data.data(),
941+
"size of GNU_PROPERTY_AARCH64_FEATURE_PAUTH property must be 16");
942+
aarch64PauthAbiTag = std::array<uint8_t, 16>{};
943+
memcpy(aarch64PauthAbiTag->data(), desc.data(),
944+
aarch64PauthAbiTag->size());
927945
}
928946

929947
// Padding is present in the note descriptor, if necessary.
@@ -934,7 +952,7 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
934952
data = data.slice(nhdr->getSize(sec.addralign));
935953
}
936954

937-
return featuresSet;
955+
return {featuresSet, aarch64PauthAbiTag};
938956
}
939957

940958
// Extract compatibility info for aarch64 pointer authentication from the
@@ -966,13 +984,15 @@ static void readAArch64PauthAbiTag(const InputSection &sec, ObjFile<ELFT> &f) {
966984
" (ARM expected)");
967985

968986
ArrayRef<uint8_t> desc = note.getDesc(sec.addralign);
969-
if (desc.size() < 16) {
970-
reportError("too short AArch64 PAuth compatibility info "
971-
"(at least 16 bytes expected)");
987+
if (desc.size() != 16) {
988+
reportError("invalid AArch64 PAuth compatibility info length "
989+
"(exactly 16 bytes expected)");
972990
return;
973991
}
974992

975-
f.aarch64PauthAbiTag = SmallVector<uint8_t, 0>(iterator_range(desc));
993+
f.aarch64PauthAbiTag = std::array<uint8_t, 16>{};
994+
memcpy(f.aarch64PauthAbiTag->data(), desc.data(),
995+
f.aarch64PauthAbiTag->size());
976996
}
977997

978998
template <class ELFT>
@@ -1029,12 +1049,18 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
10291049
// .note.gnu.property containing a single AND'ed bitmap, we discard an input
10301050
// file's .note.gnu.property section.
10311051
if (name == ".note.gnu.property") {
1032-
this->andFeatures = readAndFeatures<ELFT>(InputSection(*this, sec, name));
1052+
std::tie(this->andFeatures, this->aarch64PauthAbiTag) =
1053+
readGnuProperty<ELFT>(InputSection(*this, sec, name));
10331054
return &InputSection::discarded;
10341055
}
10351056

10361057
if (config->emachine == EM_AARCH64 &&
10371058
name == ".note.AARCH64-PAUTH-ABI-tag") {
1059+
// TODO: proper handling of both ways of ELF marking in one file
1060+
// To be implemented after the following PRs are merged:
1061+
// - https://github.com/ARM-software/abi-aa/pull/240
1062+
// - https://github.com/llvm/llvm-project/pull/72714
1063+
assert(this->aarch64PauthAbiTag == std::nullopt);
10381064
readAArch64PauthAbiTag<ELFT>(InputSection(*this, sec, name), *this);
10391065
return &InputSection::discarded;
10401066
}

lld/ELF/InputFiles.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ class ELFFileBase : public InputFile {
218218
public:
219219
uint32_t andFeatures = 0;
220220
bool hasCommonSyms = false;
221-
SmallVector<uint8_t, 0> aarch64PauthAbiTag;
221+
std::optional<std::array<uint8_t, 16>> aarch64PauthAbiTag;
222222
};
223223

224224
// .o file.

lld/ELF/SyntheticSections.cpp

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -314,33 +314,56 @@ GnuPropertySection::GnuPropertySection()
314314
config->wordsize, ".note.gnu.property") {}
315315

316316
void GnuPropertySection::writeTo(uint8_t *buf) {
317+
write32(buf, 4); // Name size
318+
write32(buf + 4, getSize() - 16); // Content size
319+
write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
320+
memcpy(buf + 12, "GNU", 4); // Name string
321+
317322
uint32_t featureAndType = config->emachine == EM_AARCH64
318323
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
319324
: GNU_PROPERTY_X86_FEATURE_1_AND;
320325

321-
write32(buf, 4); // Name size
322-
write32(buf + 4, config->is64 ? 16 : 12); // Content size
323-
write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
324-
memcpy(buf + 12, "GNU", 4); // Name string
325-
write32(buf + 16, featureAndType); // Feature type
326-
write32(buf + 20, 4); // Feature size
327-
write32(buf + 24, config->andFeatures); // Feature flags
328-
if (config->is64)
329-
write32(buf + 28, 0); // Padding
326+
unsigned offset = 16;
327+
328+
if (config->andFeatures != 0) {
329+
write32(buf + offset + 0, featureAndType); // Feature type
330+
write32(buf + offset + 4, 4); // Feature size
331+
write32(buf + offset + 8, config->andFeatures); // Feature flags
332+
if (config->is64)
333+
write32(buf + offset + 12, 0); // Padding
334+
offset += 16;
335+
}
336+
337+
if (ctx.aarch64PauthAbiTag != std::nullopt) {
338+
write32(buf + offset + 0, GNU_PROPERTY_AARCH64_FEATURE_PAUTH);
339+
write32(buf + offset + 4, 8 * 2);
340+
memcpy(buf + offset + 8, ctx.aarch64PauthAbiTag->data(),
341+
ctx.aarch64PauthAbiTag->size());
342+
}
330343
}
331344

332-
size_t GnuPropertySection::getSize() const { return config->is64 ? 32 : 28; }
345+
size_t GnuPropertySection::getSize() const {
346+
uint32_t contentSize = 0;
347+
if (config->andFeatures != 0)
348+
contentSize += config->is64 ? 16 : 12;
349+
if (ctx.aarch64PauthAbiTag != std::nullopt) {
350+
assert(config->emachine == EM_AARCH64);
351+
contentSize += 4 + 4 + 8 * 2;
352+
}
353+
assert(contentSize != 0);
354+
return contentSize + 16;
355+
}
333356

334357
AArch64PauthAbiTag::AArch64PauthAbiTag()
335358
: SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_NOTE,
336359
config->wordsize, ".note.AARCH64-PAUTH-ABI-tag") {}
337360

338361
bool AArch64PauthAbiTag::isNeeded() const {
339-
return !ctx.aarch64PauthAbiTag.empty();
362+
return ctx.aarch64PauthAbiTag != std::nullopt;
340363
}
341364

342365
void AArch64PauthAbiTag::writeTo(uint8_t *buf) {
343-
const SmallVector<uint8_t, 0> &data = ctx.aarch64PauthAbiTag;
366+
std::array<uint8_t, 16> data = ctx.aarch64PauthAbiTag.value();
344367
write32(buf, 4); // Name size
345368
write32(buf + 4, data.size()); // Content size
346369
write32(buf + 8, NT_ARM_TYPE_PAUTH_ABI_TAG); // Type
@@ -349,11 +372,6 @@ void AArch64PauthAbiTag::writeTo(uint8_t *buf) {
349372
memset(buf + 16 + data.size(), 0, getSize() - 16 - data.size()); // Padding
350373
}
351374

352-
size_t AArch64PauthAbiTag::getSize() const {
353-
return alignToPowerOf2(16 + ctx.aarch64PauthAbiTag.size(),
354-
config->is64 ? 8 : 4);
355-
}
356-
357375
BuildIdSection::BuildIdSection()
358376
: SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"),
359377
hashSize(getHashSize()) {}

lld/ELF/SyntheticSections.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class AArch64PauthAbiTag final : public SyntheticSection {
150150
public:
151151
AArch64PauthAbiTag();
152152
void writeTo(uint8_t *buf) override;
153-
size_t getSize() const override;
153+
size_t getSize() const override { return 32; };
154154
bool isNeeded() const override;
155155
};
156156

lld/ELF/Writer.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -521,13 +521,17 @@ template <class ELFT> void elf::createSyntheticSections() {
521521
in.iplt = std::make_unique<IpltSection>();
522522
add(*in.iplt);
523523

524-
if (config->andFeatures)
524+
if (config->andFeatures || ctx.aarch64PauthAbiTag.has_value())
525525
add(*make<GnuPropertySection>());
526526

527-
if (!ctx.aarch64PauthAbiTag.empty()) {
528-
in.aarch64PauthAbiTag = std::make_unique<AArch64PauthAbiTag>();
529-
add(*in.aarch64PauthAbiTag);
530-
}
527+
// TODO: alternative PAuth ELF marking way
528+
// To be implemented after the following PRs are merged:
529+
// - https://github.com/ARM-software/abi-aa/pull/240
530+
// - https://github.com/llvm/llvm-project/pull/72714
531+
// if (!ctx.aarch64PauthAbiTag.empty()) {
532+
// in.aarch64PauthAbiTag = std::make_unique<AArch64PauthAbiTag>();
533+
// add(*in.aarch64PauthAbiTag);
534+
// }
531535

532536
// .note.GNU-stack is always added when we are creating a re-linkable
533537
// object file. Other linkers are using the presence of this marker

lld/test/ELF/aarch64-feature-pauth.s

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# REQUIRES: aarch64
2+
# TODO: test PAuth ELF marking via GNU property section
23

34
# RUN: rm -rf %t && split-file %s %t && cd %t
45

lldb/include/lldb/Symbol/ObjectFile.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/Support/Threading.h"
2424
#include "llvm/Support/VersionTuple.h"
2525
#include <optional>
26+
#include <utility>
2627

2728
namespace lldb_private {
2829

@@ -331,6 +332,15 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
331332
///
332333
virtual void RelocateSection(lldb_private::Section *section);
333334

335+
/// Parse ELF's AArch64 PAuth ABI from GNU property section. If it's missing
336+
/// or the object file is not an ELF, return std::nullopt. Define this as a
337+
/// virtual function in a base class since direct usage of ObjectFileELF in
338+
/// ClangExpressionParser requires linking against the ObjectFileELF plugin.
339+
virtual std::optional<std::pair<uint64_t, uint64_t>>
340+
ParseGNUPropertyAArch64PAuthABI() {
341+
return std::nullopt;
342+
}
343+
334344
/// Appends a Symbol for the specified so_addr to the symbol table.
335345
///
336346
/// If verify_unique is false, the symbol table is not searched to determine

0 commit comments

Comments
 (0)