@@ -45,6 +45,7 @@ class ICF {
45
45
const ConcatInputSection *ib);
46
46
bool equalsVariable (const ConcatInputSection *ia,
47
47
const ConcatInputSection *ib);
48
+ void applySafeThunksToRange (size_t begin, size_t end);
48
49
49
50
// ICF needs a copy of the inputs vector because its equivalence-class
50
51
// segregation algorithm destroys the proper sequence.
@@ -251,6 +252,38 @@ void ICF::forEachClassRange(size_t begin, size_t end,
251
252
}
252
253
}
253
254
255
+ // Given a range of identical icfInputs's, replace address significant functions
256
+ // with a thunk that is just a direct branch to the first function in the
257
+ // series. This way we end up we keep only one main body of the function but we
258
+ // still retain address uniqueness of rellevant functions by having them be a
259
+ // direct branch thunk rather than contain a full copy of the actual function
260
+ // body.
261
+ void ICF::applySafeThunksToRange (size_t begin, size_t end) {
262
+ // If we need to create a unique ICF thunk, use the first section as the
263
+ // section that all thunks will branch to.
264
+ ConcatInputSection *masterIsec = icfInputs[begin];
265
+
266
+ uint32_t keepUniqueCount = masterIsec->keepUnique ? 1 : 0 ;
267
+ for (size_t i = begin + 1 ; i < end; ++i) {
268
+ ConcatInputSection *isec = icfInputs[i];
269
+ if (isec->keepUnique )
270
+ ++keepUniqueCount;
271
+
272
+ // We create thunks for the 2nd, 3rd, ... keepUnique sections. The first
273
+ // keepUnique section we leave as is - as it will not end up sharing an
274
+ // address with any other keepUnique section.
275
+ if (keepUniqueCount >= 2 && isec->keepUnique ) {
276
+ ConcatInputSection *thunk =
277
+ makeSyntheticInputSection (isec->getSegName (), isec->getName ());
278
+ target->initICFSafeThunkBody (thunk, masterIsec);
279
+
280
+ thunk->foldIdentical (isec);
281
+
282
+ addInputSection (thunk);
283
+ }
284
+ }
285
+ }
286
+
254
287
// Split icfInputs into shards, then parallelize invocation of FUNC on subranges
255
288
// with matching equivalence class
256
289
void ICF::forEachClass (llvm::function_ref<void (size_t , size_t )> func) {
@@ -335,9 +368,20 @@ void ICF::run() {
335
368
forEachClass ([&](size_t begin, size_t end) {
336
369
if (end - begin < 2 )
337
370
return ;
371
+ bool useSafeThunks = config->icfLevel == ICFLevel::safe_thunks;
372
+
373
+ // For ICF level safe_thunks, replace keepUnique function bodies with
374
+ // thunks. For all other ICF levles, directly merge the functions.
375
+ if (useSafeThunks)
376
+ applySafeThunksToRange (begin, end);
377
+
338
378
ConcatInputSection *beginIsec = icfInputs[begin];
339
- for (size_t i = begin + 1 ; i < end; ++i)
379
+ for (size_t i = begin + 1 ; i < end; ++i) {
380
+ // When using safe_thunks, keepUnique inputs are already handeled above
381
+ if (useSafeThunks && icfInputs[i]->keepUnique )
382
+ continue ;
340
383
beginIsec->foldIdentical (icfInputs[i]);
384
+ }
341
385
});
342
386
}
343
387
@@ -421,11 +465,22 @@ void macho::foldIdenticalSections(bool onlyCfStrings) {
421
465
// can still fold it.
422
466
bool hasFoldableFlags = (isSelRefsSection (isec) ||
423
467
sectionType (isec->getFlags ()) == MachO::S_REGULAR);
468
+
469
+ bool isCodeSec = isCodeSection (isec);
470
+
471
+ // When keepUnique is true, the section is not foldable. Unless we are at
472
+ // icf level safe_thunks, in which case we still want to fold code sections.
473
+ // When using safe_thunks we'll apply the safe_thunks logic at merge time
474
+ // based on the 'keepUnique' flag.
475
+ bool noUniqueRequirement =
476
+ !isec->keepUnique ||
477
+ ((config->icfLevel == ICFLevel::safe_thunks) && isCodeSec);
478
+
424
479
// FIXME: consider non-code __text sections as foldable?
425
480
bool isFoldable = (!onlyCfStrings || isCfStringSection (isec)) &&
426
- (isCodeSection (isec) || isFoldableWithAddendsRemoved ||
481
+ (isCodeSec || isFoldableWithAddendsRemoved ||
427
482
isGccExceptTabSection (isec)) &&
428
- !isec-> keepUnique && !isec->hasAltEntry &&
483
+ noUniqueRequirement && !isec->hasAltEntry &&
429
484
!isec->shouldOmitFromOutput () && hasFoldableFlags;
430
485
if (isFoldable) {
431
486
foldable.push_back (isec);
0 commit comments