Skip to content

[lld][AArch64][Build Attributes] Add support for converting AArch64 Build Attributes to GNU Properties #131990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 89 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
f98c952
[lld][AArch64][Build Attributes] Add support for converting AArch64 B…
sivan-shani Mar 18, 2025
d4299e9
fix formatting
sivan-shani Mar 19, 2025
783dbf9
remove stand alone condition out of braces of prevoius condition
sivan-shani Mar 19, 2025
5dfca32
formatting
sivan-shani Mar 19, 2025
8b6377a
formatting
sivan-shani Mar 19, 2025
9d81bc0
formatting
sivan-shani Mar 19, 2025
9c8f950
format
sivan-shani Mar 19, 2025
94bebe0
format
sivan-shani Mar 19, 2025
e73a6bd
fix: readig symbol table should be done once per file, not per symbol…
sivan-shani Mar 19, 2025
60a5eea
remove memory header
sivan-shani Mar 20, 2025
9052abf
undo unrealted formatting
sivan-shani Mar 20, 2025
52869a1
remove unused variable
sivan-shani Mar 20, 2025
534e55e
clarify what is being sanitized in comments
sivan-shani Mar 20, 2025
02a1fa7
change SmallVector to SmallVectorImpl
sivan-shani Mar 20, 2025
ec89018
undo unrelated formatting
sivan-shani Mar 20, 2025
7292c36
fix formating fail
sivan-shani Mar 20, 2025
d026726
use instead of asigning auto f =(*this)
sivan-shani Mar 20, 2025
6709e9a
pass InputSection by reference
sivan-shani Mar 20, 2025
04e2a16
remove unnecessery headers
sivan-shani Mar 20, 2025
eb2abbc
err on unknown tags for non-optional subsection
sivan-shani Mar 20, 2025
eb84c8c
use vector.empty() instead of 0 == vector.size()
sivan-shani Mar 20, 2025
be821a5
remove warnig on empty pauth subsection
sivan-shani Mar 20, 2025
f9a0fcb
enum instead of numbers
sivan-shani Mar 20, 2025
ab6dc73
simplify: use struct to hold attributes instead of needlesly over-com…
sivan-shani Mar 20, 2025
8a21905
remove merging
sivan-shani Mar 20, 2025
fd365cb
check for gnu properties section in a separate loop before the main loop
sivan-shani Mar 20, 2025
024847d
fix asignment to wrong values
sivan-shani Mar 20, 2025
f9d7aa8
scheme --> schema
sivan-shani Mar 20, 2025
7903817
use value_or() for optionals
sivan-shani Mar 20, 2025
f225428
warn when both gnu properties and aarch64 build attributes exist
sivan-shani Mar 20, 2025
0e643e5
add test files
sivan-shani Mar 20, 2025
f187b20
remove required from test files in AArch64 folder
sivan-shani Mar 20, 2025
81a86d8
add test files for drop-in aarch64 BA replacement for gnu properties
sivan-shani Apr 1, 2025
592100f
change test files names
sivan-shani Apr 1, 2025
fe23b71
remove now unused variables
sivan-shani Apr 2, 2025
dceec93
change varibles from std::optional to unsigned
sivan-shani Apr 2, 2025
de3e43e
remove unused bool
sivan-shani Apr 2, 2025
72e725a
comments should have capital letters and full stops
sivan-shani Apr 2, 2025
902f9ef
create InputSection once outside if/else
sivan-shani Apr 2, 2025
2df0fcb
remove warning when both aarch64 BA and gno properties present + rela…
sivan-shani Apr 2, 2025
ecd2c51
remove part of tests which are irelevant for testing aarch64 ba
sivan-shani Apr 2, 2025
d439930
fix file name
sivan-shani Apr 2, 2025
22c6478
remove unused func getBuildAttributesSection
sivan-shani Apr 3, 2025
3321d46
remove test file for testing errs and warns
sivan-shani Apr 3, 2025
17dbb95
fix endianess
sivan-shani Apr 3, 2025
ed7b5e6
format
sivan-shani Apr 3, 2025
f0eb74d
restore formatting
sivan-shani Apr 3, 2025
6a541b8
remove unused function arguments
sivan-shani Apr 4, 2025
4620091
add break to loop when section found
sivan-shani Apr 4, 2025
c8637a0
refactor by using lambda
sivan-shani Apr 4, 2025
1470bdf
format
sivan-shani Apr 4, 2025
98dc05f
remove unused include, s/dispatcher/loader/
sivan-shani Apr 4, 2025
57d7ff9
do not wrtie pauth data when both values are 0
sivan-shani Apr 4, 2025
ddb1b3e
consolidate test files
sivan-shani Apr 4, 2025
debcd30
check gnu properties content
sivan-shani Apr 8, 2025
deaf7de
add test file when both GNU properties and BA present, but GP has no …
sivan-shani Apr 8, 2025
88359f4
add test file for melformed object file
sivan-shani Apr 8, 2025
64a45ed
change struct name
sivan-shani Apr 10, 2025
8873a15
handle GNU properties and build attributes after loop
sivan-shani Apr 11, 2025
9e70cbe
delete commented lines
sivan-shani Apr 11, 2025
bbb33fe
only serialize, reduce message size
sivan-shani Apr 11, 2025
711ea6f
comments
sivan-shani Apr 11, 2025
b46b466
revert unintended change in comment
sivan-shani Apr 11, 2025
24f4b80
format
sivan-shani Apr 11, 2025
8e27785
unsigned -> uint64_t
sivan-shani Apr 14, 2025
da33de6
change to uint32_t andFeatures = 0;
sivan-shani Apr 14, 2025
5cb1940
use lambda for getting attributes values
sivan-shani Apr 14, 2025
572e5f4
move reading .note.gnu.property to the parse loop
sivan-shani Apr 14, 2025
31214b8
use split-file for testing
sivan-shani Apr 14, 2025
7d2d795
move AArch64 related code to AArch64.h
sivan-shani Apr 14, 2025
b2803a3
restore white space
sivan-shani Apr 14, 2025
cb49f85
remove {} and fix typo in comments
sivan-shani Apr 14, 2025
dd89ea1
format
sivan-shani Apr 14, 2025
93f21f2
remove empty line
sivan-shani Apr 14, 2025
e40609a
revert std::string to StringRef, change already been merged
sivan-shani Apr 14, 2025
3f5b14c
typo and format
sivan-shani Apr 15, 2025
5013203
move AArch64 specific code to llvm/include/llvm/Support/AArch64Attrib…
sivan-shani Apr 16, 2025
9738781
add check before executing handleAArch64BAAndGnuProperties
sivan-shani Apr 16, 2025
45f7246
fix typo in file name
sivan-shani Apr 16, 2025
d802fcc
remove redundant tests, consolidate some tests files
sivan-shani Apr 16, 2025
ae1a032
move functions back to original location in file, add forward declara…
sivan-shani Apr 16, 2025
b5c882e
remove dead code
sivan-shani Apr 16, 2025
54fe275
move code back to prev lcation
sivan-shani Apr 16, 2025
afca83d
remove unnecessery include
sivan-shani Apr 16, 2025
20760a9
change test file from using yaml to using .section notations
sivan-shani Apr 17, 2025
8b1e002
change ErrAlways to Err
sivan-shani Apr 17, 2025
37a3aec
change test files comments to follow lld convention
sivan-shani Apr 17, 2025
da6ddb2
remove unneeded default ctor
sivan-shani Apr 22, 2025
b3e62ec
arrange forward declarations
sivan-shani Apr 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/ELFAttributes.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GlobPattern.h"
Expand Down Expand Up @@ -131,7 +132,7 @@ enum class SeparateSegmentKind { None, Code, Loadable };
enum class GnuStackKind { None, Exec, NoExec };

