Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
46 changes: 46 additions & 0 deletions lld/ELF/Arch/Cheri.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,13 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
}
}

// For function relocs, use PCC bounds from the PT_CHERI_PCC segment.
if (config->emachine != EM_MIPS && (isFunc || isGnuIFunc)) {
targetOffset += targetVA - pccBase();
targetVA = pccBase();
targetSize = pccSize();
}

// TODO: should we warn about symbols that are out-of-bounds?
// mandoc seems to do it so I guess we need it
// if (TargetOffset < 0 || TargetOffset > TargetSize) warn(...);
Expand Down Expand Up @@ -952,5 +959,44 @@ void addRelativeCapabilityRelocation(
addend);
}

// Determine the required alignment for a single PT_CHERI_PCC segment. Apply
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 could squash this commit down into the previous one if the detailed history here is not useful.

// the alignment to the first OutputSection and adjust the length of the padding
// section to align the end of the segment. Returns true if the alignment of
// the first OutputSection changed or the size of the padding section changed.
static bool alignPCCBounds(PhdrEntry *p, CheriPccPaddingSection &psec) {
OutputSection *first = p->firstSec;
OutputSection *last = p->lastSec;

if (!first)
return false;

assert(psec.getParent() == last && "padding section is not last");
assert(psec.isNeeded() && "padding section is not enabled");

// Ignore existing padding.
uint64_t size = last->getVA() - first->getVA();
uint64_t align = target->getCheriRequiredAlignment(size);
if (align == 0)
align = 1;
bool changed = false;
if (first->addralign < align) {
first->addralign = align;
changed = true;
}
uint64_t padSize = alignTo(size, align) - size;
if (psec.getSize() != padSize) {
psec.setSize(padSize);
changed = true;
}
return changed;
}

bool cheriCapabilityBoundsAlign() {
// Align the PT_CHERI_PCC segment.
bool changed = false;
changed |= alignPCCBounds(in.cheriBounds, *in.pccPadding);
return changed;
}

} // namespace elf
} // namespace lld
6 changes: 6 additions & 0 deletions lld/ELF/Arch/Cheri.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,12 @@ void addRelativeCapabilityRelocation(
InputSectionBase &isec, uint64_t offsetInSec,
llvm::PointerUnion<Symbol *, InputSectionBase *> symOrSec, int64_t addend,
RelExpr expr, RelType type);

// Align OutputSections as needed to ensure the bounds of capabilities
// such as PCC do not permit undesired access to portions of other
// OutputSections. Return true if the alignment of any OutputSection
// was modified.
bool cheriCapabilityBoundsAlign();
} // namespace elf
} // namespace lld

Expand Down
9 changes: 9 additions & 0 deletions lld/ELF/Arch/Mips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/CHERI/cheri-compressed-cap/cheri_compressed_cap.h"

