[clang] [lld] [lld-macho][draft]Allow folding entries with identical FDE (PR #216895)

Vy Nguyen via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 17:17:48 PDT 2026


================
@@ -613,32 +638,33 @@ void macho::foldIdenticalSections(bool onlyCfStrings) {
       for (Defined *d : isec->symbols)
         if (d->unwindEntry())
           foldable.push_back(d->unwindEntry());
-
-      // Some sections have embedded addends that foil ICF's hashing / equality
-      // checks. (We can ignore embedded addends when doing ICF because the same
-      // information gets recorded in our Reloc structs.) We therefore create a
-      // mutable copy of the section data and zero out the embedded addends
-      // before performing any hashing / equality checks.
-      if (isFoldableWithAddendsRemoved) {
-        // We have to do this copying serially as the BumpPtrAllocator is not
-        // thread-safe. FIXME: Make a thread-safe allocator.
-        MutableArrayRef<uint8_t> copy = isec->data.copy(bAlloc());
-        for (const Relocation &r : isec->relocs)
-          target->relocateOne(copy.data() + r.offset, r, /*va=*/0,
-                              /*relocVA=*/0);
-        isec->data = copy;
-      }
-    } else if (!isEhFrameSection(isec)) {
-      // EH frames are gathered as foldables from unwindEntry above; give a
-      // unique ID to everything else.
+    } else if (isEhFrameSection(isec)) {
+      // __eh_frame contains two types of records: FDEs and CIEs.
+      // Functions point to FDEs, which are already collected above via unwindEntry().
+      // CIEs are shared headers and are not attached to individual functions.
+      // Collect only CIEs here so they can also be hashed and deduplicated.
+      auto *obj = dyn_cast_or_null<ObjFile>(isec->getFile());
+      if (!onlyCfStrings && obj && !obj->fdes.contains(isec) &&
+          !isec->shouldOmitFromOutput())
+        foldable.push_back(isec);
+    } else {
+      // Give a unique ID to everything else.
       isec->icfEqClass[0] = ++icfUniqueID;
     }
   }
   parallelForEach(foldable, [](ConcatInputSection *isec) {
     assert(isec->icfEqClass[0] == 0); // don't overwrite a unique ID!
+    uint64_t hash;
+    if (isFoldableWithAddendsRemoved(isec)) {
+      SmallVector<uint8_t, 64> stackBuf;
----------------
oontvoo wrote:

> But if the section size is larger than 64 bytes, then we will have a heap allocation, right

Yes. But they're typically not larger than 64.

Specifically,
- __objc_selrefs and __objc_classrefs are exactly 8 bytes
- __cfstring : 32 bytes max
```
struct __CFString {
  void *isa;            // 8 bytes
  uintptr_t flags;      // 8 bytes 
  const char *str;      // 8 bytes 
  uintptr_t length;     // 8 bytes 
};                      
```
- CIE:
```
struct CIE {
  uint8_t fdePtrEnc = 0;       
  uint8_t lsdaPtrEnc = 0;      
  uint8_t personalityEnc = 0;
  uint8_t funcPtrSize = 0;    
  uint8_t lsdaPtrSize = 0;    
  Symbol *personalitySymbol = nullptr;
}; // 16 bytes max (with alignment)
```
- FDE: ~56
```
Length: 4
CIE Pointer: 4
func offset: 4
function size: 4
augmentation len: 1
lsda ptr: 4
DW_CFA_advance_loc: 1
DW_CFA_def_cfa_offset: 2
DW_CFA_offset (FP): 2
[DW_CFA_offset (LR): 2
[DW_CFA_offset (x19): 2
< .... more here...>
[Padding: 3B]
---------------------------
Total: ~40 to 56 bytes in binary
```

-  (other "regular sections" are handled in the "else" below)

https://github.com/llvm/llvm-project/pull/216895


More information about the llvm-commits mailing list