#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
friend class AtomGraph;
private:
- Section(StringRef Name, sys::Memory::ProtectionFlags Prot, unsigned Ordinal,
- bool IsZeroFill)
- : Name(Name), Prot(Prot), Ordinal(Ordinal), IsZeroFill(IsZeroFill) {}
+ Section(StringRef Name, uint32_t Alignment, sys::Memory::ProtectionFlags Prot,
+ unsigned Ordinal, bool IsZeroFill)
+ : Name(Name), Alignment(Alignment), Prot(Prot), Ordinal(Ordinal),
+ IsZeroFill(IsZeroFill) {
+ assert(isPowerOf2_32(Alignment) && "Alignments must be a power of 2");
+ }
using DefinedAtomSet = DenseSet<DefinedAtom *>;
~Section();
StringRef getName() const { return Name; }
+ uint32_t getAlignment() const { return Alignment; }
sys::Memory::ProtectionFlags getProtectionFlags() const { return Prot; }
unsigned getSectionOrdinal() const { return Ordinal; }
size_t getNextAtomOrdinal() { return ++NextAtomOrdinal; }
}
StringRef Name;
+ uint32_t Alignment = 0;
sys::Memory::ProtectionFlags Prot;
unsigned Ordinal = 0;
unsigned NextAtomOrdinal = 0;
private:
DefinedAtom(Section &Parent, JITTargetAddress Address, uint32_t Alignment)
: Atom("", Address), Parent(Parent), Ordinal(Parent.getNextAtomOrdinal()),
- Alignment(Alignment) {}
+ Alignment(Alignment) {
+ assert(isPowerOf2_32(Alignment) && "Alignments must be a power of two");
+ }
DefinedAtom(Section &Parent, StringRef Name, JITTargetAddress Address,
uint32_t Alignment)
: Atom(Name, Address), Parent(Parent),
- Ordinal(Parent.getNextAtomOrdinal()), Alignment(Alignment) {}
+ Ordinal(Parent.getNextAtomOrdinal()), Alignment(Alignment) {
+ assert(isPowerOf2_32(Alignment) && "Alignments must be a power of two");
+ }
public:
using edge_iterator = EdgeVector::iterator;
inline SectionRange Section::getRange() const {
if (atoms_empty())
return SectionRange();
- DefinedAtom *First = *DefinedAtoms.begin(), *Last = *DefinedAtoms.end();
+ DefinedAtom *First = *DefinedAtoms.begin(), *Last = *DefinedAtoms.begin();
for (auto *DA : atoms()) {
if (DA->getAddress() < First->getAddress())
First = DA;
support::endianness getEndianness() const { return Endianness; }
/// Create a section with the given name, protection flags, and alignment.
- Section &createSection(StringRef Name, sys::Memory::ProtectionFlags Prot,
- bool IsZeroFill) {
+ Section &createSection(StringRef Name, uint32_t Alignment,
+ sys::Memory::ProtectionFlags Prot, bool IsZeroFill) {
std::unique_ptr<Section> Sec(
- new Section(Name, Prot, Sections.size(), IsZeroFill));
+ new Section(Name, Alignment, Prot, Sections.size(), IsZeroFill));
Sections.push_back(std::move(Sec));
return *Sections.back();
}
for (auto &SI : SegLayout.ContentSections) {
assert(!SI.S->atoms_empty() && "Sections in layout must not be empty");
assert(!SI.Atoms.empty() && "Section layouts must not be empty");
+
+ // Bump to section alignment before processing atoms.
+ SegContentSize = alignTo(SegContentSize, SI.S->getAlignment());
+
for (auto *DA : SI.Atoms) {
SegContentSize = alignTo(SegContentSize, DA->getAlignment());
SegContentSize += DA->getSize();
// Get segment content alignment.
unsigned SegContentAlign = 1;
- if (!SegLayout.ContentSections.empty())
+ if (!SegLayout.ContentSections.empty()) {
+ auto &FirstContentSection = SegLayout.ContentSections.front();
SegContentAlign =
- SegLayout.ContentSections.front().Atoms.front()->getAlignment();
+ std::max(FirstContentSection.S->getAlignment(),
+ FirstContentSection.Atoms.front()->getAlignment());
+ }
// Calculate segment zero-fill size.
uint64_t SegZeroFillSize = 0;
for (auto &SI : SegLayout.ZeroFillSections) {
assert(!SI.S->atoms_empty() && "Sections in layout must not be empty");
assert(!SI.Atoms.empty() && "Section layouts must not be empty");
+
+ // Bump to section alignment before processing atoms.
+ SegZeroFillSize = alignTo(SegZeroFillSize, SI.S->getAlignment());
+
for (auto *DA : SI.Atoms) {
SegZeroFillSize = alignTo(SegZeroFillSize, DA->getAlignment());
SegZeroFillSize += DA->getSize();
// Calculate segment zero-fill alignment.
uint32_t SegZeroFillAlign = 1;
- if (!SegLayout.ZeroFillSections.empty())
+
+ if (!SegLayout.ZeroFillSections.empty()) {
+ auto &FirstZeroFillSection = SegLayout.ZeroFillSections.front();
SegZeroFillAlign =
- SegLayout.ZeroFillSections.front().Atoms.front()->getAlignment();
+ std::max(FirstZeroFillSection.S->getAlignment(),
+ FirstZeroFillSection.Atoms.front()->getAlignment());
+ }
if (SegContentSize == 0)
SegContentAlign = SegZeroFillAlign;
Alloc->getTargetMemory(static_cast<sys::Memory::ProtectionFlags>(Prot));
for (auto *SIList : {&SL.ContentSections, &SL.ZeroFillSections})
- for (auto &SI : *SIList)
+ for (auto &SI : *SIList) {
+ AtomTargetAddr = alignTo(AtomTargetAddr, SI.S->getAlignment());
for (auto *DA : SI.Atoms) {
AtomTargetAddr = alignTo(AtomTargetAddr, DA->getAlignment());
DA->setAddress(AtomTargetAddr);
AtomTargetAddr += DA->getSize();
}
+ }
}
return Error::success();
auto SegMem = Alloc.getWorkingMemory(
static_cast<sys::Memory::ProtectionFlags>(Prot));
char *LastAtomEnd = SegMem.data();
- char *AtomDataPtr = nullptr;
+ char *AtomDataPtr = LastAtomEnd;
LLVM_DEBUG({
dbgs() << " Processing segment "
for (auto &SI : SegLayout.ContentSections) {
LLVM_DEBUG(dbgs() << " " << SI.S->getName() << ":\n");
+
+ AtomDataPtr += alignmentAdjustment(AtomDataPtr, SI.S->getAlignment());
+
+ LLVM_DEBUG({
+ dbgs() << " Bumped atom pointer to " << (const void *)AtomDataPtr
+ << " to meet section alignment "
+ << " of " << SI.S->getAlignment() << "\n";
+ });
+
for (auto *DA : SI.Atoms) {
- AtomDataPtr = LastAtomEnd;
// Align.
AtomDataPtr += alignmentAdjustment(AtomDataPtr, DA->getAlignment());
// Update atom end pointer.
LastAtomEnd = AtomDataPtr + DA->getContent().size();
+ AtomDataPtr = LastAtomEnd;
}
}
if (!CommonSymbolsSection) {
auto Prot = static_cast<sys::Memory::ProtectionFlags>(
sys::Memory::MF_READ | sys::Memory::MF_WRITE);
- auto &GenericSection = G->createSection("<common>", Prot, true);
+ auto &GenericSection = G->createSection("<common>", 1, Prot, true);
CommonSymbolsSection = MachOSection(GenericSection);
}
return *CommonSymbolsSection;
unsigned SectionIndex = SecRef.getIndex() + 1;
+ uint32_t Align = SecRef.getAlignment();
+ if (!isPowerOf2_32(Align))
+ return make_error<JITLinkError>("Section " + Name +
+ " has non-power-of-2 "
+ "alignment");
+
// FIXME: Get real section permissions
// How, exactly, on MachO?
sys::Memory::ProtectionFlags Prot;
Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
sys::Memory::MF_WRITE);
- auto &GenericSection = G->createSection(Name, Prot, SecRef.isBSS());
+ auto &GenericSection = G->createSection(Name, Align, Prot, SecRef.isBSS());
LLVM_DEBUG({
dbgs() << "Adding section " << Name << ": "
private:
Section &getGOTSection() {
if (!GOTSection)
- GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ, false);
+ GOTSection = &G.createSection("$__GOT", 8, sys::Memory::MF_READ, false);
return *GOTSection;
}
if (!StubsSection) {
auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
sys::Memory::MF_READ | sys::Memory::MF_EXEC);
- StubsSection = &G.createSection("$__STUBS", StubsProt, false);
+ StubsSection = &G.createSection("$__STUBS", 8, StubsProt, false);
}
return *StubsSection;
}
.globl zero_fill_test
.zerofill __DATA,__zero_fill_test,zero_fill_test,8,3
+# Check that section alignments are respected.
+# We test this by introducing two segments with alignment 8, each containing one
+# byte of data. We require both symbols to have an aligned address.
+#
+# jitlink-check: section_alignment_check1[2:0] = 0
+# jitlink-check: section_alignment_check2[2:0] = 0
+ .section __DATA,__sec_align_chk1
+ .p2align 3
+
+ .globl section_alignment_check1
+section_alignment_check1:
+ .byte 0
+
+ .section __DATA,__sec_align_chk2
+ .p2align 3
+
+ .globl section_alignment_check2
+section_alignment_check2:
+ .byte 0
+
.subsections_via_symbols