From 4e572db0c2ec4e96f8ddfade7384e8ee8ad97384 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 14 Oct 2021 18:32:10 -0400 Subject: [PATCH] [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 --- lld/MachO/SyntheticSections.cpp | 8 +++++-- ...-unwind-both-local-and-dylib-personality.s | 3 ++- lld/test/MachO/indirect-symtab.s | 21 ++++++++++++++++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp index 61fbf7487cc0..81f9224a1d2c 100644 --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -1104,8 +1104,12 @@ void IndirectSymtabSection::finalizeContents() { } static uint32_t indirectValue(const Symbol *sym) { - return sym->symtabIndex != UINT32_MAX ? sym->symtabIndex - : INDIRECT_SYMBOL_LOCAL; + if (sym->symtabIndex == UINT32_MAX) + return INDIRECT_SYMBOL_LOCAL; + if (auto *defined = dyn_cast(sym)) + if (defined->privateExtern) + return INDIRECT_SYMBOL_LOCAL; + return sym->symtabIndex; } void IndirectSymtabSection::writeTo(uint8_t *buf) const { diff --git a/lld/test/MachO/compact-unwind-both-local-and-dylib-personality.s b/lld/test/MachO/compact-unwind-both-local-and-dylib-personality.s index a4ef172d7f7c..933fcd693916 100644 --- a/lld/test/MachO/compact-unwind-both-local-and-dylib-personality.s +++ b/lld/test/MachO/compact-unwind-both-local-and-dylib-personality.s @@ -33,12 +33,13 @@ # A: Indirect symbols for (__DATA_CONST,__got) # A-NEXT: address index name # A-DAG: 0x[[#%x,GXX_PERSONALITY_LO:]] [[#]] ___gxx_personality_v0 -# A-DAG: 0x[[#%x,GXX_PERSONALITY_HI:]] [[#]] ___gxx_personality_v0 +# A-DAG: 0x[[#%x,GXX_PERSONALITY_HI:]] [[#]] ___gxx_personality_v0 # A-DAG: 0x[[#%x,PERSONALITY_1:]] LOCAL # A-DAG: 0x[[#%x,PERSONALITY_2:]] LOCAL # BC: Indirect symbols for (__DATA_CONST,__got) # BC-NEXT: address index name +# BC-DAG: 0x[[#%x,GXX_PERSONALITY_HI:]] LOCAL # BC-DAG: 0x[[#%x,GXX_PERSONALITY_LO:]] LOCAL # BC-DAG: 0x[[#%x,PERSONALITY_1:]] LOCAL # BC-DAG: 0x[[#%x,PERSONALITY_2:]] LOCAL diff --git a/lld/test/MachO/indirect-symtab.s b/lld/test/MachO/indirect-symtab.s index 9c64735e5487..52849ccb8745 100644 --- a/lld/test/MachO/indirect-symtab.s +++ b/lld/test/MachO/indirect-symtab.s @@ -2,8 +2,9 @@ # 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/libfoo.dylib -o %t/test -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 @@ -11,6 +12,8 @@ # 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 @@ -21,8 +24,9 @@ # CHECK-NEXT: address index name # CHECK-NEXT: _bar_fn # CHECK-NEXT: _foo_fn -# CHECK-NEXT: Indirect symbols for (__DATA_CONST,__got) 3 entries +# 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 @@ -35,7 +39,7 @@ # CHECK-NEXT: _bar_tlv # CHECK-NEXT: _foo_tlv -# DYSYMTAB: nindirectsyms 9 +# DYSYMTAB: nindirectsyms 10 #--- libfoo.s @@ -56,8 +60,19 @@ _bar_tlv: _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"