diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h index 8ac07a198071..df5d1f867e2d 100644 --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -24,6 +24,10 @@ namespace macho { class Symbol; struct SymbolPriorityEntry; +using NamePair = std::pair; +using SectionRenameMap = llvm::DenseMap; +using SegmentRenameMap = llvm::DenseMap; + struct PlatformInfo { llvm::MachO::PlatformKind kind; llvm::VersionTuple minimum; @@ -76,6 +80,8 @@ struct Configuration { std::vector runtimePaths; std::vector explicitUndefineds; llvm::DenseMap priorities; + SectionRenameMap sectionRenameMap; + SegmentRenameMap segmentRenameMap; }; // The symbol with the highest priority should be ordered first in the output diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index df0eaac21e0c..ca6378aa5560 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -815,6 +815,24 @@ bool macho::link(ArrayRef argsArr, bool canExitEarly, parseDylibVersion(args, OPT_compatibility_version); config->dylibCurrentVersion = parseDylibVersion(args, OPT_current_version); + // Reject every special character except '.' and '$' + // TODO(gkm): verify that this is the proper set of invalid chars + StringRef invalidNameChars("!\"#%&'()*+,-/:;<=>?@[\\]^`{|}~"); + auto validName = [invalidNameChars](StringRef s) { + if (s.find_first_of(invalidNameChars) != StringRef::npos) + error("invalid name for segment or section: " + s); + return s; + }; + for (opt::Arg *arg : args.filtered(OPT_rename_section)) { + config->sectionRenameMap[{validName(arg->getValue(0)), + validName(arg->getValue(1))}] = { + validName(arg->getValue(2)), validName(arg->getValue(3))}; + } + for (opt::Arg *arg : args.filtered(OPT_rename_segment)) { + config->segmentRenameMap[validName(arg->getValue(0))] = + validName(arg->getValue(1)); + } + config->saveTemps = args.hasArg(OPT_save_temps); if (args.hasArg(OPT_v)) { diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td index 743b9cb08e0b..81fcdad30ffb 100644 --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -629,12 +629,10 @@ def move_to_ro_segment : MultiArg<["-"], "move_to_ro_segment", 2>, def rename_section : MultiArg<["-"], "rename_section", 4>, MetaVarName<" ">, HelpText<"Rename / as /">, - Flags<[HelpHidden]>, Group; def rename_segment : MultiArg<["-"], "rename_segment", 2>, MetaVarName<" ">, HelpText<"Rename as ">, - Flags<[HelpHidden]>, Group; def trace_symbol_layout : Flag<["-"], "trace_symbol_layout">, HelpText<"Show where and why symbols move, as specified by -move_to_ro_segment, -move_to_rw_segment, -rename_section, and -rename_segment">, diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp index 56da22c1a19d..932bfebe0677 100644 --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -704,6 +704,16 @@ static void sortSegmentsAndSections() { } } +static NamePair maybeRenameSection(NamePair key) { + auto newNames = config->sectionRenameMap.find(key); + if (newNames != config->sectionRenameMap.end()) + return newNames->second; + auto newName = config->segmentRenameMap.find(key.first); + if (newName != config->segmentRenameMap.end()) + return std::make_pair(newName->second, key.second); + return key; +} + void Writer::createOutputSections() { // First, create hidden sections stringTableSection = make(); @@ -726,13 +736,12 @@ void Writer::createOutputSections() { } // Then merge input sections into output sections. - MapVector, MergedOutputSection *> - mergedOutputSections; + MapVector mergedOutputSections; for (InputSection *isec : inputSections) { - MergedOutputSection *&osec = - mergedOutputSections[{isec->segname, isec->name}]; + NamePair names = maybeRenameSection({isec->segname, isec->name}); + MergedOutputSection *&osec = mergedOutputSections[names]; if (osec == nullptr) - osec = make(isec->name); + osec = make(names.second); osec->mergeInput(isec); } diff --git a/lld/test/MachO/rename.s b/lld/test/MachO/rename.s new file mode 100644 index 000000000000..77885b19fdef --- /dev/null +++ b/lld/test/MachO/rename.s @@ -0,0 +1,62 @@ +# REQUIRES: x86 +# RUN: rm -fr %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o +# RUN: %lld -o %t %t.o + +## Check option format +# RUN: not %lld \ +# RUN: -rename_section B@GUS_SEG b@gus_sect S/ASHY_SEG st*rry_sect \ +# RUN: -rename_section __FROM_SECT __from_sect __TO_SECT \ +# RUN: -o /dev/null %t.o 2>&1 | FileCheck %s --check-prefix=BAD1 + +# BAD1-DAG: error: invalid name for segment or section: B@GUS_SEG +# BAD1-DAG: error: invalid name for segment or section: b@gus_sect +# BAD1-DAG: error: invalid name for segment or section: S/ASHY_SEG +# BAD1-DAG: error: invalid name for segment or section: st*rry_sect +# BAD1-DAG: error: invalid name for segment or section: -o +# BAD1-DAG: error: /dev/null: unhandled file type + +# RUN: not %lld \ +# RUN: -rename_segment H#SHY_SEG PL+SSY_SEG \ +# RUN: -rename_segment __FROM_SEG \ +# RUN: -o /dev/null %t.o 2>&1 | FileCheck %s --check-prefix=BAD2 + +# BAD2-DAG: error: invalid name for segment or section: H#SHY_SEG +# BAD2-DAG: error: invalid name for segment or section: PL+SSY_SEG +# BAD2-DAG: error: invalid name for segment or section: -o +# BAD2-DAG: error: /dev/null: unhandled file type + +## Check that section and segment renames happen +# RUN: %lld \ +# RUN: -rename_section __FROM_SECT __from_sect __TO_SECT __to_sect \ +# RUN: -rename_segment __FROM_SEG __TO_SEG \ +# RUN: -o %t %t.o +# RUN: llvm-objdump --macho --all-headers %t | FileCheck %s + +# CHECK: {{^}}Section{{$}} +# CHECK-NEXT: sectname __text +# CHECK-NEXT: segname __TEXT +# CHECK: {{^}}Section{{$}} +# CHECK-NOT: sectname __from_sect +# CHECK-NEXT: sectname __to_sect +# CHECK-NOT: segname __FROM_SECT +# CHECK-NEXT: segname __TO_SECT +# CHECK: {{^}}Section{{$}} +# CHECK-NEXT: sectname __from_seg +# CHECK-NOT: segname __FROM_SEG +# CHECK-NEXT: segname __TO_SEG + +.section __FROM_SECT,__from_sect +.global _from_sect +_from_sect: + .space 8 + +.section __FROM_SEG,__from_seg +.global _from_seg +_from_seg: + .space 8 + +.text +.global _main +_main: + ret