using namespace llvm;
using namespace llvm::object;
Expand All @@ -26,6 +27,7 @@ template <class ELFT> class MIPS final : public TargetInfo {
MIPS();
uint32_t calcEFlags() const override;
int getCapabilitySize() const override;
uint64_t getCheriRequiredAlignment(uint64_t len) const override;
RelExpr getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const override;
int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
Expand Down Expand Up @@ -89,6 +91,13 @@ template <class ELFT> int MIPS<ELFT>::getCapabilitySize() const {
return 0;
}

template <class ELFT>
uint64_t MIPS<ELFT>::getCheriRequiredAlignment(uint64_t len) const {
if ((config->eflags & EF_MIPS_MACH) == EF_MIPS_MACH_CHERI128)
return cc128_get_required_alignment(len);
return 1;
}

template <class ELFT>
RelExpr MIPS<ELFT>::getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const {
Expand Down
9 changes: 9 additions & 0 deletions lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "llvm/CHERI/cheri-compressed-cap/cheri_compressed_cap.h"
#include "llvm/Support/ELFAttributes.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/RISCVAttributeParser.h"
Expand All @@ -32,6 +33,7 @@ class RISCV final : public TargetInfo {
RISCV();
uint32_t calcEFlags() const override;
int getCapabilitySize() const override;
uint64_t getCheriRequiredAlignment(uint64_t len) const override;
int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
void writeGotHeader(uint8_t *buf) const override;
void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
Expand Down Expand Up @@ -155,6 +157,13 @@ int RISCV::getCapabilitySize() const {
return config->is64 ? 16 : 8;
}

uint64_t RISCV::getCheriRequiredAlignment(uint64_t len) const {
if (config->is64)
return cc128_get_required_alignment(len);
else
return cc64_get_required_alignment(len);
}

uint32_t RISCV::calcEFlags() const {
// If there are only binary input files (from -b binary), use a
// value of 0 for the ELF header flags.
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/OutputSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class OutputSection final : public SectionBase {
uint64_t addr = 0;
uint32_t shName = 0;

// Sections accessed using PCC on CHERI architectures.
bool cheriPcc = false;

void recordSection(InputSectionBase *isec);
void commitSection(InputSection *isec);
void finalizeInputSections();
Expand Down
12 changes: 12 additions & 0 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3990,6 +3990,7 @@ void InStruct::reset() {
strTab.reset();
symTab.reset();
symTabShndx.reset();
cheriBounds = nullptr;
}

constexpr char kMemtagAndroidNoteName[] = "Android";
Expand Down Expand Up @@ -4036,6 +4037,17 @@ size_t PackageMetadataNote::getSize() const {
alignTo(config->packageMetadata.size() + 1, 4);
}

void CheriPccPaddingSection::writeTo(uint8_t *buf) { memset(buf, 0, size); }

uint64_t elf::pccBase() { return in.cheriBounds->firstSec->addr; }

uint64_t elf::pccSize() {
PhdrEntry *phdr = in.cheriBounds;
OutputSection *first = phdr->firstSec;
OutputSection *last = phdr->lastSec;
return last->getVA() + last->size - first->getVA();
}

InStruct elf::in;

std::vector<Partition> elf::partitions;
Expand Down
23 changes: 23 additions & 0 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,23 @@ class PackageMetadataNote final : public SyntheticSection {
size_t getSize() const override;
};

class CheriPccPaddingSection final : public SyntheticSection {
public:
CheriPccPaddingSection()
: SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_PROGBITS,
/*alignment=*/1, ".pad.cheri.pcc") {}

void writeTo(uint8_t *buf) override;
void markNeeded() { needed = true; }
bool isNeeded() const override { return needed; }
size_t getSize() const override { return size; }
void setSize(uint64_t len) { size = len; }

private:
uint64_t size = 0;
bool needed = false;
};

InputSection *createInterpSection();
MergeInputSection *createCommentSection();
template <class ELFT> void splitSections();
Expand Down Expand Up @@ -1313,6 +1330,7 @@ struct InStruct {
std::unique_ptr<GotPltSection> gotPlt;
std::unique_ptr<IgotPltSection> igotPlt;
std::unique_ptr<MipsCheriCapTableSection> mipsCheriCapTable;
std::unique_ptr<CheriPccPaddingSection> pccPadding;
std::unique_ptr<CheriCapRelocsSection> capRelocs;
// For per-file/per-function tables:
std::unique_ptr<MipsCheriCapTableMappingSection> mipsCheriCapTableMapping;
Expand All @@ -1336,11 +1354,16 @@ struct InStruct {
std::unique_ptr<SymbolTableBaseSection> symTab;
std::unique_ptr<SymtabShndxSection> symTabShndx;

PhdrEntry *cheriBounds;

void reset();
};

LLVM_LIBRARY_VISIBILITY extern InStruct in;

uint64_t pccBase();
uint64_t pccSize();

} // namespace lld::elf

#endif
5 changes: 5 additions & 0 deletions lld/ELF/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ ErrorPlace elf::getErrorPlace(const uint8_t *loc) {

TargetInfo::~TargetInfo() {}

uint64_t TargetInfo::getCheriRequiredAlignment(uint64_t len) const {
error("current target does not provide required Cheri alignment");
return 1;
}

int64_t TargetInfo::getImplicitAddend(const uint8_t *buf, RelType type) const {
internalLinkerError(getErrorLocation(buf),
"cannot read addend for relocation " + toString(type));
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class TargetInfo {
public:
virtual uint32_t calcEFlags() const { return 0; }
virtual int getCapabilitySize() const { return 0; }
virtual uint64_t getCheriRequiredAlignment(uint64_t len) const;
virtual RelExpr getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const = 0;
virtual RelType getDynRel(RelType type) const { return 0; }
Expand Down
Loading