fatal(Twine(__FUNCTION__) + ": FIXME: thunk range overrun");
}
thunkInfo.isec =
- make<ConcatInputSection>(isec->getSegName(), isec->getName());
+ makeSyntheticInputSection(isec->getSegName(), isec->getName());
thunkInfo.isec->parent = this;
// This code runs after dead code removal. Need to set the `live` bit
// but it's not really worth supporting the linking of 64-bit programs on
// 32-bit archs.
ArrayRef<uint8_t> data = {nullptr, static_cast<size_t>(common->size)};
- auto *isec = make<ConcatInputSection>(
- segment_names::data, section_names::common, common->getFile(), data,
- common->align, S_ZEROFILL);
+ // FIXME avoid creating one Section per symbol?
+ auto *section =
+ make<Section>(common->getFile(), segment_names::data,
+ section_names::common, S_ZEROFILL, /*addr=*/0);
+ auto *isec = make<ConcatInputSection>(*section, data, common->align);
if (!osec)
osec = ConcatOutputSection::getOrCreateForInput(isec);
isec->parent = osec;
// FIXME: CommonSymbol should store isReferencedDynamically, noDeadStrip
// and pass them on here.
- replaceSymbol<Defined>(sym, sym->getName(), isec->getFile(), isec,
+ replaceSymbol<Defined>(sym, sym->getName(), common->getFile(), isec,
/*value=*/0,
/*size=*/0,
/*isWeakDef=*/false,
TimeTraceScope timeScope("Gathering input sections");
int inputOrder = 0;
for (const InputFile *file : inputFiles) {
- for (const Section §ion : file->sections) {
- const Subsections &subsections = section.subsections;
+ for (const Section *section : file->sections) {
+ const Subsections &subsections = section->subsections;
if (subsections.empty())
continue;
if (subsections[0].isec->getName() == section_names::compactUnwind)
ArrayRef<uint8_t> data = {isZeroFill(sec.flags) ? nullptr
: buf + sec.offset,
static_cast<size_t>(sec.size)};
- sections.push_back(sec.addr);
+ sections.push_back(make<Section>(this, segname, name, sec.flags, sec.addr));
if (sec.align >= 32) {
error("alignment " + std::to_string(sec.align) + " of section " + name +
" is too large");
continue;
}
+ const Section §ion = *sections.back();
uint32_t align = 1 << sec.align;
- uint32_t flags = sec.flags;
auto splitRecords = [&](int recordSize) -> void {
if (data.empty())
return;
- Subsections &subsections = sections.back().subsections;
+ Subsections &subsections = sections.back()->subsections;
subsections.reserve(data.size() / recordSize);
- auto *isec = make<ConcatInputSection>(
- segname, name, this, data.slice(0, recordSize), align, flags);
- subsections.push_back({0, isec});
- for (uint64_t off = recordSize; off < data.size(); off += recordSize) {
- // Copying requires less memory than constructing a fresh InputSection.
- auto *copy = make<ConcatInputSection>(*isec);
- copy->data = data.slice(off, recordSize);
- subsections.push_back({off, copy});
+ for (uint64_t off = 0; off < data.size(); off += recordSize) {
+ auto *isec = make<ConcatInputSection>(
+ section, data.slice(off, recordSize), align);
+ subsections.push_back({off, isec});
}
};
InputSection *isec;
if (sectionType(sec.flags) == S_CSTRING_LITERALS) {
- isec =
- make<CStringInputSection>(segname, name, this, data, align, flags);
+ isec = make<CStringInputSection>(section, data, align);
// FIXME: parallelize this?
cast<CStringInputSection>(isec)->splitIntoPieces();
} else {
- isec = make<WordLiteralInputSection>(segname, name, this, data, align,
- flags);
+ isec = make<WordLiteralInputSection>(section, data, align);
}
- sections.back().subsections.push_back({0, isec});
+ sections.back()->subsections.push_back({0, isec});
} else if (auto recordSize = getRecordSize(segname, name)) {
splitRecords(*recordSize);
if (name == section_names::compactUnwind)
- compactUnwindSection = §ions.back();
+ compactUnwindSection = sections.back();
} else if (segname == segment_names::llvm) {
if (name == "__cg_profile" && config->callGraphProfileSort) {
TimeTraceScope timeScope("Parsing call graph section");
// spurious duplicate symbol errors, we do not parse these sections.
// TODO: Evaluate whether the bitcode metadata is needed.
} else {
- auto *isec =
- make<ConcatInputSection>(segname, name, this, data, align, flags);
+ auto *isec = make<ConcatInputSection>(section, data, align);
if (isDebugSection(isec->getFlags()) &&
isec->getSegName() == segment_names::dwarf) {
// Instead of emitting DWARF sections, we emit STABS symbols to the
// parsing their relocations unnecessarily.
debugSections.push_back(isec);
} else {
- sections.back().subsections.push_back({0, isec});
+ sections.back()->subsections.push_back({0, isec});
}
}
}
referentOffset = totalAddend - referentSecHead.addr;
}
Subsections &referentSubsections =
- sections[relInfo.r_symbolnum - 1].subsections;
+ sections[relInfo.r_symbolnum - 1]->subsections;
r.referent =
findContainingSubsection(referentSubsections, &referentOffset);
r.addend = referentOffset;
uint64_t referentOffset =
totalAddend - sectionHeaders[minuendInfo.r_symbolnum - 1].addr;
Subsections &referentSubsectVec =
- sections[minuendInfo.r_symbolnum - 1].subsections;
+ sections[minuendInfo.r_symbolnum - 1]->subsections;
p.referent =
findContainingSubsection(referentSubsectVec, &referentOffset);
p.addend = referentOffset;
StringRef name = strtab + sym.n_strx;
if ((sym.n_type & N_TYPE) == N_SECT) {
- Subsections &subsections = sections[sym.n_sect - 1].subsections;
+ Subsections &subsections = sections[sym.n_sect - 1]->subsections;
// parseSections() may have chosen not to parse this section.
if (subsections.empty())
continue;
}
for (size_t i = 0; i < sections.size(); ++i) {
- Subsections &subsections = sections[i].subsections;
+ Subsections &subsections = sections[i]->subsections;
if (subsections.empty())
continue;
InputSection *lastIsec = subsections.back().isec;
: InputFile(OpaqueKind, mb) {
const auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
ArrayRef<uint8_t> data = {buf, mb.getBufferSize()};
- ConcatInputSection *isec =
- make<ConcatInputSection>(segName.take_front(16), sectName.take_front(16),
- /*file=*/this, data);
+ sections.push_back(make<Section>(/*file=*/this, segName.take_front(16),
+ sectName.take_front(16),
+ /*flags=*/0, /*addr=*/0));
+ Section §ion = *sections.back();
+ ConcatInputSection *isec = make<ConcatInputSection>(section, data);
isec->live = true;
- sections.push_back(0);
- sections.back().subsections.push_back({0, isec});
+ section.subsections.push_back({0, isec});
}
ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName,
// The relocations may refer to the symbols, so we parse them after we have
// parsed all the symbols.
for (size_t i = 0, n = sections.size(); i < n; ++i)
- if (!sections[i].subsections.empty())
+ if (!sections[i]->subsections.empty())
parseRelocations(sectionHeaders, sectionHeaders[i],
- sections[i].subsections);
+ sections[i]->subsections);
parseDebugInfo();
if (compactUnwindSection)
};
using Subsections = std::vector<Subsection>;
+class InputFile;
struct Section {
- uint64_t address = 0;
+ InputFile *file;
+ StringRef segname;
+ StringRef name;
+ uint32_t flags;
+ uint64_t addr;
Subsections subsections;
- Section(uint64_t addr) : address(addr){};
+
+ Section(InputFile *file, StringRef segname, StringRef name, uint32_t flags,
+ uint64_t addr)
+ : file(file), segname(segname), name(name), flags(flags), addr(addr) {}
+ // Ensure pointers to Sections are never invalidated.
+ Section(const Section &) = delete;
+ Section &operator=(const Section &) = delete;
+ Section(Section &&) = delete;
+ Section &operator=(Section &&) = delete;
};
// Represents a call graph profile edge.
MemoryBufferRef mb;
std::vector<Symbol *> symbols;
- std::vector<Section> sections;
+ std::vector<Section *> sections;
// If not empty, this stores the name of the archive containing this file.
// We use this string for creating error messages.
}
}
+ConcatInputSection *macho::makeSyntheticInputSection(StringRef segName,
+ StringRef sectName,
+ uint32_t flags,
+ ArrayRef<uint8_t> data,
+ uint32_t align) {
+ Section §ion =
+ *make<Section>(/*file=*/nullptr, segName, sectName, flags, /*addr=*/0);
+ auto isec = make<ConcatInputSection>(section, data, align);
+ section.subsections.push_back({0, isec});
+ return isec;
+}
+
void CStringInputSection::splitIntoPieces() {
size_t off = 0;
StringRef s = toStringRef(data);
return piece.outSecOff + addend;
}
-WordLiteralInputSection::WordLiteralInputSection(StringRef segname,
- StringRef name,
- InputFile *file,
+WordLiteralInputSection::WordLiteralInputSection(const Section §ion,
ArrayRef<uint8_t> data,
- uint32_t align, uint32_t flags)
- : InputSection(WordLiteralKind, segname, name, file, data, align, flags) {
- switch (sectionType(flags)) {
+ uint32_t align)
+ : InputSection(WordLiteralKind, section, data, align) {
+ switch (sectionType(getFlags())) {
case S_4BYTE_LITERALS:
power2LiteralSize = 2;
break;
class InputSection {
public:
- enum Kind {
+ enum Kind : uint8_t {
ConcatKind,
CStringLiteralKind,
WordLiteralKind,
};
- Kind kind() const { return shared->sectionKind; }
+ Kind kind() const { return sectionKind; }
virtual ~InputSection() = default;
virtual uint64_t getSize() const { return data.size(); }
virtual bool empty() const { return data.empty(); }
- InputFile *getFile() const { return shared->file; }
- StringRef getName() const { return shared->name; }
- StringRef getSegName() const { return shared->segname; }
- uint32_t getFlags() const { return shared->flags; }
+ InputFile *getFile() const { return section.file; }
+ StringRef getName() const { return section.name; }
+ StringRef getSegName() const { return section.segname; }
+ uint32_t getFlags() const { return section.flags; }
uint64_t getFileSize() const;
// Translates \p off -- an offset relative to this InputSection -- into an
// offset from the beginning of its parent OutputSection.
virtual InputSection *canonical() { return this; }
virtual const InputSection *canonical() const { return this; }
- OutputSection *parent = nullptr;
+protected:
+ InputSection(Kind kind, const Section §ion, ArrayRef<uint8_t> data,
+ uint32_t align)
+ : sectionKind(kind), align(align), data(data), section(section) {}
- uint32_t align = 1;
+ InputSection(const InputSection &rhs)
+ : sectionKind(rhs.sectionKind), align(rhs.align), data(rhs.data),
+ section(rhs.section) {}
+
+ Kind sectionKind;
+
+public:
// is address assigned?
bool isFinal = false;
+ uint32_t align = 1;
+ OutputSection *parent = nullptr;
ArrayRef<uint8_t> data;
std::vector<Reloc> relocs;
// The symbols that belong to this InputSection, sorted by value. With
llvm::TinyPtrVector<Defined *> symbols;
protected:
- // The fields in this struct are immutable. Since we create a lot of
- // InputSections with identical values for them (due to
- // .subsections_via_symbols), factoring them out into a shared struct reduces
- // memory consumption and makes copying cheaper.
- struct Shared {
- InputFile *file;
- StringRef name;
- StringRef segname;
- uint32_t flags;
- Kind sectionKind;
- Shared(InputFile *file, StringRef name, StringRef segname, uint32_t flags,
- Kind kind)
- : file(file), name(name), segname(segname), flags(flags),
- sectionKind(kind) {}
- };
-
- InputSection(Kind kind, StringRef segname, StringRef name, InputFile *file,
- ArrayRef<uint8_t> data, uint32_t align, uint32_t flags)
- : align(align), data(data),
- shared(make<Shared>(file, name, segname, flags, kind)) {}
-
- InputSection(const InputSection &rhs)
- : align(rhs.align), data(rhs.data), shared(rhs.shared) {}
-
- const Shared *const shared;
+ const Section §ion;
};
// ConcatInputSections are combined into (Concat)OutputSections through simple
// contents merged before output.
class ConcatInputSection final : public InputSection {
public:
- ConcatInputSection(StringRef segname, StringRef name, InputFile *file,
- ArrayRef<uint8_t> data, uint32_t align = 1,
- uint32_t flags = 0)
- : InputSection(ConcatKind, segname, name, file, data, align, flags) {}
-
- ConcatInputSection(StringRef segname, StringRef name)
- : ConcatInputSection(segname, name, /*file=*/nullptr,
- /*data=*/{},
- /*align=*/1, /*flags=*/0) {}
+ ConcatInputSection(const Section §ion, ArrayRef<uint8_t> data,
+ uint32_t align = 1)
+ : InputSection(ConcatKind, section, data, align) {}
uint64_t getOffset(uint64_t off) const override { return outSecOff + off; }
uint64_t getVA() const { return InputSection::getVA(0); }
uint64_t outSecOff = 0;
};
+// Initialize a fake InputSection that does not belong to any InputFile.
+ConcatInputSection *makeSyntheticInputSection(StringRef segName,
+ StringRef sectName,
+ uint32_t flags = 0,
+ ArrayRef<uint8_t> data = {},
+ uint32_t align = 1);
+
// Helper functions to make it easy to sprinkle asserts.
inline bool shouldOmitFromOutput(InputSection *isec) {
// conservative behavior we can certainly implement that.
class CStringInputSection final : public InputSection {
public:
- CStringInputSection(StringRef segname, StringRef name, InputFile *file,
- ArrayRef<uint8_t> data, uint32_t align, uint32_t flags)
- : InputSection(CStringLiteralKind, segname, name, file, data, align,
- flags) {}
+ CStringInputSection(const Section §ion, ArrayRef<uint8_t> data,
+ uint32_t align)
+ : InputSection(CStringLiteralKind, section, data, align) {}
uint64_t getOffset(uint64_t off) const override;
bool isLive(uint64_t off) const override { return getStringPiece(off).live; }
void markLive(uint64_t off) override { getStringPiece(off).live = true; }
class WordLiteralInputSection final : public InputSection {
public:
- WordLiteralInputSection(StringRef segname, StringRef name, InputFile *file,
- ArrayRef<uint8_t> data, uint32_t align,
- uint32_t flags);
+ WordLiteralInputSection(const Section §ion, ArrayRef<uint8_t> data,
+ uint32_t align);
uint64_t getOffset(uint64_t off) const override;
bool isLive(uint64_t off) const override {
return live[off >> power2LiteralSize];
}
if (!osec) {
- ConcatInputSection *isec = make<ConcatInputSection>(segName, sectName);
+ ConcatInputSection *isec = makeSyntheticInputSection(segName, sectName);
// This runs after markLive() and is only called for Undefineds that are
// live. Marking the isec live ensures an OutputSection is created that the
SyntheticSection::SyntheticSection(const char *segname, const char *name)
: OutputSection(SyntheticKind, name) {
std::tie(this->segname, this->name) = maybeRenameSection({segname, name});
- isec = make<ConcatInputSection>(segname, name);
+ isec = makeSyntheticInputSection(segname, name);
isec->parent = this;
syntheticSections.push_back(this);
}
// For each code subsection find 'data in code' entries residing in it.
// Compute the new offset values as
// <offset within subsection> + <subsection address> - <__TEXT address>.
- for (const Section §ion : objFile->sections) {
- for (const Subsection &subsec : section.subsections) {
+ for (const Section *section : objFile->sections) {
+ for (const Subsection &subsec : section->subsections) {
const InputSection *isec = subsec.isec;
if (!isCodeSection(isec))
continue;
if (cast<ConcatInputSection>(isec)->shouldOmitFromOutput())
continue;
- const uint64_t beginAddr = section.address + subsec.offset;
+ const uint64_t beginAddr = section->addr + subsec.offset;
auto it = llvm::lower_bound(
entries, beginAddr,
[](const MachO::data_in_code_entry &entry, uint64_t addr) {
// dyld to cache an address to the image loader it uses.
uint8_t *arr = bAlloc().Allocate<uint8_t>(target->wordSize);
memset(arr, 0, target->wordSize);
- in.imageLoaderCache = make<ConcatInputSection>(
- segment_names::data, section_names::data, /*file=*/nullptr,
+ in.imageLoaderCache = makeSyntheticInputSection(
+ segment_names::data, section_names::data, S_REGULAR,
ArrayRef<uint8_t>{arr, target->wordSize},
- /*align=*/target->wordSize, /*flags=*/S_REGULAR);
+ /*align=*/target->wordSize);
// References from dyld are not visible to us, so ensure this section is
// always treated as live.
in.imageLoaderCache->live = true;