@@ -136,17 +136,52 @@ std::optional<ObjCOptimizationHeader> GetObjCOptimizationHeader(SharedCache& cac
136136 return header;
137137}
138138
139+ std::optional<std::pair<uint64_t , LegacyObjCOptimizationHeader>> GetLegacyObjCOptimizationHeader (SharedCache& cache, VirtualMemoryReader& reader)
140+ {
141+ // In older versions the header lives in the `__TEXT,__objc_opt_ro` section within /usr/lib/libobjc.A.dylib
142+ auto libObjC = cache.GetImageWithName (" /usr/lib/libobjc.A.dylib" );
143+ if (!libObjC)
144+ return std::nullopt ;
145+
146+ // Convert the header's `char[16]` to a `string_view`.
147+ auto AsStringView = []<size_t N>(const char (&arr)[N]) {
148+ const char * end = std::find (arr, arr + N, ' \0 ' );
149+ return std::string_view (arr, end - arr);
150+ };
151+
152+ for (auto section : libObjC->header ->sections ) {
153+ if (AsStringView (section.segname ) != " __TEXT" || AsStringView (section.sectname ) != " __objc_opt_ro" )
154+ continue ;
155+
156+ LegacyObjCOptimizationHeader header = {};
157+ reader.Read (&header, section.addr , sizeof (LegacyObjCOptimizationHeader));
158+
159+ // The `relativeMethodSelectorBaseAddressOffset` field was added in version 16 (the final version of this struct).
160+ if (header.version >= 16 )
161+ return {{section.addr , header}};
162+
163+ break ;
164+ }
165+
166+ return std::nullopt ;
167+ }
168+
139169uint64_t SharedCacheObjCProcessor::GetObjCRelativeMethodBaseAddress (ObjCReader* reader)
140170{
141171 // Try and retrieve the base address of the selector stuff.
142172 if (const auto controller = DSC::SharedCacheController::FromView (*m_data))
143173 {
144- auto baseAddress = controller->GetCache ().GetBaseAddress ();
145174 auto dangerReader = dynamic_cast <SharedCacheObjCReader*>(reader)->GetVMReader ();
146175 if (const auto header = GetObjCOptimizationHeader (controller->GetCache (), dangerReader); header.has_value ())
147176 {
177+ auto baseAddress = controller->GetCache ().GetBaseAddress ();
148178 m_customRelativeMethodSelectorBase = baseAddress + header->relativeMethodSelectorBaseAddressOffset ;
149179 }
180+ else if (const auto info = GetLegacyObjCOptimizationHeader (controller->GetCache (), dangerReader); info.has_value ())
181+ {
182+ const auto [optSectionAddr, header] = *info;
183+ m_customRelativeMethodSelectorBase = optSectionAddr + header.relativeMethodSelectorBaseAddressOffset ;
184+ }
150185 }
151186
152187 return m_customRelativeMethodSelectorBase.value_or (0 );
0 commit comments