// For --lto=
enum LtoKind : uint8_t {UnifiedThin, UnifiedRegular, Default};
enum LtoKind : uint8_t { UnifiedThin, UnifiedRegular, Default };

// For -z gcs=
enum class GcsPolicy { Implicit, Never, Always };
Expand Down Expand Up @@ -195,7 +196,8 @@ struct Config {
uint8_t osabi = 0;
uint32_t andFeatures = 0;
llvm::CachePruningPolicy thinLTOCachePolicy;
llvm::SetVector<llvm::CachedHashString> dependencyFiles; // for --dependency-file
llvm::SetVector<llvm::CachedHashString>
dependencyFiles; // for --dependency-file
llvm::StringMap<uint64_t> sectionStartMap;
llvm::StringRef bfdname;
llvm::StringRef chroot;
Expand Down Expand Up @@ -694,6 +696,10 @@ struct Ctx : CommonLinkerContext {
llvm::raw_fd_ostream openAuxiliaryFile(llvm::StringRef, std::error_code &);

ArrayRef<uint8_t> aarch64PauthAbiCoreInfo;

// AArch64 Build Attributes data
std::optional<llvm::BuildAttributeSubSection> mergedPauthSubSection;
std::optional<llvm::BuildAttributeSubSection> mergedFAndBSubSection;
};

// The first two elements of versionDefinitions represent VER_NDX_LOCAL and
Expand Down
249 changes: 233 additions & 16 deletions lld/ELF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,21 @@
#include "lld/Common/DWARF.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Support/AArch64AttributeParser.h"
#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/ELFAttributes.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/RISCVAttributeParser.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <optional>

using namespace llvm;
Expand Down Expand Up @@ -207,6 +212,166 @@ static void updateSupportedARMFeatures(Ctx &ctx,
ctx.arg.armHasThumb2ISA |= thumb && *thumb >= ARMBuildAttrs::AllowThumb32;
}

// Sanitize pauth values
static void sanitizePauthSubSection(
Ctx &ctx, std::optional<llvm::BuildAttributeSubSection> &pauthSubSection,
InputSection isec) {
/*
Incomplete data: ignore
*/
if (!pauthSubSection)
return;
// Currently there are 2 known tags defined for the pauth subsection,
// however, user is allowed to add other, unknown tag. If such tags exists,
// remove them. (no need to check for duplicates, they should not be possible)
pauthSubSection->Content.erase(
std::remove_if(pauthSubSection->Content.begin(),
pauthSubSection->Content.end(),
[](const BuildAttributeItem &item) {
return item.Tag != 1 && item.Tag != 2;
}),
pauthSubSection->Content.end());

if (pauthSubSection->Content.size() < 2) {
if (0 == pauthSubSection->Content.size())
Warn(ctx) << &isec
<< ": AArch64 Build Attributes: empty 'aeabi_pauthabi' "
"subsection detected; ignoring subsection";
if (1 == pauthSubSection->Content.size()) {
if (1 == pauthSubSection->Content[0].Tag)
Warn(ctx)
<< &isec
<< ": AArch64 Build Attributes: 'aeabi_pauthabi' subsection "
"contains only an ID (scheme missing); ignoring subsection";
if (2 == pauthSubSection->Content[0].Tag)
Warn(ctx) << &isec
<< ": AArch64 Build Attributes: 'aeabi_pauthabi' subsection "
"contains only a scheme (ID missing); ignoring subsection";
}
pauthSubSection = std::nullopt;
return;
}
// printvec(*pauthSubSection);
assert(2 == pauthSubSection->Content.size() && "vector size should be 2");
std::sort(pauthSubSection->Content.begin(), pauthSubSection->Content.end(),
[](const auto &a, const auto &b) { return a.Tag < b.Tag; });
assert(1 == pauthSubSection->Content[0].Tag && "first tag should be 1");
assert(2 == pauthSubSection->Content[1].Tag && "first tag should be 2");
}

// Sanitize features bits
static void sanitizeFAndBSubSection(
std::optional<llvm::BuildAttributeSubSection> &fAndBSubSection) {
/*
Same as gnu properties: treat a missing 'aeabi_feature_and_bits' feature as
being set to 0
*/
if (!fAndBSubSection) {
fAndBSubSection.emplace("aeabi_feature_and_bits", 1, 0,
SmallVector<BuildAttributeItem, 64>());
} else {
// Currently there are 3 known tags defined for the features and bits
// subsection, however, user is allowed to add other, unknown tag. If such
// tags exists, remove them. (duplicates are not possible)
fAndBSubSection->Content.erase(
std::remove_if(fAndBSubSection->Content.begin(),
fAndBSubSection->Content.end(),
[](const BuildAttributeItem &item) {
return item.Tag != 0 && item.Tag != 1 && item.Tag != 2;
}),
fAndBSubSection->Content.end());
}

constexpr unsigned tagBTI = 0, tagPAC = 1, tagGCS = 2;
// Find missing tags
std::set<unsigned> requiredTags = {tagBTI, tagPAC, tagGCS};
for (const auto &item : fAndBSubSection->Content)
requiredTags.erase(item.Tag);

// Add missing tags
for (const auto &tag : requiredTags)
fAndBSubSection->Content.push_back(
BuildAttributeItem(BuildAttributeItem::NumericAttribute, tag, 0, ""));

assert(3 == fAndBSubSection->Content.size() && "vector size should be 3");
std::sort(fAndBSubSection->Content.begin(), fAndBSubSection->Content.end(),
[](const auto &a, const auto &b) { return a.Tag < b.Tag; });
assert(0 == fAndBSubSection->Content[0].Tag && "first tag should be 0");
assert(1 == fAndBSubSection->Content[1].Tag && "first tag should be 1");
assert(2 == fAndBSubSection->Content[2].Tag && "first tag should be 2");
}

static std::array<std::optional<llvm::BuildAttributeSubSection>, 2>
extractBuildAttributesSubsection(
Ctx &ctx,
const SmallVector<llvm::BuildAttributeSubSection, 8>
&buildAttributesSubsections,
InputSection isec) {

std::optional<llvm::BuildAttributeSubSection> newPauthSubSection;
std::optional<llvm::BuildAttributeSubSection> newFAndBSubSection;

for (const auto &newSubSection : buildAttributesSubsections) {
if (newPauthSubSection && newFAndBSubSection)
break;
if ("aeabi_pauthabi" == newSubSection.Name) {
newPauthSubSection.emplace(newSubSection);
continue;
}
if ("aeabi_feature_and_bits" == newSubSection.Name) {
newFAndBSubSection.emplace(newSubSection);
}
}
sanitizePauthSubSection(ctx, newPauthSubSection, isec);
sanitizeFAndBSubSection(newFAndBSubSection);

return {std::move(newPauthSubSection), std::move(newFAndBSubSection)};
}

// Merge AArch64 Build Attributes subsection
static void mergeAArch64BuildAttributes(
Ctx &ctx,
const std::array<std::optional<llvm::BuildAttributeSubSection>, 2>
&buildAttributesSubsections,
InputSection isec) {

auto [newPauthSubSection, newFAndBSubSection] = buildAttributesSubsections;

if (ctx.mergedPauthSubSection == std::nullopt) {
ctx.mergedPauthSubSection = newPauthSubSection;
}

if (ctx.mergedFAndBSubSection == std::nullopt)
ctx.mergedFAndBSubSection = newFAndBSubSection;

if (newPauthSubSection) {
// Since sanitizePauthSubSection sorts, we know that both vectors align.
// Merge pauth (values has to match)
if ((ctx.mergedPauthSubSection->Content[0].IntValue !=
newPauthSubSection->Content[0].IntValue) ||
ctx.mergedPauthSubSection->Content[1].IntValue !=
newPauthSubSection->Content[1].IntValue) {
ctx.mergedPauthSubSection->Content[0].IntValue =
std::numeric_limits<unsigned>::max();
ctx.mergedPauthSubSection->Content[1].IntValue =
std::numeric_limits<unsigned>::max();
Warn(ctx)
<< &isec
<< ": AArch64 Build Attributes: mismatch in 'aeabi_pauthabi' values "
"detected; marking 'aeabi_pauthabi' as invalid for this project";
}
}

// Since sanitizeFAndBSubSection sorts, we know that both vectors align.
// Merge Features and Bits
ctx.mergedFAndBSubSection->Content[0].IntValue &=
newFAndBSubSection->Content[0].IntValue;
ctx.mergedFAndBSubSection->Content[1].IntValue &=
newFAndBSubSection->Content[1].IntValue;
ctx.mergedFAndBSubSection->Content[2].IntValue &=
newFAndBSubSection->Content[2].IntValue;
}

InputFile::InputFile(Ctx &ctx, Kind k, MemoryBufferRef m)
: ctx(ctx), mb(m), groupId(ctx.driver.nextGroupId), fileKind(k) {
// All files within the same --{start,end}-group get the same group ID.
Expand Down Expand Up @@ -552,6 +717,7 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
// done in parallel.
ArrayRef<Elf_Shdr> objSections = getELFShdrs<ELFT>();
StringRef shstrtab = CHECK2(obj.getSectionStringTable(objSections), this);
bool hasGnuProperties = false;
uint64_t size = objSections.size();
sections.resize(size);
for (size_t i = 0; i != size; ++i) {
Expand All @@ -574,9 +740,12 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
.try_emplace(CachedHashStringRef(signature), this)
.second;
if (keepGroup) {
if (!ctx.arg.resolveGroups)
sections[i] = createInputSection(
i, sec, check(obj.getSectionName(sec, shstrtab)));
if (!ctx.arg.resolveGroups) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary change.

StringRef name = check(obj.getSectionName(sec, shstrtab));
if (name == ".note.gnu.property")
hasGnuProperties = true;
sections[i] = createInputSection(i, sec, name);
}
} else {
// Otherwise, discard group members.
for (uint32_t secIndex : entries.slice(1)) {
Expand Down Expand Up @@ -638,25 +807,73 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
}
}
break;
case EM_AARCH64:
// FIXME: BuildAttributes have been implemented in llvm, but not yet in
// lld. Remove the section so that it does not accumulate in the output
// file. When support is implemented we expect not to output a build
// attributes section in files of type ET_EXEC or ET_SHARED, but ld -r
// ouptut will need a single merged attributes section.
if (sec.sh_type == SHT_AARCH64_ATTRIBUTES)
case EM_AARCH64: {
// The specification states that if a file contains both GNU properties
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second sentence here doesn't logically follow from the first. The spec allows for this behaviour, but it would be better to check that the two encodings match (if both are present in one object file), and emit a warning if they do not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing to ...they can be assumed to be identical
Adding check and warning for when both exists and aarch64 build attributes are ignored.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, while I'm happy for this error checking to not be included in this PR, it's still very important because silently ignoring a build attribute can result in a security feature being disabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to depend also on your comment below:

What if the input object has a GNU properties section, but it does not have both of GNU_PROPERTY_AARCH64_FEATURE_1_AND and GNU_PROPERTY_AARCH64_FEATURE_PAUTH? In that case, we still need to parse the build attribute subsections which don't have the matching GNU properties subsections.

If it is indeed possible to have any of the subsections in one file but not in the other, the files will have to be read. Which is basically depends on the meaning of The specification states that if a file contains both GNU properties and AArch64 build attributes, they can be assumed to be identical.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now GNU properties content is being checked

// and AArch64 build attributes, they must be identical. Therefore, if a
// file contains GNU properties, the AArch64 build attributes are ignored.
// If a file does not contain GNU properties, we leverage the existing GNU
// properties mechanism by populating the corresponding data structures,
// which will later be handled by Driver.cpp::readSecurityNotes. This
// ensures that AArch64 build attributes are represented in the linked
// object file as GNU properties, which are already supported by the Linux
// kernel and the dynamic dispatcher.
if (sec.sh_type == SHT_AARCH64_ATTRIBUTES) {
StringRef name = check(obj.getSectionName(sec, shstrtab));
AArch64AttributeParser attributes;
ArrayRef<uint8_t> contents = check(obj.getSectionContents(sec));
if (Error e = attributes.parse(contents, ELFT::Endianness)) {
InputSection isec(*this, sec, name);
Warn(ctx) << &isec << ": " << std::move(e);
} else {
// for functions that has to warn/err/report
InputSection isec(*this, sec, name);
const SmallVector<llvm::BuildAttributeSubSection, 8>
buildAttributesSubSections =
attributes.getBuildAttributesSection();
auto subsections = extractBuildAttributesSubsection(
ctx, buildAttributesSubSections, isec);
mergeAArch64BuildAttributes(ctx, subsections, isec);
if (!hasGnuProperties) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the input object has a GNU properties section, but it does not have both of GNU_PROPERTY_AARCH64_FEATURE_1_AND and GNU_PROPERTY_AARCH64_FEATURE_PAUTH? In that case, we still need to parse the build attribute subsections which don't have the matching GNU properties subsections.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now content of GP is being read.

ObjFile<ELFT> &f = *this;
auto [pauthSubSection, fAndBSubSection] = subsections;
if (pauthSubSection) {
assert(
(pauthSubSection->Content.size() == 2) &&
"pauthSubSection must contain exactly two build attributes");
// sanitizePauthSubSection already sorts
f.aarch64PauthAbiCoreInfoStorage =
std::make_unique<std::array<uint8_t, 16>>();
uint64_t values[2] = {
static_cast<uint64_t>(pauthSubSection->Content[0].IntValue),
static_cast<uint64_t>(pauthSubSection->Content[1].IntValue)};
std::memcpy(f.aarch64PauthAbiCoreInfoStorage->data(), &values[0],
sizeof(values));
f.aarch64PauthAbiCoreInfo = *f.aarch64PauthAbiCoreInfoStorage;
}
if (fAndBSubSection) {
assert((fAndBSubSection->Content.size() == 3) &&
"fAndBSubSection must contain exactly three build "
"attributes");
// sanitizeFAndBSubSection already sorts
f.andFeatures = 0;
f.andFeatures |= (fAndBSubSection->Content[0].IntValue) << 0;
f.andFeatures |= (fAndBSubSection->Content[1].IntValue) << 1;
f.andFeatures |= (fAndBSubSection->Content[2].IntValue) << 2;
}
}
}
sections[i] = &InputSection::discarded;
// Producing a static binary with MTE globals is not currently supported,
// remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
// medatada, and we don't want them to end up in the output file for
// static executables.
}
// Producing a static binary with MTE globals is not currently
// supported, remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as
// they're unused metadata, and we don't want them to end up in the
// output file for static executables.
if (sec.sh_type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC &&
!canHaveMemtagGlobals(ctx))
sections[i] = &InputSection::discarded;
break;
} break;
}
}

