@@ -825,10 +825,43 @@ StringRef ObjCStubsSection::getMethName(Symbol *sym) {
825
825
return methname;
826
826
}
827
827
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
+
828
855
void ObjCStubsSection::addEntry (Symbol *sym) {
829
856
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
+ }
832
865
833
866
auto stubSize = config->objcStubsMode == ObjCStubsMode::fast
834
867
? target->objcStubsFastSize
@@ -863,10 +896,12 @@ void ObjCStubsSection::setUp() {
863
896
in.stubs ->addEntry (objcMsgSend);
864
897
}
865
898
866
- size_t size = offsets .size () * target->wordSize ;
899
+ size_t size = methnameToidxOffsetPair .size () * target->wordSize ;
867
900
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
+ }
870
905
871
906
in.objcSelrefs =
872
907
makeSyntheticInputSection (segment_names::data, section_names::objcSelrefs,
@@ -875,12 +910,13 @@ void ObjCStubsSection::setUp() {
875
910
/* align=*/ target->wordSize );
876
911
in.objcSelrefs ->live = true ;
877
912
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;
879
915
in.objcSelrefs ->relocs .push_back (
880
916
{/* type=*/ target->unsignedRelocType ,
881
917
/* 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 ,
884
920
/* referent=*/ in.objcMethnameSection ->isec });
885
921
}
886
922
@@ -904,8 +940,22 @@ void ObjCStubsSection::writeTo(uint8_t *buf) const {
904
940
uint64_t stubOffset = 0 ;
905
941
for (size_t i = 0 , n = symbols.size (); i < n; ++i) {
906
942
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
+ }
907
957
target->writeObjCMsgSendStub (buf + stubOffset, sym, in.objcStubs ->addr ,
908
- stubOffset, in. objcSelrefs -> getVA (), i ,
958
+ stubOffset, selBaseAddr, selIndex ,
909
959
objcMsgSend);
910
960
}
911
961
}
0 commit comments