Skip to content

Commit 74a7802

Browse files
authored
[lld-macho] Fix code section ordering in output binary (llvm#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.
1 parent 5271dea commit 74a7802

File tree

2 files changed

+40
-20
lines changed

2 files changed

+40
-20
lines changed

lld/MachO/OutputSegment.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,20 +103,32 @@ static int sectionOrder(OutputSection *osec) {
103103
// be the section that determines whether we need thunks or not.
104104
if (osec->name == section_names::text)
105105
return -6;
106+
107+
// Prioritize specific section ordering based on our knowledge. This ensures
108+
// that certain sections are placed in a particular order, even if they
109+
// are also categorized as code sections. This explicit ordering takes
110+
// precedence over the general code section ordering.
111+
int knownPriority =
112+
StringSwitch<int>(osec->name)
113+
.Case(section_names::stubs, -4)
114+
.Case(section_names::stubHelper, -3)
115+
.Case(section_names::objcStubs, -2)
116+
.Case(section_names::initOffsets, -1)
117+
.Case(section_names::unwindInfo,
118+
std::numeric_limits<int>::max() - 1)
119+
.Case(section_names::ehFrame, std::numeric_limits<int>::max())
120+
.Default(0);
121+
122+
if (knownPriority != 0)
123+
return knownPriority;
124+
106125
// Ensure all code sections are contiguous with `__text` for thunk
107126
// calculations.
108-
if (sections::isCodeSection(osec->name, segment_names::text, osec->flags) &&
109-
osec->name != section_names::stubHelper) {
127+
if (sections::isCodeSection(osec->name, segment_names::text, osec->flags)) {
110128
return -5;
111129
}
112-
return StringSwitch<int>(osec->name)
113-
.Case(section_names::stubs, -4)
114-
.Case(section_names::stubHelper, -3)
115-
.Case(section_names::objcStubs, -2)
116-
.Case(section_names::initOffsets, -1)
117-
.Case(section_names::unwindInfo, std::numeric_limits<int>::max() - 1)
118-
.Case(section_names::ehFrame, std::numeric_limits<int>::max())
119-
.Default(osec->inputOrder);
130+
131+
return osec->inputOrder;
120132
} else if (segname == segment_names::data ||
121133
segname == segment_names::dataConst) {
122134
// For each thread spawned, dyld will initialize its TLVs by copying the

lld/test/MachO/arm64-objc-stubs.s

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
# REQUIRES: aarch64
22

33
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t.o
4-
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o
4+
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -U _external_func
55
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
6-
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -dead_strip
6+
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -dead_strip -U _external_func
77
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
8-
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_fast
8+
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_fast -U _external_func
99
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
1010
# RUN: llvm-otool -l %t.out | FileCheck %s --check-prefix=FASTALIGN
11-
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_small
11+
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_small -U _external_func
1212
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s --check-prefix=SMALL
1313
# RUN: llvm-otool -l %t.out | FileCheck %s --check-prefix=SMALLALIGN
14+
# RUN: llvm-objdump --section-headers %t.out | FileCheck %s --check-prefix=SECTIONS
1415

1516
# CHECK: Contents of (__TEXT,__objc_stubs) section
1617

1718
# CHECK-NEXT: _objc_msgSend$foo:
1819
# CHECK-NEXT: adrp x1, 8 ; 0x100008000
19-
# CHECK-NEXT: ldr x1, [x1, #0x10]
20+
# CHECK-NEXT: ldr x1, [x1, #0x18]
2021
# CHECK-NEXT: adrp x16, 4 ; 0x100004000
2122
# CHECK-NEXT: ldr x16, [x16]
2223
# CHECK-NEXT: br x16
@@ -26,7 +27,7 @@
2627

2728
# CHECK-NEXT: _objc_msgSend$length:
2829
# CHECK-NEXT: adrp x1, 8 ; 0x100008000
29-
# CHECK-NEXT: ldr x1, [x1, #0x18]
30+
# CHECK-NEXT: ldr x1, [x1, #0x20]
3031
# CHECK-NEXT: adrp x16, 4 ; 0x100004000
3132
# CHECK-NEXT: ldr x16, [x16]
3233
# CHECK-NEXT: br x16
@@ -44,13 +45,13 @@
4445
# FASTALIGN-NEXT: align 2^5 (32)
4546

4647
# SMALL: _objc_msgSend$foo:
47-
# SMALL-NEXT: adrp x1, 4 ; 0x100004000
48-
# SMALL-NEXT: ldr x1, [x1, #0x10]
48+
# SMALL-NEXT: adrp x1, 8 ; 0x100008000
49+
# SMALL-NEXT: ldr x1, [x1, #0x18]
4950
# SMALL-NEXT: b
5051

5152
# SMALL-NEXT: _objc_msgSend$length:
52-
# SMALL-NEXT: adrp x1, 4 ; 0x100004000
53-
# SMALL-NEXT: ldr x1, [x1, #0x18]
53+
# SMALL-NEXT: adrp x1, 8 ; 0x100008000
54+
# SMALL-NEXT: ldr x1, [x1, #0x20]
5455
# SMALL-NEXT: b
5556

5657
# SMALLALIGN: sectname __objc_stubs
@@ -60,6 +61,12 @@
6061
# SMALLALIGN-NEXT: offset
6162
# SMALLALIGN-NEXT: align 2^2 (4)
6263

64+
## Check correct section ordering
65+
# SECTIONS: Sections:
66+
# SECTIONS: __text
67+
# SECTIONS: __stubs
68+
# SECTIONS: __objc_stubs
69+
6370
.section __TEXT,__objc_methname,cstring_literals
6471
lselref1:
6572
.asciz "foo"
@@ -81,4 +88,5 @@ _main:
8188
bl _objc_msgSend$length
8289
bl _objc_msgSend$foo
8390
bl _objc_msgSend$foo
91+
bl _external_func
8492
ret

0 commit comments

Comments
 (0)