aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/InputFiles.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/InputFiles.cpp')
-rw-r--r--lld/ELF/InputFiles.cpp131
1 files changed, 114 insertions, 17 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 71e72e7..a5921fe 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -20,7 +20,9 @@
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/LTO/LTO.h"
+#include "llvm/Object/Archive.h"
#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/AArch64AttributeParser.h"
#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/Endian.h"
@@ -537,6 +539,41 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const {
this);
}
+template <class ELFT>
+static void
+handleAArch64BAAndGnuProperties(ObjFile<ELFT> *file, Ctx &ctx,
+ const AArch64BuildAttrSubsections &baInfo) {
+ if (file->aarch64PauthAbiCoreInfo) {
+ // Check for data mismatch.
+ if (file->aarch64PauthAbiCoreInfo) {
+ if (baInfo.Pauth.TagPlatform != file->aarch64PauthAbiCoreInfo->platform ||
+ baInfo.Pauth.TagSchema != file->aarch64PauthAbiCoreInfo->version)
+ Err(ctx) << file
+ << " GNU properties and build attributes have conflicting "
+ "AArch64 PAuth data";
+ }
+ if (baInfo.AndFeatures != file->andFeatures)
+ Err(ctx) << file
+ << " GNU properties and build attributes have conflicting "
+ "AArch64 PAuth data";
+ } else {
+ // When BuildAttributes are missing, PauthABI value defaults to (TagPlatform
+ // = 0, TagSchema = 0). GNU properties do not write PAuthAbiCoreInfo if GNU
+ // property is not present. To match this behaviour, we only write
+ // PAuthAbiCoreInfo when there is at least one non-zero value. The
+ // specification reserves TagPlatform = 0, TagSchema = 1 values to match the
+ // 'Invalid' GNU property section with platform = 0, version = 0.
+ if (baInfo.Pauth.TagPlatform || baInfo.Pauth.TagSchema) {
+ if (baInfo.Pauth.TagPlatform == 0 && baInfo.Pauth.TagSchema == 1)
+ file->aarch64PauthAbiCoreInfo = {0, 0};
+ else
+ file->aarch64PauthAbiCoreInfo = {baInfo.Pauth.TagPlatform,
+ baInfo.Pauth.TagSchema};
+ }
+ file->andFeatures = baInfo.AndFeatures;
+ }
+}
+
template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
object::ELFFile<ELFT> obj = this->getObj();
// Read a section table. justSymbols is usually false.
@@ -554,6 +591,7 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
sections.resize(size);
for (size_t i = 0; i != size; ++i) {
const Elf_Shdr &sec = objSections[i];
+
if (LLVM_LIKELY(sec.sh_type == SHT_PROGBITS))
continue;
if (LLVM_LIKELY(sec.sh_type == SHT_GROUP)) {
@@ -637,13 +675,6 @@ 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)
- 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
@@ -744,6 +775,8 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
StringRef shstrtab = CHECK2(obj.getSectionStringTable(objSections), this);
uint64_t size = objSections.size();
SmallVector<ArrayRef<Elf_Word>, 0> selectedGroups;
+ AArch64BuildAttrSubsections aarch64BAsubSections;
+ bool hasAArch64BuildAttributes = false;
for (size_t i = 0; i != size; ++i) {
if (this->sections[i] == &InputSection::discarded)
continue;
@@ -775,6 +808,26 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
continue;
}
+ // Processor-specific types that do not use the following switch statement.
+ //
+ // Extract Build Attributes section contents into aarch64BAsubSections.
+ // Input objects may contain both build Build Attributes and GNU
+ // properties. We delay processing Build Attributes until we have finished
+ // reading all sections so that we can check that these are consistent.
+ if (type == SHT_AARCH64_ATTRIBUTES && ctx.arg.emachine == EM_AARCH64) {
+ ArrayRef<uint8_t> contents = check(obj.getSectionContents(sec));
+ AArch64AttributeParser attributes;
+ if (Error e = attributes.parse(contents, ELFT::Endianness)) {
+ StringRef name = check(obj.getSectionName(sec, shstrtab));
+ InputSection isec(*this, sec, name);
+ Warn(ctx) << &isec << ": " << std::move(e);
+ } else {
+ aarch64BAsubSections = extractBuildAttributesSubsections(attributes);
+ hasAArch64BuildAttributes = true;
+ }
+ this->sections[i] = &InputSection::discarded;
+ continue;
+ }
switch (type) {
case SHT_GROUP: {
if (!ctx.arg.relocatable)
@@ -912,6 +965,12 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
<< linkSec;
}
+ // Handle AArch64 Build Attributes and GNU properties:
+ // - Err on mismatched values.
+ // - Store missing values as GNU properties.
+ if (hasAArch64BuildAttributes)
+ handleAArch64BAAndGnuProperties<ELFT>(this, ctx, aarch64BAsubSections);
+
for (ArrayRef<Elf_Word> entries : selectedGroups)
handleSectionGroup<ELFT>(this->sections, entries);
}
@@ -1753,6 +1812,39 @@ static uint8_t getOsAbi(const Triple &t) {
}
}
+// For DTLTO, bitcode member names must be valid paths to files on disk.
+// For thin archives, resolve `memberPath` relative to the archive's location.
+// Returns true if adjusted; false otherwise. Non-thin archives are unsupported.
+static bool dtltoAdjustMemberPathIfThinArchive(Ctx &ctx, StringRef archivePath,
+ std::string &memberPath) {
+ assert(!archivePath.empty());
+
+ if (ctx.arg.dtltoDistributor.empty())
+ return false;
+
+ // Read the archive header to determine if it's a thin archive.
+ auto bufferOrErr =
+ MemoryBuffer::getFileSlice(archivePath, sizeof(ThinArchiveMagic) - 1, 0);
+ if (std::error_code ec = bufferOrErr.getError()) {
+ ErrAlways(ctx) << "cannot open " << archivePath << ": " << ec.message();
+ return false;
+ }
+
+ if (!bufferOrErr->get()->getBuffer().starts_with(ThinArchiveMagic))
+ return false;
+
+ SmallString<128> resolvedPath;
+ if (path::is_relative(memberPath)) {
+ resolvedPath = path::parent_path(archivePath);
+ path::append(resolvedPath, memberPath);
+ } else
+ resolvedPath = memberPath;
+
+ path::remove_dots(resolvedPath, /*remove_dot_dot=*/true);
+ memberPath = resolvedPath.str();
+ return true;
+}
+
BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive, bool lazy)
: InputFile(ctx, BitcodeKind, mb) {
@@ -1763,17 +1855,22 @@ BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName,
if (ctx.arg.thinLTOIndexOnly)
path = replaceThinLTOSuffix(ctx, mb.getBufferIdentifier());
- // ThinLTO assumes that all MemoryBufferRefs given to it have a unique
- // name. If two archives define two members with the same name, this
- // causes a collision which result in only one of the objects being taken
- // into consideration at LTO time (which very likely causes undefined
- // symbols later in the link stage). So we append file offset to make
- // filename unique.
StringSaver &ss = ctx.saver;
- StringRef name = archiveName.empty()
- ? ss.save(path)
- : ss.save(archiveName + "(" + path::filename(path) +
- " at " + utostr(offsetInArchive) + ")");
+ StringRef name;
+ if (archiveName.empty() ||
+ dtltoAdjustMemberPathIfThinArchive(ctx, archiveName, path)) {
+ name = ss.save(path);
+ } else {
+ // ThinLTO assumes that all MemoryBufferRefs given to it have a unique
+ // name. If two archives define two members with the same name, this
+ // causes a collision which result in only one of the objects being taken
+ // into consideration at LTO time (which very likely causes undefined
+ // symbols later in the link stage). So we append file offset to make
+ // filename unique.
+ name = ss.save(archiveName + "(" + path::filename(path) + " at " +
+ utostr(offsetInArchive) + ")");
+ }
+
MemoryBufferRef mbref(mb.getBuffer(), name);
obj = CHECK2(lto::InputFile::create(mbref), this);