diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -92,6 +92,7 @@ bool emitBitcodeBundle = false; bool emitEncryptionInfo = false; bool timeTraceEnabled = false; + bool dataConst = false; uint32_t headerPad; uint32_t dylibCompatibilityVersion = 0; uint32_t dylibCurrentVersion = 0; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -558,6 +558,33 @@ } } +static void initializeSectionRenameMap() { + if (config->dataConst) { + SmallVector v{section_names::got, + section_names::authGot, + section_names::authPtr, + section_names::nonLazySymbolPtr, + section_names::const_, + section_names::cfString, + section_names::moduleInitFunc, + section_names::moduleTermFunc, + section_names::objcClassList, + section_names::objcNonLazyClassList, + section_names::objcCatList, + section_names::objcNonLazyCatList, + section_names::objcProtoList, + section_names::objcImageInfo}; + for (StringRef s : v) + config->sectionRenameMap[{segment_names::data, s}] = { + segment_names::dataConst, s}; + } + config->sectionRenameMap[{segment_names::text, section_names::staticInit}] = { + segment_names::text, section_names::text}; + config->sectionRenameMap[{segment_names::import, section_names::pointers}] = { + config->dataConst ? segment_names::dataConst : segment_names::data, + section_names::nonLazySymbolPtr}; +} + static inline char toLowerDash(char x) { if (x >= 'A' && x <= 'Z') return x - 'A' + 'a'; @@ -757,6 +784,26 @@ return prot; } +static bool dataConstDefault(const InputArgList &args) { + switch (config->outputType) { + case MH_EXECUTE: + return !args.hasArg(OPT_no_pie); + case MH_BUNDLE: + // FIXME: return false when -final_name ... + // has prefix "/System/Library/UserEventPlugins/" + // or matches "/usr/libexec/locationd" "/usr/libexec/terminusd" + return true; + case MH_DYLIB: + return true; + case MH_OBJECT: + return false; + default: + llvm_unreachable( + "unsupported output type for determining data-const default"); + } + return false; +} + void SymbolPatterns::clear() { literals.clear(); globs.clear(); @@ -1002,6 +1049,11 @@ parseDylibVersion(args, OPT_compatibility_version); config->dylibCurrentVersion = parseDylibVersion(args, OPT_current_version); + config->dataConst = + args.hasFlag(OPT_data_const, OPT_no_data_const, dataConstDefault(args)); + // Populate config->sectionRenameMap with builtin default renames. + // Options -rename_section and -rename_segment are able to override. + initializeSectionRenameMap(); // Reject every special character except '.' and '$' // TODO(gkm): verify that this is the proper set of invalid chars StringRef invalidNameChars("!\"#%&'()*+,-/:;<=>?@[\\]^`{|}~"); diff --git a/lld/MachO/MergedOutputSection.h b/lld/MachO/MergedOutputSection.h --- a/lld/MachO/MergedOutputSection.h +++ b/lld/MachO/MergedOutputSection.h @@ -44,7 +44,7 @@ } private: - void mergeFlags(uint32_t inputFlags); + void mergeFlags(InputSection *input); size_t size = 0; uint64_t fileSize = 0; diff --git a/lld/MachO/MergedOutputSection.cpp b/lld/MachO/MergedOutputSection.cpp --- a/lld/MachO/MergedOutputSection.cpp +++ b/lld/MachO/MergedOutputSection.cpp @@ -7,9 +7,11 @@ //===----------------------------------------------------------------------===// #include "MergedOutputSection.h" +#include "OutputSegment.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "llvm/BinaryFormat/MachO.h" +#include "llvm/Support/ScopedPrinter.h" using namespace llvm; using namespace llvm::MachO; @@ -21,8 +23,8 @@ align = input->align; flags = input->flags; } else { - mergeFlags(input->flags); align = std::max(align, input->align); + mergeFlags(input); } inputs.push_back(input); @@ -52,21 +54,25 @@ // TODO: this is most likely wrong; reconsider how section flags // are actually merged. The logic presented here was written without // any form of informed research. -void MergedOutputSection::mergeFlags(uint32_t inputFlags) { - uint8_t sectionFlag = SECTION_TYPE & inputFlags; - if (sectionFlag != (SECTION_TYPE & flags)) - error("Cannot add merge section; inconsistent type flags " + - Twine(sectionFlag)); +void MergedOutputSection::mergeFlags(InputSection *input) { + uint8_t baseType = flags & SECTION_TYPE; + uint8_t inputType = input->flags & SECTION_TYPE; + if (baseType != inputType) + error("Cannot merge section " + input->name + " (type=0x" + + to_hexString(inputType) + ") into " + name + " (type=0x" + + to_hexString(baseType) + "): inconsistent types"); - uint32_t inconsistentFlags = S_ATTR_DEBUG | S_ATTR_STRIP_STATIC_SYMS | - S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT; - if ((inputFlags ^ flags) & inconsistentFlags) - error("Cannot add merge section; cannot merge inconsistent flags"); + constexpr uint32_t strictFlags = S_ATTR_DEBUG | S_ATTR_STRIP_STATIC_SYMS | + S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT; + if ((input->flags ^ flags) & strictFlags) + error("Cannot merge section " + input->name + " (flags=0x" + + to_hexString(input->flags) + ") into " + name + " (flags=0x" + + to_hexString(flags) + "): strict flags differ"); // Negate pure instruction presence if any section isn't pure. - uint32_t pureMask = ~S_ATTR_PURE_INSTRUCTIONS | (inputFlags & flags); + uint32_t pureMask = ~S_ATTR_PURE_INSTRUCTIONS | (input->flags & flags); // Merge the rest - flags |= inputFlags; + flags |= input->flags; flags &= pureMask; } diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -635,6 +635,16 @@ HelpText<"Show where and why symbols move, as specified by -move_to_ro_segment, -move_to_rw_segment, -rename_section, and -rename_segment">, Flags<[HelpHidden]>, Group; +def data_const : Flag<["-"], "data_const">, + HelpText<"Force migration of readonly data into __DATA_CONST segment">, + Group; +def no_data_const : Flag<["-"], "no_data_const">, + HelpText<"Block migration of readonly data away from __DATA segment">, + Group; +def text_exec : Flag<["-"], "text_exec">, + HelpText<"Rename __segment TEXT to __TEXT_EXEC for sections __text and __stubs">, + Flags<[HelpHidden]>, + Group; def section_order : MultiArg<["-"], "section_order", 2>, MetaVarName<" ">, HelpText<"With -preload, specify layout sequence of colon-separated in ">, @@ -1134,14 +1144,6 @@ HelpText<"This option is undocumented in ld64">, Flags<[HelpHidden]>, Group; -def data_const : Flag<["-"], "data_const">, - HelpText<"This option is undocumented in ld64">, - Flags<[HelpHidden]>, - Group; -def no_data_const : Flag<["-"], "no_data_const">, - HelpText<"This option is undocumented in ld64">, - Flags<[HelpHidden]>, - Group; def data_in_code_info : Flag<["-"], "data_in_code_info">, HelpText<"This option is undocumented in ld64">, Flags<[HelpHidden]>, @@ -1286,10 +1288,6 @@ HelpText<"This option is undocumented in ld64">, Flags<[HelpHidden]>, Group; -def text_exec : Flag<["-"], "text_exec">, - HelpText<"This option is undocumented in ld64">, - Flags<[HelpHidden]>, - Group; def threaded_starts_section : Flag<["-"], "threaded_starts_section">, HelpText<"This option is undocumented in ld64">, Flags<[HelpHidden]>, diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -774,7 +774,8 @@ .Case(section_names::unwindInfo, std::numeric_limits::max() - 1) .Case(section_names::ehFrame, std::numeric_limits::max()) .Default(0); - } else if (segname == segment_names::data) { + } else if (segname == segment_names::data || + segname == segment_names::dataConst) { // For each thread spawned, dyld will initialize its TLVs by copying the // address range from the start of the first thread-local data section to // the end of the last one. We therefore arrange these sections contiguously diff --git a/lld/test/MachO/builtin-rename.s b/lld/test/MachO/builtin-rename.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/builtin-rename.s @@ -0,0 +1,170 @@ +# REQUIRES: x86 +# RUN: rm -rf %t; split-file %s %t + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin \ +# RUN: %t/main.s -o %t/main.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin \ +# RUN: %t/renames.s -o %t/renames.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin \ +# RUN: %t/error.s -o %t/error.o + +# RUN: not %lld -o %t/error %t/main.o %t/error.o -lSystem 2>&1 | \ +# RUN: FileCheck %s --check-prefix=ERROR + +## Check the error diagnostic for merging mismatched section types +# ERROR: Cannot merge section __pointers (type=0x0) into __nl_symbol_ptr (type=0x6): inconsistent types + +## Check that section and segment renames happen as expected +# RUN: %lld -o %t/ydata %t/main.o %t/renames.o -lSystem +# RUN: %lld -no_data_const -o %t/ndata %t/main.o %t/renames.o -lSystem +# RUN: %lld -no_pie -o %t/nopie %t/main.o %t/renames.o -lSystem + +# RUN: llvm-objdump --syms %t/ydata | \ +# RUN: FileCheck %s --check-prefixes=CHECK,YDATA +# RUN: llvm-objdump --syms %t/ndata | \ +# RUN: FileCheck %s --check-prefixes=CHECK,NDATA +# RUN: llvm-objdump --syms %t/nopie | \ +# RUN: FileCheck %s --check-prefixes=CHECK,NDATA + +# CHECK-LABEL: {{^}}SYMBOL TABLE: + +# CHECK-DAG: __TEXT,__text __TEXT__StaticInit + +# NDATA-DAG: __DATA,__auth_got __DATA__auth_got +# NDATA-DAG: __DATA,__auth_ptr __DATA__auth_ptr +# NDATA-DAG: __DATA,__nl_symbol_ptr __DATA__nl_symbol_ptr +# NDATA-DAG: __DATA,__const __DATA__const +# NDATA-DAG: __DATA,__cfstring __DATA__cfstring +# NDATA-DAG: __DATA,__mod_init_func __DATA__mod_init_func +# NDATA-DAG: __DATA,__mod_term_func __DATA__mod_term_func +# NDATA-DAG: __DATA,__objc_classlist __DATA__objc_classlist +# NDATA-DAG: __DATA,__objc_nlclslist __DATA__objc_nlclslist +# NDATA-DAG: __DATA,__objc_catlist __DATA__objc_catlist +# NDATA-DAG: __DATA,__objc_nlcatlist __DATA__objc_nlcatlist +# NDATA-DAG: __DATA,__objc_protolist __DATA__objc_protolist +# NDATA-DAG: __DATA,__objc_imageinfo __DATA__objc_imageinfo +# NDATA-DAG: __DATA,__nl_symbol_ptr __IMPORT__pointers + +# YDATA-DAG: __DATA_CONST,__auth_got __DATA__auth_got +# YDATA-DAG: __DATA_CONST,__auth_ptr __DATA__auth_ptr +# YDATA-DAG: __DATA_CONST,__nl_symbol_ptr __DATA__nl_symbol_ptr +# YDATA-DAG: __DATA_CONST,__const __DATA__const +# YDATA-DAG: __DATA_CONST,__cfstring __DATA__cfstring +# YDATA-DAG: __DATA_CONST,__mod_init_func __DATA__mod_init_func +# YDATA-DAG: __DATA_CONST,__mod_term_func __DATA__mod_term_func +# YDATA-DAG: __DATA_CONST,__objc_classlist __DATA__objc_classlist +# YDATA-DAG: __DATA_CONST,__objc_nlclslist __DATA__objc_nlclslist +# YDATA-DAG: __DATA_CONST,__objc_catlist __DATA__objc_catlist +# YDATA-DAG: __DATA_CONST,__objc_nlcatlist __DATA__objc_nlcatlist +# YDATA-DAG: __DATA_CONST,__objc_protolist __DATA__objc_protolist +# YDATA-DAG: __DATA_CONST,__objc_imageinfo __DATA__objc_imageinfo +# YDATA-DAG: __DATA_CONST,__nl_symbol_ptr __IMPORT__pointers + +#--- renames.s +.section __DATA,__auth_got +.global __DATA__auth_got +__DATA__auth_got: + .space 8 + +.section __DATA,__auth_ptr +.global __DATA__auth_ptr +__DATA__auth_ptr: + .space 8 + +.section __DATA,__nl_symbol_ptr +.global __DATA__nl_symbol_ptr +__DATA__nl_symbol_ptr: + .space 8 + +.section __DATA,__const +.global __DATA__const +__DATA__const: + .space 8 + +.section __DATA,__cfstring +.global __DATA__cfstring +__DATA__cfstring: + .space 8 + +# FIXME: error: conflicts with synthetic section ... +# FIXME: we can't explicitly define syms in synthetic sections +# COM: .section __DATA,__got +# COM: .global __DATA__got +# COM: __DATA__got: +# COM: .space 8 + +.section __DATA,__mod_init_func,mod_init_funcs +.global __DATA__mod_init_func +__DATA__mod_init_func: + .space 8 + +.section __DATA,__mod_term_func,mod_term_funcs +.global __DATA__mod_term_func +__DATA__mod_term_func: + .space 8 + +.section __DATA,__objc_classlist +.global __DATA__objc_classlist +__DATA__objc_classlist: + .space 8 + +.section __DATA,__objc_nlclslist +.global __DATA__objc_nlclslist +__DATA__objc_nlclslist: + .space 8 + +.section __DATA,__objc_catlist +.global __DATA__objc_catlist +__DATA__objc_catlist: + .space 8 + +.section __DATA,__objc_nlcatlist +.global __DATA__objc_nlcatlist +__DATA__objc_nlcatlist: + .space 8 + +.section __DATA,__objc_protolist +.global __DATA__objc_protolist +__DATA__objc_protolist: + .space 8 + +.section __DATA,__objc_imageinfo +.global __DATA__objc_imageinfo +__DATA__objc_imageinfo: + .space 8 + +# FIXME: error: conflicts with synthetic section ... +# FIXME: we can't explicitly define syms in synthetic sections +# COM: .section __DATA,__la_symbol_ptr,lazy_symbol_pointers +# COM: .global __DATA__la_symbol_ptr +# COM: __DATA__la_symbol_ptr: +# COM: .space 8 + +.section __IMPORT,__pointers,non_lazy_symbol_pointers +.global __IMPORT__pointers +__IMPORT__pointers: + .space 8 + +.section __TEXT,__StaticInit +.section __TEXT,__StaticInit +.global __TEXT__StaticInit +__TEXT__StaticInit: + .space 8 + +#--- error.s + +.section __DATA,__nl_symbol_ptr +.global __DATA__nl_symbol_ptr +__DATA__nl_symbol_ptr: + .space 8 + +.section __IMPORT,__pointers +.global __IMPORT__pointers +__IMPORT__pointers: + .space 8 + +#--- main.s +.text +.global _main +_main: + ret diff --git a/lld/test/MachO/load-command-sequence.s b/lld/test/MachO/load-command-sequence.s --- a/lld/test/MachO/load-command-sequence.s +++ b/lld/test/MachO/load-command-sequence.s @@ -28,14 +28,14 @@ # COMMON: segname __TEXT # COMMON: cmd LC_SEGMENT_64 # COMMON: segname __DATA_CONST +# COMMON: sectname __const +# COMMON: segname __DATA_CONST # COMMON: sectname __got # COMMON: segname __DATA_CONST # COMMON: cmd LC_SEGMENT_64 # COMMON: segname __DATA # COMMON: sectname __data # COMMON: segname __DATA -# COMMON: sectname __const -# COMMON: segname __DATA # COMMON: cmd LC_SEGMENT_64 # COMMON: segname __LINKEDIT # COMMON: cmd LC_DYLD_INFO_ONLY diff --git a/lld/test/MachO/local-got.s b/lld/test/MachO/local-got.s --- a/lld/test/MachO/local-got.s +++ b/lld/test/MachO/local-got.s @@ -8,7 +8,7 @@ # RUN: %lld -lSystem -o %t/test %t/test.o -L%t -lhello # RUN: llvm-objdump --macho --full-contents --rebase --bind %t/test | FileCheck %s --check-prefixes=CHECK,PIE --match-full-lines -# RUN: %lld -no_pie -lSystem -o %t/test %t/test.o -L%t -lhello +# RUN: %lld -no_pie -data_const -lSystem -o %t/test %t/test.o -L%t -lhello # RUN: llvm-objdump --macho --full-contents --rebase --bind %t/test | FileCheck %s --check-prefixes=CHECK,NO-PIE --match-full-lines ## Check that the GOT references the cstrings. --full-contents displays the diff --git a/lld/test/MachO/x86-64-relocs.s b/lld/test/MachO/x86-64-relocs.s --- a/lld/test/MachO/x86-64-relocs.s +++ b/lld/test/MachO/x86-64-relocs.s @@ -20,7 +20,7 @@ # CHECK-NEXT: [[#%x, CSTRING_ADDR + 22 - LSTR_OFF]] # RUN: llvm-objdump --section=__const --full-contents %t | FileCheck %s --check-prefix=NONPCREL -# NONPCREL: Contents of section __DATA,__const: +# NONPCREL: Contents of section __DATA_CONST,__const: # NONPCREL-NEXT: 100001000 18040000 01000000 18040000 01000000 .section __TEXT,__text diff --git a/lld/test/MachO/x86-64-stubs.s b/lld/test/MachO/x86-64-stubs.s --- a/lld/test/MachO/x86-64-stubs.s +++ b/lld/test/MachO/x86-64-stubs.s @@ -12,7 +12,7 @@ # RUN: -o %t/libgoodbye.dylib # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/dylink-lazy.o -# RUN: %lld -no_pie -o %t/dylink-lazy-no-pie \ +# RUN: %lld -no_pie -data_const -o %t/dylink-lazy-no-pie \ # RUN: -L%t -lhello -lgoodbye %t/dylink-lazy.o -lSystem ## When looking at the __stubs section alone, we are unable to easily tell which