Skip to content

Commit b7d9c36

Browse files
committed
[lld-macho] icf objc stubs
1 parent 28db5b1 commit b7d9c36

File tree

5 files changed

+77
-13
lines changed

5 files changed

+77
-13
lines changed

lld/MachO/SyntheticSections.cpp

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -825,10 +825,43 @@ StringRef ObjCStubsSection::getMethName(Symbol *sym) {
825825
return methname;
826826
}
827827

828+
void ObjCStubsSection::initialize() {
829+
// Do not fold selrefs without ICF.
830+
if (config->icfLevel == ICFLevel::none)
831+
return;
832+
833+
// Search methnames already referenced in __objc_selrefs
834+
// Map the name to the corresponding selref entry
835+
// which we will reuse when creating objc stubs.
836+
for (ConcatInputSection *isec : inputSections) {
837+
if (isec->shouldOmitFromOutput())
838+
continue;
839+
if (isec->getName() != "__objc_selrefs")
840+
continue;
841+
// We expect a single relocation per selref entry to __objc_methname that
842+
// might be aggregated.
843+
assert(isec->relocs.size() == 1);
844+
auto Reloc = isec->relocs[0];
845+
if (const auto *sym = Reloc.referent.dyn_cast<Symbol *>()) {
846+
if (const auto *d = dyn_cast<Defined>(sym)) {
847+
auto *cisec = cast<CStringInputSection>(d->isec);
848+
auto methname = cisec->getStringRefAtOffset(d->value);
849+
methnameToselref[methname] = isec;
850+
}
851+
}
852+
}
853+
}
854+
828855
void ObjCStubsSection::addEntry(Symbol *sym) {
829856
StringRef methname = getMethName(sym);
830-
offsets.push_back(
831-
in.objcMethnameSection->getStringOffset(methname).outSecOff);
857+
// We will create a selref entry for each unique methname.
858+
if (!methnameToselref.count(methname) &&
859+
!methnameToidxOffsetPair.count(methname)) {
860+
auto methnameOffset =
861+
in.objcMethnameSection->getStringOffset(methname).outSecOff;
862+
auto selIndex = methnameToidxOffsetPair.size();
863+
methnameToidxOffsetPair[methname] = {selIndex, methnameOffset};
864+
}
832865

833866
auto stubSize = config->objcStubsMode == ObjCStubsMode::fast
834867
? target->objcStubsFastSize
@@ -863,10 +896,12 @@ void ObjCStubsSection::setUp() {
863896
in.stubs->addEntry(objcMsgSend);
864897
}
865898

866-
size_t size = offsets.size() * target->wordSize;
899+
size_t size = methnameToidxOffsetPair.size() * target->wordSize;
867900
uint8_t *selrefsData = bAlloc().Allocate<uint8_t>(size);
868-
for (size_t i = 0, n = offsets.size(); i < n; ++i)
869-
write64le(&selrefsData[i * target->wordSize], offsets[i]);
901+
for (const auto &[methname, idxOffsetPair] : methnameToidxOffsetPair) {
902+
const auto &[idx, offset] = idxOffsetPair;
903+
write64le(&selrefsData[idx * target->wordSize], offset);
904+
}
870905

871906
in.objcSelrefs =
872907
makeSyntheticInputSection(segment_names::data, section_names::objcSelrefs,
@@ -875,12 +910,13 @@ void ObjCStubsSection::setUp() {
875910
/*align=*/target->wordSize);
876911
in.objcSelrefs->live = true;
877912

878-
for (size_t i = 0, n = offsets.size(); i < n; ++i) {
913+
for (const auto &[methname, idxOffsetPair] : methnameToidxOffsetPair) {
914+
const auto &[idx, offset] = idxOffsetPair;
879915
in.objcSelrefs->relocs.push_back(
880916
{/*type=*/target->unsignedRelocType,
881917
/*pcrel=*/false, /*length=*/3,
882-
/*offset=*/static_cast<uint32_t>(i * target->wordSize),
883-
/*addend=*/offsets[i] * in.objcMethnameSection->align,
918+
/*offset=*/static_cast<uint32_t>(idx * target->wordSize),
919+
/*addend=*/offset * in.objcMethnameSection->align,
884920
/*referent=*/in.objcMethnameSection->isec});
885921
}
886922

@@ -904,8 +940,22 @@ void ObjCStubsSection::writeTo(uint8_t *buf) const {
904940
uint64_t stubOffset = 0;
905941
for (size_t i = 0, n = symbols.size(); i < n; ++i) {
906942
Defined *sym = symbols[i];
943+
uint64_t selBaseAddr;
944+
uint64_t selIndex;
945+
946+
auto methname = getMethName(sym);
947+
auto j = methnameToselref.find(methname);
948+
if (j != methnameToselref.end()) {
949+
selBaseAddr = j->second->getVA(0);
950+
selIndex = 0;
951+
} else {
952+
auto k = methnameToidxOffsetPair.find(methname);
953+
assert(k != methnameToidxOffsetPair.end());
954+
selBaseAddr = in.objcSelrefs->getVA();
955+
selIndex = k->second.first;
956+
}
907957
target->writeObjCMsgSendStub(buf + stubOffset, sym, in.objcStubs->addr,
908-
stubOffset, in.objcSelrefs->getVA(), i,
958+
stubOffset, selBaseAddr, selIndex,
909959
objcMsgSend);
910960
}
911961
}

lld/MachO/SyntheticSections.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ class StubHelperSection final : public SyntheticSection {
324324
class ObjCStubsSection final : public SyntheticSection {
325325
public:
326326
ObjCStubsSection();
327+
void initialize();
327328
void addEntry(Symbol *sym);
328329
uint64_t getSize() const override;
329330
bool isNeeded() const override { return !symbols.empty(); }
@@ -337,7 +338,12 @@ class ObjCStubsSection final : public SyntheticSection {
337338

338339
private:
339340
std::vector<Defined *> symbols;
340-
std::vector<uint32_t> offsets;
341+
// Existing mapping from methname to selref (0 index is assumed).
342+
llvm::StringMap<InputSection *> methnameToselref;
343+
// Newly created mapping from methname to the pair of index (selref) and
344+
// offset (methname).
345+
llvm::MapVector<StringRef, std::pair<uint32_t, uint32_t>>
346+
methnameToidxOffsetPair;
341347
Symbol *objcMsgSend = nullptr;
342348
};
343349

lld/MachO/Writer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ static void addNonWeakDefinition(const Defined *defined) {
720720

721721
void Writer::scanSymbols() {
722722
TimeTraceScope timeScope("Scan symbols");
723+
in.objcStubs->initialize();
723724
for (Symbol *sym : symtab->getSymbols()) {
724725
if (auto *defined = dyn_cast<Defined>(sym)) {
725726
if (!defined->isLive())

lld/test/MachO/objc-selrefs.s

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
# SELREFS-NEXT: __TEXT:__objc_methname:length
2525
# SELREFS-EMPTY:
2626

27-
## We don't yet support dedup'ing implicitly-defined selrefs.
2827
# RUN: %lld -dylib -arch arm64 -lSystem --icf=all -o %t/explicit-and-implicit \
2928
# RUN: %t/explicit-selrefs-1.o %t/explicit-selrefs-2.o %t/implicit-selrefs.o
3029
# RUN: llvm-otool -vs __DATA __objc_selrefs %t/explicit-and-implicit \
@@ -43,8 +42,6 @@
4342
# EXPLICIT-AND-IMPLICIT: Contents of (__DATA,__objc_selrefs) section
4443
# EXPLICIT-AND-IMPLICIT-NEXT: __TEXT:__objc_methname:foo
4544
# EXPLICIT-AND-IMPLICIT-NEXT: __TEXT:__objc_methname:bar
46-
# NOTE: Ideally this wouldn't exist, but while it does it needs to point to the deduplicated string
47-
# EXPLICIT-AND-IMPLICIT-NEXT: __TEXT:__objc_methname:foo
4845
# EXPLICIT-AND-IMPLICIT-NEXT: __TEXT:__objc_methname:length
4946

5047
#--- explicit-selrefs-1.s

lld/test/MachO/x86-64-objc-stubs.s

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
# WARNING: warning: -objc_stubs_small is not yet implemented, defaulting to -objc_stubs_fast
1212

13+
# RUN: %lld -arch x86_64 -lSystem -o %t-icf.out --icf=all %t.o
14+
# RUN: llvm-otool -vs __DATA __objc_selrefs %t-icf.out | FileCheck %s --check-prefix=ICF
15+
1316
# CHECK: Sections:
1417
# CHECK: __got {{[0-9a-f]*}} [[#%x, GOTSTART:]] DATA
1518
# CHECK: __objc_selrefs {{[0-9a-f]*}} [[#%x, SELSTART:]] DATA
@@ -21,6 +24,13 @@
2124
# CHECK-NEXT: [[#%x, FOOSELREF:]] __TEXT:__objc_methname:foo
2225
# CHECK-NEXT: [[#%x, LENGTHSELREF:]] __TEXT:__objc_methname:length
2326

27+
# ICF: Contents of (__DATA,__objc_selrefs) section
28+
29+
# ICF-NEXT: {{[0-9a-f]*}} __TEXT:__objc_methname:foo
30+
# ICF-NEXT: {{[0-9a-f]*}} __TEXT:__objc_methname:bar
31+
# ICF-NEXT: {{[0-9a-f]*}} __TEXT:__objc_methname:length
32+
# ICF-EMPTY:
33+
2434
# CHECK: Contents of (__TEXT,__objc_stubs) section
2535

2636
# CHECK-NEXT: _objc_msgSend$foo:

0 commit comments

Comments
 (0)