llvm-project/lld/test/MachO/indirect-symtab.s
Nico Weber 4e572db0c2 [lld/mac] Mark private externs with GOT relocs as LOCAL in indirect symbtab
prepareSymbolRelocation() in Writer.cpp adds both symbols that need binding and
symbols relocated with a pointer relocation to the got.

Pointer relocations are emitted for non-movq GOTPCREL(%rip) loads.  (movqs
become GOT_LOADs so that the linker knows they can be relaxed to leaqs, while
others, such as addq, become just GOT -- a pointer relocation -- since they
can't be relaxed in that way).

For example, this C file produces a private_extern GOT relocation when
compiled with -O2 with clang:

    extern const char kString[];
    const char* g(int a) { return kString + a; }

Linkers need to put pointer-relocated symbols into the GOT, but ld64 marks them
as LOCAL in the indirect symbol table. This matters, since `strip -x` looks at
the indirect symbol table when deciding what to strip.

The indirect symtab emitting code was assuming that only symbols that need
binding are in the GOT, but pointer relocations where there too. Hence, the
code needs to explicitly check if a symbol is a private extern.

Fixes https://crbug.com/1242638, which has some more information in comments 14
and 15. With this patch, the output of `nm -U` on Chromium Framework after
stripping now contains just two symbols when using lld, just like with ld64.

Differential Revision: https://reviews.llvm.org/D111852
2021-10-15 13:24:47 -04:00

79 lines
2.3 KiB
ArmAsm

# REQUIRES: x86
# RUN: rm -rf %t; split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/libfoo.s -o %t/libfoo.o
# 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/bar.s -o %t/bar.o
# RUN: %lld -dylib %t/libfoo.o -o %t/libfoo.dylib -lSystem
# RUN: %lld %t/test.o %t/bar.o %t/libfoo.dylib -o %t/test -lSystem
# RUN: llvm-objdump --macho -d --no-show-raw-insn --indirect-symbols %t/test | FileCheck %s
# RUN: llvm-otool -l %t/test | FileCheck --check-prefix=DYSYMTAB %s
# CHECK: (__TEXT,__text) section
# CHECK-NEXT: _main:
# CHECK-NEXT: movq {{.*}}(%rip), %rax ## literal pool symbol address: _foo
# CHECK-NEXT: movq {{.*}}(%rip), %rax ## literal pool symbol address: _bar
# CHECK-NEXT: leaq _baz(%rip), %rax
# CHECK-NEXT: addq {{.*}}(%rip), %rax
# CHECK-NEXT: movq {{.*}}(%rip), %rax ## literal pool symbol address: _foo_tlv
# CHECK-NEXT: movq {{.*}}(%rip), %rax ## literal pool symbol address: _bar_tlv
# CHECK-NEXT: callq {{.*}} ## symbol stub for: _foo_fn
# CHECK-NEXT: callq {{.*}} ## symbol stub for: _bar_fn
# CHECK-NEXT: retq
# CHECK: Indirect symbols for (__TEXT,__stubs) 2 entries
# CHECK-NEXT: address index name
# CHECK-NEXT: _bar_fn
# CHECK-NEXT: _foo_fn
# CHECK-NEXT: Indirect symbols for (__DATA_CONST,__got) 4 entries
# CHECK-NEXT: address index name
# CHECK-NEXT: LOCAL
# CHECK-NEXT: _bar
# CHECK-NEXT: _foo
# CHECK-NEXT: _stub_binder
# CHECK-NEXT: Indirect symbols for (__DATA,__la_symbol_ptr) 2 entries
# CHECK-NEXT: address index name
# CHECK-NEXT: _bar_fn
# CHECK-NEXT: _foo_fn
# CHECK-NEXT: Indirect symbols for (__DATA,__thread_ptrs) 2 entries
# CHECK-NEXT: address index name
# CHECK-NEXT: _bar_tlv
# CHECK-NEXT: _foo_tlv
# DYSYMTAB: nindirectsyms 10
#--- libfoo.s
.globl _foo, _foo_fn, _bar, _bar_fn
_foo:
_foo_fn:
_bar:
_bar_fn:
.section __DATA,__thread_vars,thread_local_variables
.globl _foo_tlv, _bar_tlv
_foo_tlv:
_bar_tlv:
#--- test.s
.globl _main
_main:
movq _foo@GOTPCREL(%rip), %rax
movq _bar@GOTPCREL(%rip), %rax
movq _baz@GOTPCREL(%rip), %rax
addq _quux@GOTPCREL(%rip), %rax
mov _foo_tlv@TLVP(%rip), %rax
mov _bar_tlv@TLVP(%rip), %rax
callq _foo_fn
callq _bar_fn
ret
#--- bar.s
.data
.globl _baz,_quux
.private_extern _baz,_quux
_baz:
.asciz "baz"
_quux:
.asciz "quux"