Skip to content

[lld-macho][NFC] Refactor ObjCSelRefsSection out of ObjCStubsSection #83878

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

Merged
merged 3 commits into from
Mar 10, 2024
Merged
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
105 changes: 59 additions & 46 deletions lld/MachO/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -806,26 +806,10 @@ void StubHelperSection::setUp() {
dyldPrivate->used = true;
}

ObjCStubsSection::ObjCStubsSection()
: SyntheticSection(segment_names::text, section_names::objcStubs) {
flags = S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
align = config->objcStubsMode == ObjCStubsMode::fast
? target->objcStubsFastAlignment
: target->objcStubsSmallAlignment;
}

bool ObjCStubsSection::isObjCStubSymbol(Symbol *sym) {
return sym->getName().starts_with(symbolPrefix);
}
ObjCSelRefsSection::ObjCSelRefsSection()
: SyntheticSection(segment_names::data, section_names::objcSelrefs) {}

StringRef ObjCStubsSection::getMethname(Symbol *sym) {
assert(isObjCStubSymbol(sym) && "not an objc stub");
auto name = sym->getName();
StringRef methname = name.drop_front(symbolPrefix.size());
return methname;
}

void ObjCStubsSection::initialize() {
void ObjCSelRefsSection::initialize() {
// Do not fold selrefs without ICF.
if (config->icfLevel == ICFLevel::none)
return;
Expand All @@ -852,33 +836,62 @@ void ObjCStubsSection::initialize() {
}
}

ConcatInputSection *ObjCSelRefsSection::makeSelRef(StringRef methname) {
auto methnameOffset =
in.objcMethnameSection->getStringOffset(methname).outSecOff;

size_t wordSize = target->wordSize;
uint8_t *selrefData = bAlloc().Allocate<uint8_t>(wordSize);
write64le(selrefData, methnameOffset);
ConcatInputSection *objcSelref =
makeSyntheticInputSection(segment_names::data, section_names::objcSelrefs,
S_LITERAL_POINTERS | S_ATTR_NO_DEAD_STRIP,
ArrayRef<uint8_t>{selrefData, wordSize},
/*align=*/wordSize);
objcSelref->live = true;
objcSelref->relocs.push_back({/*type=*/target->unsignedRelocType,
/*pcrel=*/false, /*length=*/3,
/*offset=*/0,
/*addend=*/static_cast<int64_t>(methnameOffset),
/*referent=*/in.objcMethnameSection->isec});
objcSelref->parent = ConcatOutputSection::getOrCreateForInput(objcSelref);
inputSections.push_back(objcSelref);
objcSelref->isFinal = true;
methnameToSelref[CachedHashStringRef(methname)] = objcSelref;
return objcSelref;
}

ConcatInputSection *ObjCSelRefsSection::getSelRef(StringRef methname) {
auto it = methnameToSelref.find(CachedHashStringRef(methname));
if (it == methnameToSelref.end())
return nullptr;
return it->second;
}

ObjCStubsSection::ObjCStubsSection()
: SyntheticSection(segment_names::text, section_names::objcStubs) {
flags = S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
align = config->objcStubsMode == ObjCStubsMode::fast
? target->objcStubsFastAlignment
: target->objcStubsSmallAlignment;
}

bool ObjCStubsSection::isObjCStubSymbol(Symbol *sym) {
return sym->getName().starts_with(symbolPrefix);
}

StringRef ObjCStubsSection::getMethname(Symbol *sym) {
assert(isObjCStubSymbol(sym) && "not an objc stub");
auto name = sym->getName();
StringRef methname = name.drop_front(symbolPrefix.size());
return methname;
}

void ObjCStubsSection::addEntry(Symbol *sym) {
StringRef methname = getMethname(sym);
// We create a selref entry for each unique methname.
if (!methnameToSelref.count(CachedHashStringRef(methname))) {
auto methnameOffset =
in.objcMethnameSection->getStringOffset(methname).outSecOff;

size_t wordSize = target->wordSize;
uint8_t *selrefData = bAlloc().Allocate<uint8_t>(wordSize);
write64le(selrefData, methnameOffset);
auto *objcSelref = makeSyntheticInputSection(
segment_names::data, section_names::objcSelrefs,
S_LITERAL_POINTERS | S_ATTR_NO_DEAD_STRIP,
ArrayRef<uint8_t>{selrefData, wordSize},
/*align=*/wordSize);
objcSelref->live = true;
objcSelref->relocs.push_back(
{/*type=*/target->unsignedRelocType,
/*pcrel=*/false, /*length=*/3,
/*offset=*/0,
/*addend=*/static_cast<int64_t>(methnameOffset),
/*referent=*/in.objcMethnameSection->isec});
objcSelref->parent = ConcatOutputSection::getOrCreateForInput(objcSelref);
inputSections.push_back(objcSelref);
objcSelref->isFinal = true;
methnameToSelref[CachedHashStringRef(methname)] = objcSelref;
}
if (!in.objcSelRefs->getSelRef(methname))
in.objcSelRefs->makeSelRef(methname);

auto stubSize = config->objcStubsMode == ObjCStubsMode::fast
? target->objcStubsFastSize
Expand Down Expand Up @@ -927,9 +940,9 @@ void ObjCStubsSection::writeTo(uint8_t *buf) const {
Defined *sym = symbols[i];

auto methname = getMethname(sym);
auto j = methnameToSelref.find(CachedHashStringRef(methname));
assert(j != methnameToSelref.end());
auto selrefAddr = j->second->getVA(0);
InputSection *selRef = in.objcSelRefs->getSelRef(methname);
assert(selRef != nullptr && "no selref for methname");
auto selrefAddr = selRef->getVA(0);
target->writeObjCMsgSendStub(buf + stubOffset, sym, in.objcStubs->addr,
stubOffset, selrefAddr, objcMsgSend);
}
Expand Down
24 changes: 22 additions & 2 deletions lld/MachO/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,27 @@ class StubHelperSection final : public SyntheticSection {
Defined *dyldPrivate = nullptr;
};

class ObjCSelRefsSection final : public SyntheticSection {
public:
ObjCSelRefsSection();
void initialize();

// This SyntheticSection does not do directly write data to the output, it is
// just a placeholder for easily creating SyntheticInputSection's which will
// be inserted into inputSections and handeled by the default writing
// mechanism.
uint64_t getSize() const override { return 0; }
bool isNeeded() const override { return false; }
void writeTo(uint8_t *buf) const override {}

ConcatInputSection *getSelRef(StringRef methname);
ConcatInputSection *makeSelRef(StringRef methname);

private:
llvm::DenseMap<llvm::CachedHashStringRef, ConcatInputSection *>
methnameToSelref;
};

// Objective-C stubs are hoisted objc_msgSend calls per selector called in the
// program. Apple Clang produces undefined symbols to each stub, such as
// '_objc_msgSend$foo', which are then synthesized by the linker. The stubs
Expand All @@ -324,7 +345,6 @@ class StubHelperSection final : public SyntheticSection {
class ObjCStubsSection final : public SyntheticSection {
public:
ObjCStubsSection();
void initialize();
void addEntry(Symbol *sym);
uint64_t getSize() const override;
bool isNeeded() const override { return !symbols.empty(); }
Expand All @@ -338,7 +358,6 @@ class ObjCStubsSection final : public SyntheticSection {

private:
std::vector<Defined *> symbols;
llvm::DenseMap<llvm::CachedHashStringRef, InputSection *> methnameToSelref;
Symbol *objcMsgSend = nullptr;
};

Expand Down Expand Up @@ -794,6 +813,7 @@ struct InStruct {
LazyPointerSection *lazyPointers = nullptr;
StubsSection *stubs = nullptr;
StubHelperSection *stubHelper = nullptr;
ObjCSelRefsSection *objcSelRefs = nullptr;
ObjCStubsSection *objcStubs = nullptr;
UnwindInfoSection *unwindInfo = nullptr;
ObjCImageInfoSection *objCImageInfo = nullptr;
Expand Down
3 changes: 2 additions & 1 deletion lld/MachO/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ static void addNonWeakDefinition(const Defined *defined) {

void Writer::scanSymbols() {
TimeTraceScope timeScope("Scan symbols");
in.objcStubs->initialize();
in.objcSelRefs->initialize();
for (Symbol *sym : symtab->getSymbols()) {
if (auto *defined = dyn_cast<Defined>(sym)) {
if (!defined->isLive())
Expand Down Expand Up @@ -1359,6 +1359,7 @@ void macho::createSyntheticSections() {
in.got = make<GotSection>();
in.tlvPointers = make<TlvPointerSection>();
in.stubs = make<StubsSection>();
in.objcSelRefs = make<ObjCSelRefsSection>();
in.objcStubs = make<ObjCStubsSection>();
in.unwindInfo = makeUnwindInfoSection();
in.objCImageInfo = make<ObjCImageInfoSection>();
Expand Down