// Read a symbol table.
initializeSymbols(obj);
}
Expand Down
6 changes: 4 additions & 2 deletions lld/ELF/InputFiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "llvm/Object/ELF.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/Threading.h"
#include <memory>

namespace llvm {
struct DILineInfo;
Expand Down Expand Up @@ -199,7 +200,7 @@ class ELFFileBase : public InputFile {
}
MutableArrayRef<Symbol *> getMutableGlobalSymbols() {
return llvm::MutableArrayRef(symbols.get() + firstGlobal,
numSymbols - firstGlobal);
numSymbols - firstGlobal);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop irrelevant formatting.

Use sth like

git diff -U0  --relative main...  | ~/llvm/clang/tools/clang-format/clang-format-diff.py -p1 -i

}

template <typename ELFT> typename ELFT::ShdrRange getELFShdrs() const {
Expand Down Expand Up @@ -239,9 +240,11 @@ class ELFFileBase : public InputFile {
public:
// Name of source file obtained from STT_FILE, if present.
StringRef sourceFile;
std::unique_ptr<std::string> sourceFileStorage;
uint32_t andFeatures = 0;
bool hasCommonSyms = false;
ArrayRef<uint8_t> aarch64PauthAbiCoreInfo;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this ever point anywhere other than aarch64PauthAbiCoreInfoStorage? Do we need both?

Copy link
Contributor Author

@sivan-shani sivan-shani Mar 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this ever point anywhere other than aarch64PauthAbiCoreInfoStorage?

No

Do we need both

Yes

In other places aarch64PauthAbiCoreInfo is being pointed at consistent memory that is alive longer then the intended usage of this variable. It has not been designed to point at memory that is going out of scope.
Examples: InputFiles.cpp::parseGnuPropertyNote has f.aarch64PauthAbiCoreInfo = desc and Driver.cpp::readSecurityNotes has ctx.aarch64PauthAbiCoreInfo = (*it)->aarch64PauthAbiCoreInfo.
However, since we have to point aarch64PauthAbiCoreInfo to memory that will no longer be alive beyond scope, aarch64PauthAbiCoreInfoStorage had to be introduced.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative that involves a bit of refactoring of the existing aarch64PauthABICoreInfo, which is optimal for a note section, but not ideal for build attributes, is to deserialize the aarch64PauthABICoreInfo and store the members as two uint64_t instead of an arrayRef. We'll need to update the comparison code in Driver.cpp and in the .note.gnu.property writing code, but it may be neater overall.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the proposed approach could lead to a cleaner design overall, but given the scope and context of the current changes, it feels a bit too involved to refactor at this stage. It might be better to revisit this as a follow-up if needed.

std::unique_ptr<std::array<uint8_t, 16>> aarch64PauthAbiCoreInfoStorage;
};

// .o file.
Expand All @@ -268,7 +271,6 @@ template <class ELFT> class ObjFile : public ELFFileBase {

uint32_t getSectionIndex(const Elf_Sym &sym) const;


// Pointer to this input file's .llvm_addrsig section, if it has one.
const Elf_Shdr *addrsigSec = nullptr;

Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/Support/ELFAttrParserExtended.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ class ELFExtendedAttrParser : public ELFAttributeParser {
virtual ~ELFExtendedAttrParser() { static_cast<void>(!Cursor.takeError()); }
Error parse(ArrayRef<uint8_t> Section, llvm::endianness Endian) override;

const SmallVector<BuildAttributeSubSection, 8> &
getBuildAttributesSection() const {
return SubSectionVec;
}

std::optional<unsigned> getAttributeValue(unsigned Tag) const override;
std::optional<unsigned> getAttributeValue(StringRef BuildAttrSubsectionName,
unsigned Tag) const override;
Expand Down
Loading