Skip to content

Commit 27b426b

Browse files
committed
[lld-macho] Implement builtin section renaming
ld64 automatically renames many sections depending on output type and assorted flags. Here, we implement the most common configs. We can add more obscure flags and behaviors as needed. Depends on D101393 Differential Revision: https://reviews.llvm.org/D101395
1 parent 959eec1 commit 27b426b

File tree

11 files changed

+259
-31
lines changed

11 files changed

+259
-31
lines changed

lld/MachO/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ struct Configuration {
9292
bool emitBitcodeBundle = false;
9393
bool emitEncryptionInfo = false;
9494
bool timeTraceEnabled = false;
95+
bool dataConst = false;
9596
uint32_t headerPad;
9697
uint32_t dylibCompatibilityVersion = 0;
9798
uint32_t dylibCurrentVersion = 0;

lld/MachO/Driver.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,33 @@ static void replaceCommonSymbols() {
558558
}
559559
}
560560

561+
static void initializeSectionRenameMap() {
562+
if (config->dataConst) {
563+
SmallVector<StringRef> v{section_names::got,
564+
section_names::authGot,
565+
section_names::authPtr,
566+
section_names::nonLazySymbolPtr,
567+
section_names::const_,
568+
section_names::cfString,
569+
section_names::moduleInitFunc,
570+
section_names::moduleTermFunc,
571+
section_names::objcClassList,
572+
section_names::objcNonLazyClassList,
573+
section_names::objcCatList,
574+
section_names::objcNonLazyCatList,
575+
section_names::objcProtoList,
576+
section_names::objcImageInfo};
577+
for (StringRef s : v)
578+
config->sectionRenameMap[{segment_names::data, s}] = {
579+
segment_names::dataConst, s};
580+
}
581+
config->sectionRenameMap[{segment_names::text, section_names::staticInit}] = {
582+
segment_names::text, section_names::text};
583+
config->sectionRenameMap[{segment_names::import, section_names::pointers}] = {
584+
config->dataConst ? segment_names::dataConst : segment_names::data,
585+
section_names::nonLazySymbolPtr};
586+
}
587+
561588
static inline char toLowerDash(char x) {
562589
if (x >= 'A' && x <= 'Z')
563590
return x - 'A' + 'a';
@@ -757,6 +784,26 @@ static uint32_t parseProtection(StringRef protStr) {
757784
return prot;
758785
}
759786

787+
static bool dataConstDefault(const InputArgList &args) {
788+
switch (config->outputType) {
789+
case MH_EXECUTE:
790+
return !args.hasArg(OPT_no_pie);
791+
case MH_BUNDLE:
792+
// FIXME: return false when -final_name ...
793+
// has prefix "/System/Library/UserEventPlugins/"
794+
// or matches "/usr/libexec/locationd" "/usr/libexec/terminusd"
795+
return true;
796+
case MH_DYLIB:
797+
return true;
798+
case MH_OBJECT:
799+
return false;
800+
default:
801+
llvm_unreachable(
802+
"unsupported output type for determining data-const default");
803+
}
804+
return false;
805+
}
806+
760807
void SymbolPatterns::clear() {
761808
literals.clear();
762809
globs.clear();
@@ -1002,6 +1049,11 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
10021049
parseDylibVersion(args, OPT_compatibility_version);
10031050
config->dylibCurrentVersion = parseDylibVersion(args, OPT_current_version);
10041051

1052+
config->dataConst =
1053+
args.hasFlag(OPT_data_const, OPT_no_data_const, dataConstDefault(args));
1054+
// Populate config->sectionRenameMap with builtin default renames.
1055+
// Options -rename_section and -rename_segment are able to override.
1056+
initializeSectionRenameMap();
10051057
// Reject every special character except '.' and '$'
10061058
// TODO(gkm): verify that this is the proper set of invalid chars
10071059
StringRef invalidNameChars("!\"#%&'()*+,-/:;<=>?@[\\]^`{|}~");

lld/MachO/MergedOutputSection.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "MergedOutputSection.h"
10+
#include "OutputSegment.h"
1011
#include "lld/Common/ErrorHandler.h"
1112
#include "lld/Common/Memory.h"
1213
#include "llvm/BinaryFormat/MachO.h"
14+
#include "llvm/Support/ScopedPrinter.h"
1315

1416
using namespace llvm;
1517
using namespace llvm::MachO;
@@ -21,8 +23,8 @@ void MergedOutputSection::mergeInput(InputSection *input) {
2123
align = input->align;
2224
flags = input->flags;
2325
} else {
24-
mergeFlags(input->flags);
2526
align = std::max(align, input->align);
27+
mergeFlags(input);
2628
}
2729

2830
inputs.push_back(input);
@@ -52,21 +54,25 @@ void MergedOutputSection::writeTo(uint8_t *buf) const {
5254
// TODO: this is most likely wrong; reconsider how section flags
5355
// are actually merged. The logic presented here was written without
5456
// any form of informed research.
55-
void MergedOutputSection::mergeFlags(uint32_t inputFlags) {
56-
uint8_t sectionFlag = SECTION_TYPE & inputFlags;
57-
if (sectionFlag != (SECTION_TYPE & flags))
58-
error("Cannot add merge section; inconsistent type flags " +
59-
Twine(sectionFlag));
57+
void MergedOutputSection::mergeFlags(InputSection *input) {
58+
uint8_t baseType = flags & SECTION_TYPE;
59+
uint8_t inputType = input->flags & SECTION_TYPE;
60+
if (baseType != inputType)
61+
error("Cannot merge section " + input->name + " (type=0x" +
62+
to_hexString(inputType) + ") into " + name + " (type=0x" +
63+
to_hexString(baseType) + "): inconsistent types");
6064

61-
uint32_t inconsistentFlags = S_ATTR_DEBUG | S_ATTR_STRIP_STATIC_SYMS |
62-
S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT;
63-
if ((inputFlags ^ flags) & inconsistentFlags)
64-
error("Cannot add merge section; cannot merge inconsistent flags");
65+
constexpr uint32_t strictFlags = S_ATTR_DEBUG | S_ATTR_STRIP_STATIC_SYMS |
66+
S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT;
67+
if ((input->flags ^ flags) & strictFlags)
68+
error("Cannot merge section " + input->name + " (flags=0x" +
69+
to_hexString(input->flags) + ") into " + name + " (flags=0x" +
70+
to_hexString(flags) + "): strict flags differ");
6571

6672
// Negate pure instruction presence if any section isn't pure.
67-
uint32_t pureMask = ~S_ATTR_PURE_INSTRUCTIONS | (inputFlags & flags);
73+
uint32_t pureMask = ~S_ATTR_PURE_INSTRUCTIONS | (input->flags & flags);
6874

6975
// Merge the rest
70-
flags |= inputFlags;
76+
flags |= input->flags;
7177
flags &= pureMask;
7278
}

lld/MachO/MergedOutputSection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class MergedOutputSection : public OutputSection {
4444
}
4545

4646
private:
47-
void mergeFlags(uint32_t inputFlags);
47+
void mergeFlags(InputSection *input);
4848

4949
size_t size = 0;
5050
uint64_t fileSize = 0;

lld/MachO/Options.td

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,16 @@ def trace_symbol_layout : Flag<["-"], "trace_symbol_layout">,
635635
HelpText<"Show where and why symbols move, as specified by -move_to_ro_segment, -move_to_rw_segment, -rename_section, and -rename_segment">,
636636
Flags<[HelpHidden]>,
637637
Group<grp_rare>;
638+
def data_const : Flag<["-"], "data_const">,
639+
HelpText<"Force migration of readonly data into __DATA_CONST segment">,
640+
Group<grp_rare>;
641+
def no_data_const : Flag<["-"], "no_data_const">,
642+
HelpText<"Block migration of readonly data away from __DATA segment">,
643+
Group<grp_rare>;
644+
def text_exec : Flag<["-"], "text_exec">,
645+
HelpText<"Rename __segment TEXT to __TEXT_EXEC for sections __text and __stubs">,
646+
Flags<[HelpHidden]>,
647+
Group<grp_rare>;
638648
def section_order : MultiArg<["-"], "section_order", 2>,
639649
MetaVarName<"<segment> <sections>">,
640650
HelpText<"With -preload, specify layout sequence of colon-separated <sections> in <segment>">,
@@ -1134,14 +1144,6 @@ def classic_linker : Flag<["-"], "classic_linker">,
11341144
HelpText<"This option is undocumented in ld64">,
11351145
Flags<[HelpHidden]>,
11361146
Group<grp_undocumented>;
1137-
def data_const : Flag<["-"], "data_const">,
1138-
HelpText<"This option is undocumented in ld64">,
1139-
Flags<[HelpHidden]>,
1140-
Group<grp_undocumented>;
1141-
def no_data_const : Flag<["-"], "no_data_const">,
1142-
HelpText<"This option is undocumented in ld64">,
1143-
Flags<[HelpHidden]>,
1144-
Group<grp_undocumented>;
11451147
def data_in_code_info : Flag<["-"], "data_in_code_info">,
11461148
HelpText<"This option is undocumented in ld64">,
11471149
Flags<[HelpHidden]>,
@@ -1286,10 +1288,6 @@ def source_version : Flag<["-"], "source_version">,
12861288
HelpText<"This option is undocumented in ld64">,
12871289
Flags<[HelpHidden]>,
12881290
Group<grp_undocumented>;
1289-
def text_exec : Flag<["-"], "text_exec">,
1290-
HelpText<"This option is undocumented in ld64">,
1291-
Flags<[HelpHidden]>,
1292-
Group<grp_undocumented>;
12931291
def threaded_starts_section : Flag<["-"], "threaded_starts_section">,
12941292
HelpText<"This option is undocumented in ld64">,
12951293
Flags<[HelpHidden]>,

lld/MachO/Writer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,8 @@ static int sectionOrder(OutputSection *osec) {
774774
.Case(section_names::unwindInfo, std::numeric_limits<int>::max() - 1)
775775
.Case(section_names::ehFrame, std::numeric_limits<int>::max())
776776
.Default(0);
777-
} else if (segname == segment_names::data) {
777+
} else if (segname == segment_names::data ||
778+
segname == segment_names::dataConst) {
778779
// For each thread spawned, dyld will initialize its TLVs by copying the
779780
// address range from the start of the first thread-local data section to
780781
// the end of the last one. We therefore arrange these sections contiguously

lld/test/MachO/builtin-rename.s

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# REQUIRES: x86
2+
# RUN: rm -rf %t; split-file %s %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin \
5+
# RUN: %t/main.s -o %t/main.o
6+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin \
7+
# RUN: %t/renames.s -o %t/renames.o
8+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin \
9+
# RUN: %t/error.s -o %t/error.o
10+
11+
# RUN: not %lld -o %t/error %t/main.o %t/error.o -lSystem 2>&1 | \
12+
# RUN: FileCheck %s --check-prefix=ERROR
13+
14+
## Check the error diagnostic for merging mismatched section types
15+
# ERROR: Cannot merge section __pointers (type=0x0) into __nl_symbol_ptr (type=0x6): inconsistent types
16+
17+
## Check that section and segment renames happen as expected
18+
# RUN: %lld -o %t/ydata %t/main.o %t/renames.o -lSystem
19+
# RUN: %lld -no_data_const -o %t/ndata %t/main.o %t/renames.o -lSystem
20+
# RUN: %lld -no_pie -o %t/nopie %t/main.o %t/renames.o -lSystem
21+
22+
# RUN: llvm-objdump --syms %t/ydata | \
23+
# RUN: FileCheck %s --check-prefixes=CHECK,YDATA
24+
# RUN: llvm-objdump --syms %t/ndata | \
25+
# RUN: FileCheck %s --check-prefixes=CHECK,NDATA
26+
# RUN: llvm-objdump --syms %t/nopie | \
27+
# RUN: FileCheck %s --check-prefixes=CHECK,NDATA
28+
29+
# CHECK-LABEL: {{^}}SYMBOL TABLE:
30+
31+
# CHECK-DAG: __TEXT,__text __TEXT__StaticInit
32+
33+
# NDATA-DAG: __DATA,__auth_got __DATA__auth_got
34+
# NDATA-DAG: __DATA,__auth_ptr __DATA__auth_ptr
35+
# NDATA-DAG: __DATA,__nl_symbol_ptr __DATA__nl_symbol_ptr
36+
# NDATA-DAG: __DATA,__const __DATA__const
37+
# NDATA-DAG: __DATA,__cfstring __DATA__cfstring
38+
# NDATA-DAG: __DATA,__mod_init_func __DATA__mod_init_func
39+
# NDATA-DAG: __DATA,__mod_term_func __DATA__mod_term_func
40+
# NDATA-DAG: __DATA,__objc_classlist __DATA__objc_classlist
41+
# NDATA-DAG: __DATA,__objc_nlclslist __DATA__objc_nlclslist
42+
# NDATA-DAG: __DATA,__objc_catlist __DATA__objc_catlist
43+
# NDATA-DAG: __DATA,__objc_nlcatlist __DATA__objc_nlcatlist
44+
# NDATA-DAG: __DATA,__objc_protolist __DATA__objc_protolist
45+
# NDATA-DAG: __DATA,__objc_imageinfo __DATA__objc_imageinfo
46+
# NDATA-DAG: __DATA,__nl_symbol_ptr __IMPORT__pointers
47+
48+
# YDATA-DAG: __DATA_CONST,__auth_got __DATA__auth_got
49+
# YDATA-DAG: __DATA_CONST,__auth_ptr __DATA__auth_ptr
50+
# YDATA-DAG: __DATA_CONST,__nl_symbol_ptr __DATA__nl_symbol_ptr
51+
# YDATA-DAG: __DATA_CONST,__const __DATA__const
52+
# YDATA-DAG: __DATA_CONST,__cfstring __DATA__cfstring
53+
# YDATA-DAG: __DATA_CONST,__mod_init_func __DATA__mod_init_func
54+
# YDATA-DAG: __DATA_CONST,__mod_term_func __DATA__mod_term_func
55+
# YDATA-DAG: __DATA_CONST,__objc_classlist __DATA__objc_classlist
56+
# YDATA-DAG: __DATA_CONST,__objc_nlclslist __DATA__objc_nlclslist
57+
# YDATA-DAG: __DATA_CONST,__objc_catlist __DATA__objc_catlist
58+
# YDATA-DAG: __DATA_CONST,__objc_nlcatlist __DATA__objc_nlcatlist
59+
# YDATA-DAG: __DATA_CONST,__objc_protolist __DATA__objc_protolist
60+
# YDATA-DAG: __DATA_CONST,__objc_imageinfo __DATA__objc_imageinfo
61+
# YDATA-DAG: __DATA_CONST,__nl_symbol_ptr __IMPORT__pointers
62+
63+
#--- renames.s
64+
.section __DATA,__auth_got
65+
.global __DATA__auth_got
66+
__DATA__auth_got:
67+
.space 8
68+
69+
.section __DATA,__auth_ptr
70+
.global __DATA__auth_ptr
71+
__DATA__auth_ptr:
72+
.space 8
73+
74+
.section __DATA,__nl_symbol_ptr
75+
.global __DATA__nl_symbol_ptr
76+
__DATA__nl_symbol_ptr:
77+
.space 8
78+
79+
.section __DATA,__const
80+
.global __DATA__const
81+
__DATA__const:
82+
.space 8
83+
84+
.section __DATA,__cfstring
85+
.global __DATA__cfstring
86+
__DATA__cfstring:
87+
.space 8
88+
89+
# FIXME: error: conflicts with synthetic section ...
90+
# FIXME: we can't explicitly define syms in synthetic sections
91+
# COM: .section __DATA,__got
92+
# COM: .global __DATA__got
93+
# COM: __DATA__got:
94+
# COM: .space 8
95+
96+
.section __DATA,__mod_init_func,mod_init_funcs
97+
.global __DATA__mod_init_func
98+
__DATA__mod_init_func:
99+
.space 8
100+
101+
.section __DATA,__mod_term_func,mod_term_funcs
102+
.global __DATA__mod_term_func
103+
__DATA__mod_term_func:
104+
.space 8
105+
106+
.section __DATA,__objc_classlist
107+
.global __DATA__objc_classlist
108+
__DATA__objc_classlist:
109+
.space 8
110+
111+
.section __DATA,__objc_nlclslist
112+
.global __DATA__objc_nlclslist
113+
__DATA__objc_nlclslist:
114+
.space 8
115+
116+
.section __DATA,__objc_catlist
117+
.global __DATA__objc_catlist
118+
__DATA__objc_catlist:
119+
.space 8
120+
121+
.section __DATA,__objc_nlcatlist
122+
.global __DATA__objc_nlcatlist
123+
__DATA__objc_nlcatlist:
124+
.space 8
125+
126+
.section __DATA,__objc_protolist
127+
.global __DATA__objc_protolist
128+
__DATA__objc_protolist:
129+
.space 8
130+
131+
.section __DATA,__objc_imageinfo
132+
.global __DATA__objc_imageinfo
133+
__DATA__objc_imageinfo:
134+
.space 8
135+
136+
# FIXME: error: conflicts with synthetic section ...
137+
# FIXME: we can't explicitly define syms in synthetic sections
138+
# COM: .section __DATA,__la_symbol_ptr,lazy_symbol_pointers
139+
# COM: .global __DATA__la_symbol_ptr
140+
# COM: __DATA__la_symbol_ptr:
141+
# COM: .space 8
142+
143+
.section __IMPORT,__pointers,non_lazy_symbol_pointers
144+
.global __IMPORT__pointers
145+
__IMPORT__pointers:
146+
.space 8
147+
148+
.section __TEXT,__StaticInit
149+
.section __TEXT,__StaticInit
150+
.global __TEXT__StaticInit
151+
__TEXT__StaticInit:
152+
.space 8
153+
154+
#--- error.s
155+
156+
.section __DATA,__nl_symbol_ptr
157+
.global __DATA__nl_symbol_ptr
158+
__DATA__nl_symbol_ptr:
159+
.space 8
160+
161+
.section __IMPORT,__pointers
162+
.global __IMPORT__pointers
163+
__IMPORT__pointers:
164+
.space 8
165+
166+
#--- main.s
167+
.text
168+
.global _main
169+
_main:
170+
ret

lld/test/MachO/load-command-sequence.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828
# COMMON: segname __TEXT
2929
# COMMON: cmd LC_SEGMENT_64
3030
# COMMON: segname __DATA_CONST
31+
# COMMON: sectname __const
32+
# COMMON: segname __DATA_CONST
3133
# COMMON: sectname __got
3234
# COMMON: segname __DATA_CONST
3335
# COMMON: cmd LC_SEGMENT_64
3436
# COMMON: segname __DATA
3537
# COMMON: sectname __data
3638
# COMMON: segname __DATA
37-
# COMMON: sectname __const
38-
# COMMON: segname __DATA
3939
# COMMON: cmd LC_SEGMENT_64
4040
# COMMON: segname __LINKEDIT
4141
# COMMON: cmd LC_DYLD_INFO_ONLY

lld/test/MachO/local-got.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
# RUN: %lld -lSystem -o %t/test %t/test.o -L%t -lhello
1010
# RUN: llvm-objdump --macho --full-contents --rebase --bind %t/test | FileCheck %s --check-prefixes=CHECK,PIE --match-full-lines
11-
# RUN: %lld -no_pie -lSystem -o %t/test %t/test.o -L%t -lhello
11+
# RUN: %lld -no_pie -data_const -lSystem -o %t/test %t/test.o -L%t -lhello
1212
# RUN: llvm-objdump --macho --full-contents --rebase --bind %t/test | FileCheck %s --check-prefixes=CHECK,NO-PIE --match-full-lines
1313

1414
## Check that the GOT references the cstrings. --full-contents displays the

0 commit comments

Comments
 (0)