Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Apr 4, 2025

Conversation

alx32
Copy link
Contributor

@alx32 alx32 commented Apr 2, 2025

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.

@alx32 alx32 requested review from keith and kyulee-com April 2, 2025 00:27
@alx32 alx32 marked this pull request as ready for review April 2, 2025 00:37
@llvmbot
Copy link
Member

llvmbot commented Apr 2, 2025

@llvm/pr-subscribers-lld-macho

@llvm/pr-subscribers-lld

Author: None (alx32)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/134010.diff

2 Files Affected:

  • (modified) lld/MachO/OutputSegment.cpp (+22-10)
  • (modified) lld/test/MachO/arm64-objc-stubs.s (+18-10)
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

@alx32 alx32 requested review from NuriAmari and DataCorrupted April 2, 2025 00:38
Copy link
Contributor

@kyulee-com kyulee-com left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@alx32 alx32 merged commit 74a7802 into llvm:main Apr 4, 2025
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants