[lld] [lld-macho] Fix code section ordering in output binary (PR #134010)

via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 1 17:27:13 PDT 2025


https://github.com/alx32 created https://github.com/llvm/llvm-project/pull/134010

In `OutputSegment.cpp`, we need to ensure a specific order for certain sections. The current sorting logic incorrectly prioritizes code sections over explicitly defined section orders. This is problematic because the `__objc_stubs` section is both a code section *and* has a specific ordering requirement. The current logic would incorrectly prioritize its code section status, causing it to be sorted *before* the `__stubs` section. This incorrect ordering breaks the branch extension algorithm, ultimately leading to linker failures due to relocation errors.

We also modify the `lld/test/MachO/arm64-objc-stubs.s` test to ensure correct section ordering.

>From 7d202a742ec643c9d82bffd0a4c267cec132382d Mon Sep 17 00:00:00 2001
From: Alex Borcan <alexborcan at fb.com>
Date: Tue, 1 Apr 2025 17:14:16 -0700
Subject: [PATCH] [lld][MachO] Fix section ordering

---
 lld/MachO/OutputSegment.cpp       | 32 +++++++++++++++++++++----------
 lld/test/MachO/arm64-objc-stubs.s | 28 +++++++++++++++++----------
 2 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/lld/MachO/OutputSegment.cpp b/lld/MachO/OutputSegment.cpp
index c320af3fb3177..185444673ae47 100644
--- a/lld/MachO/OutputSegment.cpp
+++ b/lld/MachO/OutputSegment.cpp
@@ -103,20 +103,32 @@ static int sectionOrder(OutputSection *osec) {
     // be the section that determines whether we need thunks or not.
     if (osec->name == section_names::text)
       return -6;
+
+    // Prioritize specific section ordering based on our knowledge. This ensures
+    // that certain sections are placed in a particular order, even if they
+    // are also categorized as code sections. This explicit ordering takes
+    // precedence over the general code section ordering.
+    int knownPriority =
+        StringSwitch<int>(osec->name)
+            .Case(section_names::stubs, -4)
+            .Case(section_names::stubHelper, -3)
+            .Case(section_names::objcStubs, -2)
+            .Case(section_names::initOffsets, -1)
+            .Case(section_names::unwindInfo,
+                  std::numeric_limits<int>::max() - 1)
+            .Case(section_names::ehFrame, std::numeric_limits<int>::max())
+            .Default(0);
+
+    if (knownPriority != 0)
+      return knownPriority;
+
     // Ensure all code sections are contiguous with `__text` for thunk
     // calculations.
-    if (sections::isCodeSection(osec->name, segment_names::text, osec->flags) &&
-        osec->name != section_names::stubHelper) {
+    if (sections::isCodeSection(osec->name, segment_names::text, osec->flags)) {
       return -5;
     }
-    return StringSwitch<int>(osec->name)
-        .Case(section_names::stubs, -4)
-        .Case(section_names::stubHelper, -3)
-        .Case(section_names::objcStubs, -2)
-        .Case(section_names::initOffsets, -1)
-        .Case(section_names::unwindInfo, std::numeric_limits<int>::max() - 1)
-        .Case(section_names::ehFrame, std::numeric_limits<int>::max())
-        .Default(osec->inputOrder);
+
+    return osec->inputOrder;
   } else if (segname == segment_names::data ||
              segname == segment_names::dataConst) {
     // For each thread spawned, dyld will initialize its TLVs by copying the
diff --git a/lld/test/MachO/arm64-objc-stubs.s b/lld/test/MachO/arm64-objc-stubs.s
index 1b8ebff924300..da25b1292faa6 100644
--- a/lld/test/MachO/arm64-objc-stubs.s
+++ b/lld/test/MachO/arm64-objc-stubs.s
@@ -1,22 +1,23 @@
 # REQUIRES: aarch64
 
 # RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t.o
-# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o
+# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -U _external_func
 # RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
-# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -dead_strip
+# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -dead_strip -U _external_func
 # RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
-# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_fast
+# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_fast -U _external_func
 # RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
 # RUN: llvm-otool -l %t.out | FileCheck %s --check-prefix=FASTALIGN
-# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_small
+# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_small -U _external_func
 # RUN: llvm-otool -vs __TEXT __objc_stubs  %t.out | FileCheck %s --check-prefix=SMALL
 # RUN: llvm-otool -l %t.out | FileCheck %s --check-prefix=SMALLALIGN
+# RUN: llvm-objdump --section-headers %t.out | FileCheck %s --check-prefix=SECTIONS
 
 # CHECK: Contents of (__TEXT,__objc_stubs) section
 
 # CHECK-NEXT: _objc_msgSend$foo:
 # CHECK-NEXT: adrp    x1, 8 ; 0x100008000
-# CHECK-NEXT: ldr     x1, [x1, #0x10]
+# CHECK-NEXT: ldr     x1, [x1, #0x18]
 # CHECK-NEXT: adrp    x16, 4 ; 0x100004000
 # CHECK-NEXT: ldr     x16, [x16]
 # CHECK-NEXT: br      x16
@@ -26,7 +27,7 @@
 
 # CHECK-NEXT: _objc_msgSend$length:
 # CHECK-NEXT: adrp    x1, 8 ; 0x100008000
-# CHECK-NEXT: ldr     x1, [x1, #0x18]
+# CHECK-NEXT: ldr     x1, [x1, #0x20]
 # CHECK-NEXT: adrp    x16, 4 ; 0x100004000
 # CHECK-NEXT: ldr     x16, [x16]
 # CHECK-NEXT: br      x16
@@ -44,13 +45,13 @@
 # FASTALIGN-NEXT:     align 2^5 (32)
 
 # SMALL: _objc_msgSend$foo:
-# SMALL-NEXT: adrp    x1, 4 ; 0x100004000
-# SMALL-NEXT: ldr     x1, [x1, #0x10]
+# SMALL-NEXT: adrp    x1, 8 ; 0x100008000
+# SMALL-NEXT: ldr     x1, [x1, #0x18]
 # SMALL-NEXT: b
 
 # SMALL-NEXT: _objc_msgSend$length:
-# SMALL-NEXT: adrp    x1, 4 ; 0x100004000
-# SMALL-NEXT: ldr     x1, [x1, #0x18]
+# SMALL-NEXT: adrp    x1, 8 ; 0x100008000
+# SMALL-NEXT: ldr     x1, [x1, #0x20]
 # SMALL-NEXT: b
 
 # SMALLALIGN:       sectname __objc_stubs
@@ -60,6 +61,12 @@
 # SMALLALIGN-NEXT:    offset
 # SMALLALIGN-NEXT:     align 2^2 (4)
 
+## Check correct section ordering
+# SECTIONS: Sections:
+# SECTIONS: __text
+# SECTIONS: __stubs
+# SECTIONS: __objc_stubs
+
 .section  __TEXT,__objc_methname,cstring_literals
 lselref1:
   .asciz  "foo"
@@ -81,4 +88,5 @@ _main:
   bl  _objc_msgSend$length
   bl  _objc_msgSend$foo
   bl  _objc_msgSend$foo
+  bl  _external_func
   ret



More information about the llvm-commits mailing list