[lld-macho] Flip string deduplication default

Previously by default, when not using `--ifc=`, lld would not
deduplicate string literals. This reveals reliance on undefined behavior
where string literal addresses are compared instead of using string
equality checks. While ideally you would be able to easily identify and
eliminate the reliance on this UB, this can be difficult, especially for
third party code, and increases the friction and risk of users migrating
to lld. This flips the default to deduplicate strings unless
`--no-deduplicate-strings` is passed, matching ld64's behavior.

Differential Revision: https://reviews.llvm.org/D140517
This commit is contained in:
Keith Smiley
2022-12-21 15:48:28 -08:00
parent 85bb24ab52
commit 2e5989e814
15 changed files with 56 additions and 87 deletions

View File

@@ -135,7 +135,7 @@ struct Configuration {
bool emitChainedFixups = false;
bool timeTraceEnabled = false;
bool dataConst = false;
bool dedupLiterals = true;
bool dedupStrings = true;
bool deadStripDuplicates = false;
bool omitDebugInfo = false;
bool warnDylibInstallName = false;

View File

@@ -1209,8 +1209,7 @@ static void foldIdenticalLiterals() {
// Either way, we must unconditionally finalize it here.
in.cStringSection->finalizeContents();
in.objcMethnameSection->finalizeContents();
if (in.wordLiteralSection)
in.wordLiteralSection->finalizeContents();
in.wordLiteralSection->finalizeContents();
}
static void addSynthenticMethnames() {
@@ -1552,9 +1551,8 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
config->emitInitOffsets =
config->emitChainedFixups || args.hasArg(OPT_init_offsets);
config->icfLevel = getICFLevel(args);
config->dedupLiterals =
args.hasFlag(OPT_deduplicate_literals, OPT_icf_eq, false) ||
config->icfLevel != ICFLevel::none;
config->dedupStrings =
args.hasFlag(OPT_deduplicate_strings, OPT_no_deduplicate_strings, true);
config->deadStripDuplicates = args.hasArg(OPT_dead_strip_duplicates);
config->warnDylibInstallName = args.hasFlag(
OPT_warn_dylib_install_name, OPT_no_warn_dylib_install_name, false);
@@ -1863,7 +1861,7 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
if (config->icfLevel == ICFLevel::safe)
markAddrSigSymbols();
foldIdenticalSections(/*onlyCfStrings=*/false);
} else if (config->dedupLiterals) {
} else if (config->dedupStrings) {
foldIdenticalSections(/*onlyCfStrings=*/true);
}

View File

@@ -270,7 +270,7 @@ static std::optional<size_t> getRecordSize(StringRef segname, StringRef name) {
if (segname == segment_names::ld)
return target->wordSize == 8 ? 32 : 20;
}
if (!config->dedupLiterals)
if (!config->dedupStrings)
return {};
if (name == section_names::cfString && segname == segment_names::data)
@@ -342,25 +342,25 @@ void ObjFile::parseSections(ArrayRef<SectionHeader> sectionHeaders) {
section.doneSplitting = true;
};
if (sectionType(sec.flags) == S_CSTRING_LITERALS ||
(config->dedupLiterals && isWordLiteralSection(sec.flags))) {
if (sec.nreloc && config->dedupLiterals)
if (sectionType(sec.flags) == S_CSTRING_LITERALS) {
if (sec.nreloc && config->dedupStrings)
fatal(toString(this) + " contains relocations in " + sec.segname + "," +
sec.sectname +
", so LLD cannot deduplicate literals. Try re-running without "
"--deduplicate-literals.");
", so LLD cannot deduplicate strings. Try re-running with "
"--no-deduplicate-strings.");
InputSection *isec;
if (sectionType(sec.flags) == S_CSTRING_LITERALS) {
isec = make<CStringInputSection>(section, data, align,
/*dedupLiterals=*/name ==
section_names::objcMethname ||
config->dedupLiterals);
// FIXME: parallelize this?
cast<CStringInputSection>(isec)->splitIntoPieces();
} else {
isec = make<WordLiteralInputSection>(section, data, align);
}
InputSection *isec = make<CStringInputSection>(
section, data, align,
/*dedupLiterals=*/name == section_names::objcMethname ||
config->dedupStrings);
// FIXME: parallelize this?
cast<CStringInputSection>(isec)->splitIntoPieces();
section.subsections.push_back({0, isec});
} else if (isWordLiteralSection(sec.flags)) {
if (sec.nreloc)
fatal(toString(this) + " contains unsupported relocations in " +
sec.segname + "," + sec.sectname);
InputSection *isec = make<WordLiteralInputSection>(section, data, align);
section.subsections.push_back({0, isec});
} else if (auto recordSize = getRecordSize(segname, name)) {
splitRecords(*recordSize);

View File

@@ -54,8 +54,11 @@ def : Flag<["--"], "time-trace">,
def time_trace_granularity_eq: Joined<["--"], "time-trace-granularity=">,
HelpText<"Minimum time granularity (in microseconds) traced by time profiler">,
Group<grp_lld>;
def deduplicate_literals: Flag<["--"], "deduplicate-literals">,
HelpText<"Enable literal deduplication. This is implied by --icf={safe,all}">,
def deduplicate_strings: Flag<["--"], "deduplicate-strings">,
HelpText<"Enable string deduplication">,
Group<grp_lld>;
def no_deduplicate_strings: Flag<["--"], "no-deduplicate-strings">,
HelpText<"Disable string deduplication. This helps uncover cases of comparing string addresses instead of equality and might have a link time performance benefit.">,
Group<grp_lld>;
def dead_strip_duplicates: Flag<["--"], "dead-strip-duplicates">,
HelpText<"Do not error on duplicate symbols that will be dead stripped.">,

View File

@@ -1319,15 +1319,14 @@ void macho::resetWriter() { LCDylib::resetInstanceCount(); }
void macho::createSyntheticSections() {
in.header = make<MachHeaderSection>();
if (config->dedupLiterals)
if (config->dedupStrings)
in.cStringSection =
make<DeduplicatedCStringSection>(section_names::cString);
else
in.cStringSection = make<CStringSection>(section_names::cString);
in.objcMethnameSection =
make<DeduplicatedCStringSection>(section_names::objcMethname);
in.wordLiteralSection =
config->dedupLiterals ? make<WordLiteralSection>() : nullptr;
in.wordLiteralSection = make<WordLiteralSection>();
if (config->emitChainedFixups) {
in.chainedFixups = make<ChainedFixupsSection>();
} else {

View File

@@ -51,9 +51,6 @@ LLD can be used by adding ``-fuse-ld=/path/to/ld64.lld`` to the linker flags.
For Xcode, this can be done by adding it to "Other linker flags" in the build
settings. For Bazel, this can be done with ``--linkopt`` or with
`rules_apple_linker <https://github.com/keith/rules_apple_linker>`_.
The user may also need to add ``-Wl,--deduplicate-literals`` in order
to match Apple's linker behavior more closely (otherwise problems
can occur, for instance, in unit tests).
.. seealso::

View File

@@ -5,15 +5,6 @@ ld64 vs LLD-MachO
This doc lists all significant deliberate differences in behavior between ld64
and LLD-MachO.
String Literal Deduplication
****************************
ld64 always deduplicates string literals. LLD only does it when the ``--icf=``
or the ``--deduplicate-literals`` flag is passed. Omitting deduplication by
default ensures that our link is as fast as possible. However, it may also break
some programs which have (incorrectly) relied on string deduplication always
occurring. In particular, programs which compare string literals via pointer
equality must be fixed to use value equality instead.
Dead Stripping Duplicate Symbols
********************************
ld64 strips dead code before reporting duplicate symbols. By default, LLD does

View File

@@ -4,7 +4,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo2.s -o %t/foo2.o
# RUN: %lld -dylib --icf=all -framework CoreFoundation %t/foo1.o %t/foo2.o -o %t/foo
# RUN: llvm-objdump --no-print-imm-hex --macho --rebase --bind --syms -d %t/foo | FileCheck %s --check-prefixes=CHECK,LITERALS
# RUN: %lld -dylib --deduplicate-literals -framework CoreFoundation %t/foo1.o %t/foo2.o -o %t/foo
# RUN: %lld -dylib -framework CoreFoundation %t/foo1.o %t/foo2.o -o %t/foo
# RUN: llvm-objdump --no-print-imm-hex --macho --rebase --bind --syms -d %t/foo | FileCheck %s --check-prefix=LITERALS
# CHECK: (__TEXT,__text) section

View File

@@ -16,24 +16,24 @@
## get dedup'ed, meaning that the output strings get their offsets "naturally"
## preserved.
# RUN: %lld -dylib %t/align-empty.o %t/align-4-0.o %t/align-16-0.o -o %t/align-4-0-16-0
# RUN: %lld -dylib --no-deduplicate-strings %t/align-empty.o %t/align-4-0.o %t/align-16-0.o -o %t/align-4-0-16-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/align-4-0-16-0 | \
# RUN: FileCheck %s -D#OFF1=4 -D#OFF2=16
# RUN: %lld -dylib %t/align-empty.o %t/align-16-0.o %t/align-4-0.o -o %t/align-16-0-4-0
# RUN: %lld -dylib --no-deduplicate-strings %t/align-empty.o %t/align-16-0.o %t/align-4-0.o -o %t/align-16-0-4-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/align-16-0-4-0 | \
# RUN: FileCheck %s -D#OFF1=16 -D#OFF2=20
# RUN: %lld -dylib %t/align-empty.o %t/align-4-2.o %t/align-16-0.o -o %t/align-4-2-16-0
# RUN: %lld -dylib --no-deduplicate-strings %t/align-empty.o %t/align-4-2.o %t/align-16-0.o -o %t/align-4-2-16-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/align-4-2-16-0 | \
# RUN: FileCheck %s -D#OFF1=6 -D#OFF2=16
# RUN: %lld -dylib %t/align-empty.o %t/align-16-0.o %t/align-4-2.o -o %t/align-16-0-4-2
# RUN: %lld -dylib --no-deduplicate-strings %t/align-empty.o %t/align-16-0.o %t/align-4-2.o -o %t/align-16-0-4-2
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/align-16-0-4-2 | \
# RUN: FileCheck %s -D#OFF1=16 -D#OFF2=22
# RUN: %lld -dylib %t/align-empty.o %t/align-4-0.o %t/align-16-2.o -o %t/align-4-0-16-2
# RUN: %lld -dylib --no-deduplicate-strings %t/align-empty.o %t/align-4-0.o %t/align-16-2.o -o %t/align-4-0-16-2
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/align-4-0-16-2 | \
# RUN: FileCheck %s -D#OFF1=4 -D#OFF2=18
# RUN: %lld -dylib %t/align-empty.o %t/align-16-2.o %t/align-4-0.o -o %t/align-16-2-4-0
# RUN: %lld -dylib --no-deduplicate-strings %t/align-empty.o %t/align-16-2.o %t/align-4-0.o -o %t/align-16-2-4-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/align-16-2-4-0 | \
# RUN: FileCheck %s -D#OFF1=18 -D#OFF2=20
@@ -46,42 +46,42 @@
## The dedup cases are more interesting...
## Same offset, different alignments => pick higher alignment
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-4-0.o %t/align-16-0.o -o %t/dedup-4-0-16-0
# RUN: %lld -dylib %t/align-empty.o %t/align-4-0.o %t/align-16-0.o -o %t/dedup-4-0-16-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-4-0-16-0 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=16
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-16-0.o %t/align-4-0.o -o %t/dedup-16-0-4-0
# RUN: %lld -dylib %t/align-empty.o %t/align-16-0.o %t/align-4-0.o -o %t/dedup-16-0-4-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-16-0-4-0 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=16
## 16 byte alignment vs 2 byte offset => align to 16 bytes
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-4-2.o %t/align-16-0.o -o %t/dedup-4-2-16-0
# RUN: %lld -dylib %t/align-empty.o %t/align-4-2.o %t/align-16-0.o -o %t/dedup-4-2-16-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-4-2-16-0 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=16
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-16-0.o %t/align-4-2.o -o %t/dedup-16-0-4-2
# RUN: %lld -dylib %t/align-empty.o %t/align-16-0.o %t/align-4-2.o -o %t/dedup-16-0-4-2
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-16-0-4-2 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=16
## 4 byte alignment vs 2 byte offset => align to 4 bytes
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-4-0.o %t/align-16-2.o -o %t/dedup-4-0-16-2
# RUN: %lld -dylib %t/align-empty.o %t/align-4-0.o %t/align-16-2.o -o %t/dedup-4-0-16-2
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-4-0-16-2 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=4
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-16-2.o %t/align-4-0.o -o %t/dedup-16-2-4-0
# RUN: %lld -dylib %t/align-empty.o %t/align-16-2.o %t/align-4-0.o -o %t/dedup-16-2-4-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-16-2-4-0 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=4
## Both inputs are 4-byte aligned, one via offset and the other via section alignment
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-4-0.o %t/align-16-4.o -o %t/dedup-4-0-16-4
# RUN: %lld -dylib %t/align-empty.o %t/align-4-0.o %t/align-16-4.o -o %t/dedup-4-0-16-4
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-4-0-16-4 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=4
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-16-4.o %t/align-4-0.o -o %t/dedup-16-4-4-0
# RUN: %lld -dylib %t/align-empty.o %t/align-16-4.o %t/align-4-0.o -o %t/dedup-16-4-4-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-16-4-4-0 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=4
## 8-byte offset vs 4-byte section alignment => align to 8 bytes
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-4-0.o %t/align-16-8.o -o %t/dedup-4-0-16-8
# RUN: %lld -dylib %t/align-empty.o %t/align-4-0.o %t/align-16-8.o -o %t/dedup-4-0-16-8
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-4-0-16-8 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=8
# RUN: %lld -dylib --deduplicate-literals %t/align-empty.o %t/align-16-8.o %t/align-4-0.o -o %t/dedup-16-8-4-0
# RUN: %lld -dylib %t/align-empty.o %t/align-16-8.o %t/align-4-0.o -o %t/dedup-16-8-4-0
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/dedup-16-8-4-0 | \
# RUN: FileCheck %s --check-prefix=DEDUP -D#OFF=8

View File

@@ -2,7 +2,7 @@
# RUN: rm -rf %t; split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/more-foo.s -o %t/more-foo.o
# RUN: %lld -dylib --deduplicate-literals %t/test.o %t/more-foo.o -o %t/test
# RUN: %lld -dylib %t/test.o %t/more-foo.o -o %t/test
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" %t/test | \
# RUN: FileCheck %s --check-prefix=STR --implicit-check-not foo --implicit-check-not bar
# RUN: llvm-objdump --macho --section="__DATA,ptrs" --syms %t/test | FileCheck %s

View File

@@ -318,7 +318,7 @@
# RUN: llvm-mc -g -filetype=obj -triple=x86_64-apple-macos \
# RUN: %t/literals.s -o %t/literals.o
# RUN: %lld -dylib -dead_strip --deduplicate-literals %t/literals.o -o %t/literals
# RUN: %lld -dylib -dead_strip %t/literals.o -o %t/literals
# RUN: llvm-objdump --macho --section="__TEXT,__cstring" --section="__DATA,str_ptrs" \
# RUN: --section="__TEXT,__literals" %t/literals | FileCheck %s --check-prefix=LIT
# LIT: Contents of (__TEXT,__cstring) section

View File

@@ -7,11 +7,11 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/not-terminated.s -o %t/not-terminated.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/relocs.s -o %t/relocs.o
# RUN: not %lld -dylib --deduplicate-literals %t/not-terminated.o 2>&1 | FileCheck %s --check-prefix=TERM
# RUN: not %lld -dylib --deduplicate-literals %t/relocs.o 2>&1 | FileCheck %s --check-prefix=RELOCS
# RUN: not %lld -dylib %t/not-terminated.o 2>&1 | FileCheck %s --check-prefix=TERM
# RUN: not %lld -dylib %t/relocs.o 2>&1 | FileCheck %s --check-prefix=RELOCS
# TERM: not-terminated.o:(__cstring+0x4): string is not null terminated
# RELOCS: relocs.o contains relocations in __TEXT,__cstring, so LLD cannot deduplicate literals. Try re-running without --deduplicate-literals.
# RELOCS: relocs.o contains relocations in __TEXT,__cstring, so LLD cannot deduplicate strings. Try re-running with --no-deduplicate-strings.
#--- not-terminated.s
.cstring

View File

@@ -2,33 +2,14 @@
# RUN: rm -rf %t; split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/qux.s -o %t/qux.o
# RUN: %lld -dylib --deduplicate-literals %t/test.o %t/qux.o -o %t/test
# RUN: %lld -dylib %t/test.o %t/qux.o -o %t/test
# RUN: llvm-objdump --macho --section="__TEXT,__literals" --section="__DATA,ptrs" --syms %t/test | FileCheck %s
# RUN: llvm-readobj --section-headers %t/test | FileCheck %s --check-prefix=HEADER
## Make sure literal deduplication can be overridden or that the later flag wins.
# RUN: %lld -dylib --deduplicate-literals -no_deduplicate %t/test.o %t/qux.o -o %t/no-dedup-test
# RUN: llvm-objdump --macho --section="__TEXT,__literals" --section="__DATA,ptrs" %t/no-dedup-test | FileCheck %s --check-prefix=NO-DEDUP
# RUN: %lld -dylib -no_deduplicate --deduplicate-literals %t/test.o %t/qux.o -o %t/test
# RUN: %lld -dylib -no_deduplicate %t/test.o %t/qux.o -o %t/test
# RUN: llvm-objdump --macho --section="__TEXT,__literals" --section="__DATA,ptrs" --syms %t/test | FileCheck %s
# RUN: llvm-readobj --section-headers %t/test | FileCheck %s --check-prefix=HEADER
# NO-DEDUP-NOT: Contents of (__TEXT,__literals) section
# NO-DEDUP: Contents of (__DATA,ptrs) section
# NO-DEDUP-NEXT: __TEXT:__literal16:0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
# NO-DEDUP-NEXT: __TEXT:__literal16:0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
# NO-DEDUP-NEXT: __TEXT:__literal16:0xfeedface 0xfeedface 0xfeedface 0xfeedface
# NO-DEDUP-NEXT: __TEXT:__literal16:0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
# NO-DEDUP-NEXT: __TEXT:__literal8:0xdeadbeef 0xdeadbeef
# NO-DEDUP-NEXT: __TEXT:__literal8:0xdeadbeef 0xdeadbeef
# NO-DEDUP-NEXT: __TEXT:__literal8:0xfeedface 0xfeedface
# NO-DEDUP-NEXT: __TEXT:__literal8:0xdeadbeef 0xdeadbeef
# NO-DEDUP-NEXT: __TEXT:__literal4:0xdeadbeef
# NO-DEDUP-NEXT: __TEXT:__literal4:0xdeadbeef
# NO-DEDUP-NEXT: __TEXT:__literal4:0xfeedface
# NO-DEDUP-NEXT: __TEXT:__literal4:0xdeadbeef
# CHECK: Contents of (__TEXT,__literals) section
# CHECK-NEXT: [[#%.16x,DEADBEEF16:]] ef be ad de ef be ad de ef be ad de ef be ad de
# CHECK-NEXT: [[#%.16x,FEEDFACE16:]] ce fa ed fe ce fa ed fe ce fa ed fe ce fa ed fe

View File

@@ -7,7 +7,7 @@
# RUN: %lld -dylib %t/baz.o -o %t/libbaz.dylib
# RUN: %lld -demangle -map %t/map %t/test.o %t/foo.o %t/c-string-literal.o \
# RUN: %t/libbaz.dylib --time-trace -o %t/test
# RUN: %t/libbaz.dylib --time-trace -o %t/test --no-deduplicate-strings
# RUN: llvm-objdump --syms --section-headers %t/test > %t/objdump
## Check that symbols in cstring sections aren't emitted
## Also check that we don't have redundant EH_Frame symbols (regression test)

View File

@@ -4,12 +4,12 @@
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/strings.s -o %t/strings.o
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/main.s -o %t/main.o
# RUN: %lld -arch arm64 -lSystem -o %t.out %t/strings.o %t/main.o
# RUN: %lld -arch arm64 -lSystem -o %t.out %t/strings.o %t/main.o --no-deduplicate-strings
# RUN: llvm-otool -vs __TEXT __cstring %t.out | FileCheck %s --check-prefix=CSTRING
# RUN: llvm-otool -vs __TEXT __objc_methname %t.out | FileCheck %s --check-prefix=METHNAME
# RUN: %lld -arch arm64 -lSystem -o %t/duplicates %t/strings.o %t/strings.o %t/main.o --deduplicate-literals
# RUN: %lld -arch arm64 -lSystem -o %t/duplicates %t/strings.o %t/strings.o %t/main.o
# RUN: llvm-otool -vs __TEXT __cstring %t/duplicates | FileCheck %s --check-prefix=CSTRING
# RUN: llvm-otool -vs __TEXT __objc_methname %t/duplicates | FileCheck %s --check-prefix=METHNAME