diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h index 7b45f7f4c39a1..96253e15f7eea 100644 --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -193,6 +193,7 @@ struct Configuration { UndefinedSymbolTreatment undefinedSymbolTreatment = UndefinedSymbolTreatment::error; ICFLevel icfLevel = ICFLevel::none; + bool keepICFStabs = false; ObjCStubsMode objcStubsMode = ObjCStubsMode::fast; llvm::MachO::HeaderFileType outputType; std::vector systemLibraryRoots; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index d4d8d53d69eea..4ee6a907b2f46 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1648,6 +1648,7 @@ bool link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, config->emitChainedFixups || args.hasArg(OPT_init_offsets); config->emitRelativeMethodLists = shouldEmitRelativeMethodLists(args); config->icfLevel = getICFLevel(args); + config->keepICFStabs = args.hasArg(OPT_keep_icf_stabs); config->dedupStrings = args.hasFlag(OPT_deduplicate_strings, OPT_no_deduplicate_strings, true); config->deadStripDuplicates = args.hasArg(OPT_dead_strip_duplicates); diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td index 11458d92b3abe..aecced9279da4 100644 --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -85,6 +85,9 @@ def icf_eq: Joined<["--"], "icf=">, HelpText<"Set level for identical code folding (default: none)">, MetaVarName<"[none,safe,all]">, Group; +def keep_icf_stabs: Joined<["--"], "keep-icf-stabs">, + HelpText<"Generate STABS entries for symbols folded by ICF. These entries can then be used by dsymutil to discover the address range where folded symbols are located.">, + Group; def lto_O: Joined<["--"], "lto-O">, HelpText<"Set optimization level for LTO (default: 2)">, MetaVarName<"">, diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp index 29070810bb049..b3fe223938bf5 100644 --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -1220,15 +1220,18 @@ void SymtabSection::emitStabs() { continue; // Constant-folded symbols go in the executable's symbol table, but don't - // get a stabs entry. - if (defined->wasIdenticalCodeFolded) + // get a stabs entry unless --keep-icf-stabs flag is specified + if (!config->keepICFStabs && defined->wasIdenticalCodeFolded) continue; ObjFile *file = defined->getObjectFile(); if (!file || !file->compileUnit) continue; - symbolsNeedingStabs.emplace_back(defined, defined->isec()->getFile()->id); + // We use 'originalIsec' to get the file id of the symbol since 'isec()' + // might point to the merged ICF symbol's file + symbolsNeedingStabs.emplace_back(defined, + defined->originalIsec->getFile()->id); } } @@ -1243,7 +1246,9 @@ void SymtabSection::emitStabs() { InputFile *lastFile = nullptr; for (SortingPair &pair : symbolsNeedingStabs) { Defined *defined = pair.first; - InputSection *isec = defined->isec(); + // We use 'originalIsec' of the symbol since we care about the actual origin + // of the symbol, not the canonical location returned by `isec()`. + InputSection *isec = defined->originalIsec; ObjFile *file = cast(isec->getFile()); if (lastFile == nullptr || lastFile != file) { @@ -1256,7 +1261,7 @@ void SymtabSection::emitStabs() { } StabsEntry symStab; - symStab.sect = defined->isec()->parent->index; + symStab.sect = isec->parent->index; symStab.strx = stringTableSection.addString(defined->getName()); symStab.value = defined->getVA(); diff --git a/lld/test/MachO/stabs-icf.s b/lld/test/MachO/stabs-icf.s index 99d0871ce4d2c..5f8449809ddd1 100644 --- a/lld/test/MachO/stabs-icf.s +++ b/lld/test/MachO/stabs-icf.s @@ -4,6 +4,9 @@ # RUN: %lld -lSystem --icf=all %t.o -o %t # RUN: dsymutil -s %t | FileCheck %s -DDIR=%t -DSRC_PATH=%t.o +# RUN: %lld -lSystem --icf=all %t.o -o %t_icf_stabs --keep-icf-stabs +# RUN: dsymutil -s %t_icf_stabs | FileCheck %s -DDIR=%t_icf_stabs -DSRC_PATH=%t.o --check-prefixes=ICF_STABS + ## This should include no N_FUN entry for _baz (which is ICF'd into _bar), ## but it does include a SECT EXT entry. ## NOTE: We do not omit the N_FUN entry for _bar even though it is of size zero. @@ -27,6 +30,30 @@ # CHECK-DAG: ( {{.*}}) {{[0-9]+}} 0100 0000000000000000 'dyld_stub_binder' # CHECK-EMPTY: + +# ICF_STABS: (N_SO ) 00 0000 0000000000000000 '/tmp{{[/\\]}}test.cpp' +# ICF_STABS-NEXT: (N_OSO ) 03 0001 {{.*}} '[[SRC_PATH]]' +# ICF_STABS-NEXT: (N_FUN ) 01 0000 [[#%.16x,MAIN:]] '_main' +# ICF_STABS-NEXT: (N_FUN ) 00 0000 000000000000000b{{$}} +# ICF_STABS-NEXT: (N_FUN ) 01 0000 [[#%.16x,BAR:]] '_bar' +# ICF_STABS-NEXT: (N_FUN ) 00 0000 0000000000000000{{$}} +# ICF_STABS-NEXT: (N_FUN ) 01 0000 [[#BAR]] '_bar2' +# ICF_STABS-NEXT: (N_FUN ) 00 0000 0000000000000001{{$}} +# ICF_STABS-NEXT: (N_FUN ) 01 0000 [[#BAR]] '_baz' +# ICF_STABS-NEXT: (N_FUN ) 00 0000 0000000000000000{{$}} +# ICF_STABS-NEXT: (N_FUN ) 01 0000 [[#BAR]] '_baz2' +# ICF_STABS-NEXT: (N_FUN ) 00 0000 0000000000000001{{$}} +# ICF_STABS-NEXT: (N_SO ) 01 0000 0000000000000000{{$}} +# ICF_STABS-DAG: ( SECT EXT) 01 0000 [[#MAIN]] '_main' +# ICF_STABS-DAG: ( SECT EXT) 01 0000 [[#BAR]] '_bar' +# ICF_STABS-DAG: ( SECT EXT) 01 0000 [[#BAR]] '_bar2' +# ICF_STABS-DAG: ( SECT EXT) 01 0000 [[#BAR]] '_baz' +# ICF_STABS-DAG: ( SECT EXT) 01 0000 [[#BAR]] '_baz2' +# ICF_STABS-DAG: ( {{.*}}) {{[0-9]+}} 0010 {{[0-9a-f]+}} '__mh_execute_header' +# ICF_STABS-DAG: ( {{.*}}) {{[0-9]+}} 0100 0000000000000000 'dyld_stub_binder' +# ICF_STABS-EMPTY: + + .text .globl _bar, _bar2, _baz, _baz2, _main