[lld/mac] Implement -dead_strip
Also adds support for live_support sections, no_dead_strip sections,
.no_dead_strip symbols.
Chromium Framework 345MB unstripped -> 250MB stripped
(vs 290MB unstripped -> 236M stripped with ld64).
Doing dead stripping is a bit faster than not, because so much less
data needs to be processed:
% ministat lld_*
x lld_nostrip.txt
+ lld_strip.txt
N Min Max Median Avg Stddev
x 10 3.929414 4.07692 4.0269079 4.0089678 0.044214794
+ 10 3.8129408 3.9025559 3.8670411 3.8642573 0.024779651
Difference at 95.0% confidence
-0.144711 +/- 0.0336749
-3.60967% +/- 0.839989%
(Student's t, pooled s = 0.0358398)
This interacts with many parts of the linker. I tried to add test coverage
for all added `isLive()` checks, so that some test will fail if any of them
is removed. I checked that the test expectations for the most part match
ld64's behavior (except for live-support-iterations.s, see the comment
in the test). Interacts with:
- debug info
- export tries
- import opcodes
- flags like -exported_symbol(s_list)
- -U / dynamic_lookup
- mod_init_funcs, mod_term_funcs
- weak symbol handling
- unwind info
- stubs
- map files
- -sectcreate
- undefined, dylib, common, defined (both absolute and normal) symbols
It's possible it interacts with more features I didn't think of,
of course.
I also did some manual testing:
- check-llvm check-clang check-lld work with lld with this patch
as host linker and -dead_strip enabled
- Chromium still starts
- Chromium's base_unittests still pass, including unwind tests
Implemenation-wise, this is InputSection-based, so it'll work for
object files with .subsections_via_symbols (which includes all
object files generated by clang). I first based this on the COFF
implementation, but later realized that things are more similar to ELF.
I think it'd be good to refactor MarkLive.cpp to look more like the ELF
part at some point, but I'd like to get a working state checked in first.
Mechanical parts:
- Rename canOmitFromOutput to wasCoalesced (no behavior change)
since it really is for weak coalesced symbols
- Add noDeadStrip to Defined, corresponding to N_NO_DEAD_STRIP
(`.no_dead_strip` in asm)
Fixes PR49276.
Differential Revision: https://reviews.llvm.org/D103324
2021-05-08 05:10:05 +08:00
|
|
|
# REQUIRES: x86
|
|
|
|
|
|
|
|
# RUN: rm -rf %t; split-file %s %t
|
|
|
|
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/basics.s -o %t/basics.o
|
|
|
|
|
|
|
|
## Check that .private_extern symbols are marked as local in the symbol table
|
|
|
|
## and aren't in the export trie.
|
|
|
|
## Dead-stripped symbols should also not be in a map file output.
|
|
|
|
# RUN: %lld -lSystem -dead_strip -map %t/map -u _ref_private_extern_u \
|
|
|
|
# RUN: %t/basics.o -o %t/basics
|
|
|
|
# RUN: llvm-objdump --syms --section-headers %t/basics | \
|
|
|
|
# RUN: FileCheck --check-prefix=EXEC --implicit-check-not _unref %s
|
|
|
|
# RUN: llvm-objdump --macho --section=__DATA,__ref_section \
|
|
|
|
# RUN: --exports-trie --indirect-symbols %t/basics | \
|
|
|
|
# RUN: FileCheck --check-prefix=EXECDATA --implicit-check-not _unref %s
|
|
|
|
# RUN: llvm-otool -l %t/basics | grep -q 'segname __PAGEZERO'
|
|
|
|
# RUN: FileCheck --check-prefix=MAP --implicit-check-not _unref %s < %t/map
|
|
|
|
# EXEC-LABEL: Sections:
|
|
|
|
# EXEC-LABEL: Name
|
|
|
|
# EXEC-NEXT: __text
|
|
|
|
# EXEC-NEXT: __got
|
|
|
|
# EXEC-NEXT: __ref_section
|
|
|
|
# EXEC-NEXT: __common
|
|
|
|
# EXEC-LABEL: SYMBOL TABLE:
|
|
|
|
# EXEC-NEXT: l {{.*}} _ref_data
|
|
|
|
# EXEC-NEXT: l {{.*}} _ref_local
|
|
|
|
# EXEC-NEXT: l {{.*}} _ref_from_no_dead_strip_globl
|
|
|
|
# EXEC-NEXT: l {{.*}} _no_dead_strip_local
|
|
|
|
# EXEC-NEXT: l {{.*}} _ref_from_no_dead_strip_local
|
|
|
|
# EXEC-NEXT: l {{.*}} _ref_private_extern_u
|
|
|
|
# EXEC-NEXT: l {{.*}} _main
|
|
|
|
# EXEC-NEXT: l {{.*}} _ref_private_extern
|
|
|
|
# EXEC-NEXT: g {{.*}} _ref_com
|
|
|
|
# EXEC-NEXT: g {{.*}} _no_dead_strip_globl
|
|
|
|
# EXEC-NEXT: g {{.*}} __mh_execute_header
|
|
|
|
# EXECDATA-LABEL: Indirect symbols
|
|
|
|
# EXECDATA-NEXT: name
|
|
|
|
# EXECDATA-NEXT: _ref_com
|
|
|
|
# EXECDATA-LABEL: Contents of (__DATA,__ref_section) section
|
|
|
|
# EXECDATA-NEXT: 04 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00
|
|
|
|
# EXECDATA-LABEL: Exports trie:
|
|
|
|
# EXECDATA-NEXT: __mh_execute_header
|
|
|
|
# EXECDATA-NEXT: _ref_com
|
|
|
|
# EXECDATA-NEXT: _no_dead_strip_globl
|
|
|
|
# MAP: _main
|
|
|
|
|
|
|
|
# RUN: %lld -dylib -dead_strip -u _ref_private_extern_u %t/basics.o -o %t/basics.dylib
|
|
|
|
# RUN: llvm-objdump --syms %t/basics.dylib | \
|
|
|
|
# RUN: FileCheck --check-prefix=DYLIB --implicit-check-not _unref %s
|
|
|
|
# RUN: %lld -bundle -dead_strip -u _ref_private_extern_u %t/basics.o -o %t/basics.dylib
|
|
|
|
# RUN: llvm-objdump --syms %t/basics.dylib | \
|
|
|
|
# RUN: FileCheck --check-prefix=DYLIB --implicit-check-not _unref %s
|
|
|
|
# DYLIB-LABEL: SYMBOL TABLE:
|
|
|
|
# DYLIB-NEXT: l {{.*}} _ref_data
|
|
|
|
# DYLIB-NEXT: l {{.*}} _ref_local
|
|
|
|
# DYLIB-NEXT: l {{.*}} _ref_from_no_dead_strip_globl
|
|
|
|
# DYLIB-NEXT: l {{.*}} _no_dead_strip_local
|
|
|
|
# DYLIB-NEXT: l {{.*}} _ref_from_no_dead_strip_local
|
|
|
|
# DYLIB-NEXT: l {{.*}} _ref_private_extern_u
|
|
|
|
# DYLIB-NEXT: l {{.*}} _ref_private_extern
|
|
|
|
# DYLIB-NEXT: g {{.*}} _ref_com
|
|
|
|
# DYLIB-NEXT: g {{.*}} _unref_com
|
|
|
|
# DYLIB-NEXT: g {{.*}} _unref_extern
|
|
|
|
# DYLIB-NEXT: g {{.*}} _no_dead_strip_globl
|
|
|
|
|
|
|
|
## Absolute symbol handling.
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/abs.s -o %t/abs.o
|
|
|
|
# RUN: %lld -lSystem -dead_strip %t/abs.o -o %t/abs
|
|
|
|
# RUN: llvm-objdump --macho --syms --exports-trie %t/abs | \
|
|
|
|
# RUN: FileCheck --check-prefix=ABS %s
|
|
|
|
#ABS-LABEL: SYMBOL TABLE:
|
|
|
|
#ABS-NEXT: g {{.*}} _main
|
|
|
|
#ABS-NEXT: g *ABS* _abs1
|
|
|
|
#ABS-NEXT: g {{.*}} __mh_execute_header
|
|
|
|
#ABS-LABEL: Exports trie:
|
|
|
|
#ABS-NEXT: __mh_execute_header
|
|
|
|
#ABS-NEXT: _main
|
|
|
|
#ABS-NEXT: _abs1 [absolute]
|
|
|
|
|
|
|
|
## Check that symbols from -exported_symbol(s_list) are preserved.
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/exported-symbol.s -o %t/exported-symbol.o
|
|
|
|
# RUN: %lld -lSystem -dead_strip -exported_symbol _my_exported_symbol \
|
|
|
|
# RUN: %t/exported-symbol.o -o %t/exported-symbol
|
|
|
|
# RUN: llvm-objdump --syms %t/exported-symbol | \
|
|
|
|
# RUN: FileCheck --check-prefix=EXPORTEDSYMBOL --implicit-check-not _unref %s
|
|
|
|
# EXPORTEDSYMBOL-LABEL: SYMBOL TABLE:
|
|
|
|
# EXPORTEDSYMBOL-NEXT: l {{.*}} _main
|
|
|
|
# EXPORTEDSYMBOL-NEXT: l {{.*}} __mh_execute_header
|
|
|
|
# EXPORTEDSYMBOL-NEXT: g {{.*}} _my_exported_symbol
|
|
|
|
|
|
|
|
## Check that mod_init_funcs and mod_term_funcs are not stripped.
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/mod-funcs.s -o %t/mod-funcs.o
|
|
|
|
# RUN: %lld -lSystem -dead_strip %t/mod-funcs.o -o %t/mod-funcs
|
|
|
|
# RUN: llvm-objdump --syms %t/mod-funcs | \
|
|
|
|
# RUN: FileCheck --check-prefix=MODFUNCS --implicit-check-not _unref %s
|
|
|
|
# MODFUNCS-LABEL: SYMBOL TABLE:
|
|
|
|
# MODFUNCS-NEXT: l {{.*}} _ref_from_init
|
|
|
|
# MODFUNCS-NEXT: l {{.*}} _ref_init
|
|
|
|
# MODFUNCS-NEXT: l {{.*}} _ref_from_term
|
|
|
|
# MODFUNCS-NEXT: l {{.*}} _ref_term
|
|
|
|
# MODFUNCS-NEXT: g {{.*}} _main
|
|
|
|
# MODFUNCS-NEXT: g {{.*}} __mh_execute_header
|
|
|
|
|
|
|
|
## Check that DylibSymbols in dead subsections are stripped: They should
|
|
|
|
## not be in the import table and should have no import stubs.
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/dylib.s -o %t/dylib.o
|
|
|
|
# RUN: %lld -dylib -dead_strip %t/dylib.o -o %t/dylib.dylib
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/strip-dylib-ref.s -o %t/strip-dylib-ref.o
|
|
|
|
# RUN: %lld -lSystem -dead_strip %t/strip-dylib-ref.o %t/dylib.dylib \
|
|
|
|
# RUN: -o %t/strip-dylib-ref -U _ref_undef_fun -U _unref_undef_fun
|
|
|
|
# RUN: llvm-objdump --syms --bind --lazy-bind --weak-bind %t/strip-dylib-ref | \
|
|
|
|
# RUN: FileCheck --check-prefix=STRIPDYLIB --implicit-check-not _unref %s
|
|
|
|
# STRIPDYLIB: SYMBOL TABLE:
|
|
|
|
# STRIPDYLIB-NEXT: l {{.*}} __dyld_private
|
|
|
|
# STRIPDYLIB-NEXT: g {{.*}} _main
|
|
|
|
# STRIPDYLIB-NEXT: g {{.*}} __mh_execute_header
|
|
|
|
# STRIPDYLIB-NEXT: *UND* _ref_undef_fun
|
|
|
|
# STRIPDYLIB-NEXT: *UND* dyld_stub_binder
|
|
|
|
# STRIPDYLIB-NEXT: *UND* _ref_dylib_fun
|
|
|
|
# STRIPDYLIB: Bind table:
|
|
|
|
# STRIPDYLIB: Lazy bind table:
|
|
|
|
# STRIPDYLIB: __DATA __la_symbol_ptr {{.*}} flat-namespace _ref_undef_fun
|
|
|
|
# STRIPDYLIB: __DATA __la_symbol_ptr {{.*}} dylib _ref_dylib_fun
|
|
|
|
# STRIPDYLIB: Weak bind table:
|
|
|
|
## Stubs smoke check: There should be two stubs entries, not four, but we
|
|
|
|
## don't verify that they belong to _ref_undef_fun and _ref_dylib_fun.
|
|
|
|
# RUN: llvm-objdump -d --section=__stubs --section=__stub_helper \
|
|
|
|
# RUN: %t/strip-dylib-ref |FileCheck --check-prefix=STUBS %s
|
|
|
|
# STUBS-LABEL: <__stubs>:
|
|
|
|
# STUBS-NEXT: jmpq
|
|
|
|
# STUBS-NEXT: jmpq
|
|
|
|
# STUBS-NOT: jmpq
|
|
|
|
# STUBS-LABEL: <__stub_helper>:
|
|
|
|
# STUBS: pushq $0
|
|
|
|
# STUBS: jmp
|
|
|
|
# STUBS: jmp
|
|
|
|
# STUBS-NOT: jmp
|
|
|
|
## An undefined symbol referenced from a dead-stripped function shouldn't
|
|
|
|
## produce a diagnostic:
|
|
|
|
# RUN: %lld -lSystem -dead_strip %t/strip-dylib-ref.o %t/dylib.dylib \
|
|
|
|
# RUN: -o %t/strip-dylib-ref -U _ref_undef_fun
|
|
|
|
|
|
|
|
## S_ATTR_LIVE_SUPPORT tests.
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/live-support.s -o %t/live-support.o
|
|
|
|
# RUN: %lld -lSystem -dead_strip %t/live-support.o %t/dylib.dylib \
|
|
|
|
# RUN: -U _ref_undef_fun -U _unref_undef_fun -o %t/live-support
|
|
|
|
# RUN: llvm-objdump --syms %t/live-support | \
|
|
|
|
# RUN: FileCheck --check-prefix=LIVESUPP --implicit-check-not _unref %s
|
|
|
|
# LIVESUPP-LABEL: SYMBOL TABLE:
|
|
|
|
# LIVESUPP-NEXT: l {{.*}} _ref_ls_fun_fw
|
|
|
|
# LIVESUPP-NEXT: l {{.*}} _ref_ls_fun_bw
|
|
|
|
# LIVESUPP-NEXT: l {{.*}} _ref_ls_dylib_fun
|
|
|
|
# LIVESUPP-NEXT: l {{.*}} _ref_ls_undef_fun
|
|
|
|
# LIVESUPP-NEXT: l {{.*}} __dyld_private
|
|
|
|
# LIVESUPP-NEXT: g {{.*}} _main
|
|
|
|
# LIVESUPP-NEXT: g {{.*}} _bar
|
|
|
|
# LIVESUPP-NEXT: g {{.*}} _foo
|
|
|
|
# LIVESUPP-NEXT: g {{.*}} __mh_execute_header
|
|
|
|
# LIVESUPP-NEXT: *UND* _ref_undef_fun
|
|
|
|
# LIVESUPP-NEXT: *UND* dyld_stub_binder
|
|
|
|
# LIVESUPP-NEXT: *UND* _ref_dylib_fun
|
|
|
|
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/live-support-iterations.s -o %t/live-support-iterations.o
|
|
|
|
# RUN: %lld -lSystem -dead_strip %t/live-support-iterations.o \
|
|
|
|
# RUN: -o %t/live-support-iterations
|
|
|
|
# RUN: llvm-objdump --syms %t/live-support-iterations | \
|
|
|
|
# RUN: FileCheck --check-prefix=LIVESUPP2 --implicit-check-not _unref %s
|
|
|
|
# LIVESUPP2-LABEL: SYMBOL TABLE:
|
|
|
|
# LIVESUPP2-NEXT: l {{.*}} _bar
|
|
|
|
# LIVESUPP2-NEXT: l {{.*}} _foo_refd
|
|
|
|
# LIVESUPP2-NEXT: l {{.*}} _bar_refd
|
|
|
|
# LIVESUPP2-NEXT: l {{.*}} _baz
|
|
|
|
# LIVESUPP2-NEXT: l {{.*}} _baz_refd
|
|
|
|
# LIVESUPP2-NEXT: l {{.*}} _foo
|
|
|
|
# LIVESUPP2-NEXT: g {{.*}} _main
|
|
|
|
# LIVESUPP2-NEXT: g {{.*}} __mh_execute_header
|
|
|
|
|
|
|
|
## Dead stripping should not remove the __TEXT,__unwind_info
|
|
|
|
## and __TEXT,__gcc_except_tab functions, but it should still
|
|
|
|
## remove the unreferenced function __Z5unref.
|
|
|
|
## The reference to ___gxx_personality_v0 should also not be
|
|
|
|
## stripped.
|
|
|
|
## (Need to use darwin19.0.0 to make -mc emit __LD,__compact_unwind.)
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 \
|
|
|
|
# RUN: %t/unwind.s -o %t/unwind.o
|
|
|
|
# RUN: %lld -lc++ -lSystem -dead_strip %t/unwind.o -o %t/unwind
|
|
|
|
# RUN: llvm-objdump --syms %t/unwind | \
|
|
|
|
# RUN: FileCheck --check-prefix=UNWIND --implicit-check-not unref %s
|
2021-06-02 23:33:08 +08:00
|
|
|
# RUN: llvm-otool -l %t/unwind | FileCheck --check-prefix=UNWINDSECT %s
|
|
|
|
# UNWINDSECT-DAG: sectname __unwind_info
|
|
|
|
# UNWINDSECT-DAG: sectname __gcc_except_tab
|
[lld/mac] Implement -dead_strip
Also adds support for live_support sections, no_dead_strip sections,
.no_dead_strip symbols.
Chromium Framework 345MB unstripped -> 250MB stripped
(vs 290MB unstripped -> 236M stripped with ld64).
Doing dead stripping is a bit faster than not, because so much less
data needs to be processed:
% ministat lld_*
x lld_nostrip.txt
+ lld_strip.txt
N Min Max Median Avg Stddev
x 10 3.929414 4.07692 4.0269079 4.0089678 0.044214794
+ 10 3.8129408 3.9025559 3.8670411 3.8642573 0.024779651
Difference at 95.0% confidence
-0.144711 +/- 0.0336749
-3.60967% +/- 0.839989%
(Student's t, pooled s = 0.0358398)
This interacts with many parts of the linker. I tried to add test coverage
for all added `isLive()` checks, so that some test will fail if any of them
is removed. I checked that the test expectations for the most part match
ld64's behavior (except for live-support-iterations.s, see the comment
in the test). Interacts with:
- debug info
- export tries
- import opcodes
- flags like -exported_symbol(s_list)
- -U / dynamic_lookup
- mod_init_funcs, mod_term_funcs
- weak symbol handling
- unwind info
- stubs
- map files
- -sectcreate
- undefined, dylib, common, defined (both absolute and normal) symbols
It's possible it interacts with more features I didn't think of,
of course.
I also did some manual testing:
- check-llvm check-clang check-lld work with lld with this patch
as host linker and -dead_strip enabled
- Chromium still starts
- Chromium's base_unittests still pass, including unwind tests
Implemenation-wise, this is InputSection-based, so it'll work for
object files with .subsections_via_symbols (which includes all
object files generated by clang). I first based this on the COFF
implementation, but later realized that things are more similar to ELF.
I think it'd be good to refactor MarkLive.cpp to look more like the ELF
part at some point, but I'd like to get a working state checked in first.
Mechanical parts:
- Rename canOmitFromOutput to wasCoalesced (no behavior change)
since it really is for weak coalesced symbols
- Add noDeadStrip to Defined, corresponding to N_NO_DEAD_STRIP
(`.no_dead_strip` in asm)
Fixes PR49276.
Differential Revision: https://reviews.llvm.org/D103324
2021-05-08 05:10:05 +08:00
|
|
|
# UNWIND-LABEL: SYMBOL TABLE:
|
|
|
|
# UNWIND-NEXT: l O __TEXT,__gcc_except_tab GCC_except_table1
|
|
|
|
# UNWIND-NEXT: l O __DATA,__data __dyld_private
|
|
|
|
# UNWIND-NEXT: g F __TEXT,__text _main
|
|
|
|
# UNWIND-NEXT: g F __TEXT,__text __mh_execute_header
|
|
|
|
# UNWIND-NEXT: *UND* ___cxa_allocate_exception
|
|
|
|
# UNWIND-NEXT: *UND* ___cxa_end_catch
|
|
|
|
# UNWIND-NEXT: *UND* __ZTIi
|
|
|
|
# UNWIND-NEXT: *UND* ___cxa_throw
|
|
|
|
# UNWIND-NEXT: *UND* ___gxx_personality_v0
|
|
|
|
# UNWIND-NEXT: *UND* ___cxa_begin_catch
|
|
|
|
# UNWIND-NEXT: *UND* dyld_stub_binder
|
|
|
|
|
|
|
|
## If a dead stripped function has a strong ref to a dylib symbol but
|
|
|
|
## a live function only a weak ref, the dylib is still not a WEAK_DYLIB.
|
|
|
|
## This matches ld64.
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/weak-ref.s -o %t/weak-ref.o
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/strong-dead-ref.s -o %t/strong-dead-ref.o
|
|
|
|
# RUN: %lld -lSystem -dead_strip %t/weak-ref.o %t/strong-dead-ref.o \
|
|
|
|
# RUN: %t/dylib.dylib -o %t/weak-ref
|
|
|
|
# RUN: llvm-otool -l %t/weak-ref | FileCheck -DDIR=%t --check-prefix=WEAK %s
|
|
|
|
# WEAK: cmd LC_LOAD_DYLIB
|
|
|
|
# WEAK-NEXT: cmdsize
|
|
|
|
# WEAK-NEXT: name /usr/lib/libSystem.dylib
|
|
|
|
# WEAK: cmd LC_LOAD_DYLIB
|
|
|
|
# WEAK-NEXT: cmdsize
|
|
|
|
# WEAK-NEXT: name [[DIR]]/dylib.dylib
|
|
|
|
|
|
|
|
## A strong symbol that would override a weak import does not emit the
|
|
|
|
## "this overrides a weak import" opcode if it is dead-stripped.
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/weak-dylib.s -o %t/weak-dylib.o
|
|
|
|
# RUN: %lld -dylib -dead_strip %t/weak-dylib.o -o %t/weak-dylib.dylib
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/dead-weak-override.s -o %t/dead-weak-override.o
|
|
|
|
# RUN: %lld -dead_strip %t/dead-weak-override.o %t/weak-dylib.dylib \
|
|
|
|
# RUN: -o %t/dead-weak-override
|
|
|
|
# RUN: llvm-objdump --macho --weak-bind --private-header \
|
|
|
|
# RUN: %t/dead-weak-override | FileCheck --check-prefix=DEADWEAK %s
|
|
|
|
# DEADWEAK-NOT: WEAK_DEFINES
|
|
|
|
# DEADWEAK: Weak bind table:
|
|
|
|
# DEADWEAK: segment section address type addend symbol
|
|
|
|
# DEADWEAK-NOT: strong _weak_in_dylib
|
|
|
|
|
|
|
|
## Stripped symbols should not be in the debug info stabs entries.
|
|
|
|
# RUN: llvm-mc -g -filetype=obj -triple=x86_64-apple-macos \
|
|
|
|
# RUN: %t/debug.s -o %t/debug.o
|
|
|
|
# RUN: %lld -lSystem -dead_strip %t/debug.o -o %t/debug
|
|
|
|
# RUN: dsymutil -s %t/debug | FileCheck --check-prefix=EXECSTABS %s
|
|
|
|
# EXECSTABS-NOT: N_FUN {{.*}} '_unref'
|
|
|
|
# EXECSTABS: N_FUN {{.*}} '_main'
|
|
|
|
# EXECSTABS-NOT: N_FUN {{.*}} '_unref'
|
|
|
|
|
|
|
|
#--- basics.s
|
|
|
|
.comm _ref_com, 1
|
|
|
|
.comm _unref_com, 1
|
|
|
|
|
|
|
|
.section __DATA,__unref_section
|
|
|
|
_unref_data:
|
|
|
|
.quad 4
|
|
|
|
|
|
|
|
l_unref_data:
|
|
|
|
.quad 5
|
|
|
|
|
|
|
|
## Referenced by no_dead_strip == S_ATTR_NO_DEAD_STRIP
|
|
|
|
.section __DATA,__ref_section,regular,no_dead_strip
|
|
|
|
|
|
|
|
## Referenced because in no_dead_strip section.
|
|
|
|
_ref_data:
|
|
|
|
.quad 4
|
|
|
|
|
|
|
|
## This is a local symbol so it's not in the symbol table, but
|
|
|
|
## it is still in the section data.
|
|
|
|
l_ref_data:
|
|
|
|
.quad 5
|
|
|
|
|
|
|
|
.text
|
|
|
|
|
|
|
|
# Exported symbols should not be stripped from dylibs
|
|
|
|
# or bundles, but they should be stripped from executables.
|
|
|
|
.globl _unref_extern
|
|
|
|
_unref_extern:
|
|
|
|
callq _ref_local
|
|
|
|
retq
|
|
|
|
|
|
|
|
# Unreferenced local symbols should be stripped.
|
|
|
|
_unref_local:
|
|
|
|
retq
|
|
|
|
|
|
|
|
# Same for unreferenced private externs.
|
|
|
|
.globl _unref_private_extern
|
|
|
|
.private_extern _unref_private_extern
|
|
|
|
_unref_private_extern:
|
|
|
|
# This shouldn't create an indirect symbol since it's
|
|
|
|
# a reference from a dead function.
|
|
|
|
movb _unref_com@GOTPCREL(%rip), %al
|
|
|
|
retq
|
|
|
|
|
|
|
|
# Referenced local symbols should not be stripped.
|
|
|
|
_ref_local:
|
|
|
|
callq _ref_private_extern
|
|
|
|
retq
|
|
|
|
|
|
|
|
# Same for referenced private externs.
|
|
|
|
# This one is referenced by a relocation.
|
|
|
|
.globl _ref_private_extern
|
|
|
|
.private_extern _ref_private_extern
|
|
|
|
_ref_private_extern:
|
|
|
|
retq
|
|
|
|
|
|
|
|
# This one is referenced by a -u flag.
|
|
|
|
.globl _ref_private_extern_u
|
|
|
|
.private_extern _ref_private_extern_u
|
|
|
|
_ref_private_extern_u:
|
|
|
|
retq
|
|
|
|
|
|
|
|
# Entry point should not be stripped for executables, even if hidden.
|
|
|
|
# For shared libraries this is stripped since it's just a regular hidden
|
|
|
|
# symbol there.
|
|
|
|
.globl _main
|
|
|
|
.private_extern _main
|
|
|
|
_main:
|
|
|
|
movb _ref_com@GOTPCREL(%rip), %al
|
|
|
|
callq _ref_local
|
|
|
|
retq
|
|
|
|
|
|
|
|
# Things marked no_dead_strip should not be stripped either.
|
|
|
|
# (clang emits this e.g. for `__attribute__((used))` globals.)
|
|
|
|
# Both for .globl symbols...
|
|
|
|
.globl _no_dead_strip_globl
|
|
|
|
.no_dead_strip _no_dead_strip_globl
|
|
|
|
_no_dead_strip_globl:
|
|
|
|
callq _ref_from_no_dead_strip_globl
|
|
|
|
retq
|
|
|
|
_ref_from_no_dead_strip_globl:
|
|
|
|
retq
|
|
|
|
|
|
|
|
# ...and for locals.
|
|
|
|
.no_dead_strip _no_dead_strip_local
|
|
|
|
_no_dead_strip_local:
|
|
|
|
callq _ref_from_no_dead_strip_local
|
|
|
|
retq
|
|
|
|
_ref_from_no_dead_strip_local:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- exported-symbol.s
|
|
|
|
.text
|
|
|
|
|
|
|
|
.globl _unref_symbol
|
|
|
|
_unref_symbol:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _my_exported_symbol
|
|
|
|
_my_exported_symbol:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _main
|
|
|
|
_main:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- abs.s
|
|
|
|
.globl _abs1, _abs2, _abs3
|
|
|
|
|
|
|
|
.no_dead_strip _abs1
|
|
|
|
_abs1 = 1
|
|
|
|
_abs2 = 2
|
|
|
|
_abs3 = 3
|
|
|
|
|
|
|
|
.section __DATA,__foo,regular,no_dead_strip
|
|
|
|
# Absolute symbols are not in a section, so the no_dead_strip
|
|
|
|
# on the section above has no effect.
|
|
|
|
.globl _abs4
|
|
|
|
_abs4 = 4
|
|
|
|
|
|
|
|
.text
|
|
|
|
.globl _main
|
|
|
|
_main:
|
|
|
|
# This is relaxed away, so there's no relocation here and
|
|
|
|
# _abs3 isn't in the exported symbol table.
|
|
|
|
mov _abs3, %rax
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- mod-funcs.s
|
|
|
|
## Roughly based on `clang -O2 -S` output for `struct A { A(); ~A(); }; A a;`
|
|
|
|
## for mod_init_funcs. mod_term_funcs then similar to that.
|
|
|
|
.section __TEXT,__StaticInit,regular,pure_instructions
|
|
|
|
|
|
|
|
__unref:
|
|
|
|
retq
|
|
|
|
|
|
|
|
_ref_from_init:
|
|
|
|
retq
|
|
|
|
|
|
|
|
_ref_init:
|
|
|
|
callq _ref_from_init
|
|
|
|
retq
|
|
|
|
|
|
|
|
_ref_from_term:
|
|
|
|
retq
|
|
|
|
|
|
|
|
_ref_term:
|
|
|
|
callq _ref_from_term
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _main
|
|
|
|
_main:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.section __DATA,__mod_init_func,mod_init_funcs
|
|
|
|
.quad _ref_init
|
|
|
|
|
|
|
|
.section __DATA,__mod_term_func,mod_term_funcs
|
|
|
|
.quad _ref_term
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- dylib.s
|
|
|
|
.text
|
|
|
|
|
|
|
|
.globl _ref_dylib_fun
|
|
|
|
_ref_dylib_fun:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _unref_dylib_fun
|
|
|
|
_unref_dylib_fun:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- strip-dylib-ref.s
|
|
|
|
.text
|
|
|
|
|
|
|
|
_unref:
|
|
|
|
callq _ref_dylib_fun
|
|
|
|
callq _unref_dylib_fun
|
|
|
|
callq _ref_undef_fun
|
|
|
|
callq _unref_undef_fun
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _main
|
|
|
|
_main:
|
|
|
|
callq _ref_dylib_fun
|
|
|
|
callq _ref_undef_fun
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- live-support.s
|
|
|
|
## In practice, live_support is used for instruction profiling
|
|
|
|
## data and asan. (Also for __eh_frame, but that needs special handling
|
|
|
|
## in the linker anyways.)
|
|
|
|
## This test isn't based on anything happening in real code though.
|
|
|
|
.section __TEXT,__ref_ls_fw,regular,live_support
|
|
|
|
_ref_ls_fun_fw:
|
|
|
|
# This is called by _main and is kept alive by normal
|
|
|
|
# forward liveness propagation, The live_support attribute
|
|
|
|
# does nothing in this case.
|
|
|
|
retq
|
|
|
|
|
|
|
|
.section __TEXT,__unref_ls_fw,regular,live_support
|
|
|
|
_unref_ls_fun_fw:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.section __TEXT,__ref_ls_bw,regular,live_support
|
|
|
|
_ref_ls_fun_bw:
|
|
|
|
# This _calls_ something that's alive but isn't referenced itself. This is
|
|
|
|
# kept alive only due to this being in a live_support section.
|
|
|
|
callq _foo
|
|
|
|
|
|
|
|
# _bar on the other hand is kept alive since it's called from here.
|
|
|
|
callq _bar
|
|
|
|
retq
|
|
|
|
|
|
|
|
## Kept alive by a live symbol form a dynamic library.
|
|
|
|
_ref_ls_dylib_fun:
|
|
|
|
callq _ref_dylib_fun
|
|
|
|
retq
|
|
|
|
|
|
|
|
## Kept alive by a live undefined symbol.
|
|
|
|
_ref_ls_undef_fun:
|
|
|
|
callq _ref_undef_fun
|
|
|
|
retq
|
|
|
|
|
|
|
|
## All symbols in this live_support section reference dead symbols
|
|
|
|
## and are hence dead themselves.
|
|
|
|
.section __TEXT,__unref_ls_bw,regular,live_support
|
|
|
|
_unref_ls_fun_bw:
|
|
|
|
callq _unref
|
|
|
|
retq
|
|
|
|
|
|
|
|
_unref_ls_dylib_fun_bw:
|
|
|
|
callq _unref_dylib_fun
|
|
|
|
retq
|
|
|
|
|
|
|
|
_unref_ls_undef_fun_bw:
|
|
|
|
callq _unref_undef_fun
|
|
|
|
retq
|
|
|
|
|
|
|
|
.text
|
|
|
|
.globl _unref
|
|
|
|
_unref:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _bar
|
|
|
|
_bar:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _foo
|
|
|
|
_foo:
|
|
|
|
callq _ref_ls_fun_fw
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _main
|
|
|
|
_main:
|
|
|
|
callq _ref_ls_fun_fw
|
|
|
|
callq _foo
|
|
|
|
callq _ref_dylib_fun
|
|
|
|
callq _ref_undef_fun
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- live-support-iterations.s
|
|
|
|
.section __TEXT,_ls,regular,live_support
|
|
|
|
|
|
|
|
## This is a live_support subsection that only becomes
|
|
|
|
## live after _foo below is processed. This means the algorithm of
|
|
|
|
## 1. mark things reachable from gc roots live
|
|
|
|
## 2. go through live sections and mark the ones live pointing to
|
|
|
|
## live symbols or sections
|
|
|
|
## needs more than one iteration, since _bar won't be live when step 2
|
|
|
|
## runs for the first time.
|
|
|
|
## (ld64 gets this wrong -- it has different output based on if _bar is
|
|
|
|
## before _foo or after it.)
|
|
|
|
_bar:
|
|
|
|
callq _foo_refd
|
|
|
|
callq _bar_refd
|
|
|
|
retq
|
|
|
|
|
|
|
|
## Same here. This is maybe more interesting since it references a live_support
|
|
|
|
## symbol instead of a "normal" symbol.
|
|
|
|
_baz:
|
|
|
|
callq _foo_refd
|
|
|
|
callq _baz_refd
|
|
|
|
retq
|
|
|
|
|
|
|
|
_foo:
|
|
|
|
callq _main
|
|
|
|
callq _foo_refd
|
|
|
|
retq
|
|
|
|
|
|
|
|
## Test no_dead_strip on a symbol in a live_support section.
|
|
|
|
## ld64 ignores this, but that doesn't look intentional. So lld honors it.
|
|
|
|
.no_dead_strip
|
|
|
|
_quux:
|
|
|
|
retq
|
|
|
|
|
|
|
|
|
|
|
|
.text
|
|
|
|
.globl _main
|
|
|
|
_main:
|
|
|
|
movq $0, %rax
|
|
|
|
retq
|
|
|
|
|
|
|
|
_foo_refd:
|
|
|
|
retq
|
|
|
|
|
|
|
|
_bar_refd:
|
|
|
|
retq
|
|
|
|
|
|
|
|
_baz_refd:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- unwind.s
|
|
|
|
## This is the output of `clang -O2 -S throw.cc` where throw.cc
|
|
|
|
## looks like this:
|
|
|
|
## void unref() {}
|
|
|
|
## int main() {
|
|
|
|
## try {
|
|
|
|
## throw 0;
|
|
|
|
## } catch (int i) {
|
|
|
|
## return i;
|
|
|
|
## }
|
|
|
|
## }
|
|
|
|
.section __TEXT,__text,regular,pure_instructions
|
|
|
|
|
|
|
|
.globl __Z5unrefv
|
|
|
|
.p2align 4, 0x90
|
|
|
|
__Z5unrefv:
|
|
|
|
.cfi_startproc
|
|
|
|
pushq %rbp
|
|
|
|
.cfi_def_cfa_offset 16
|
|
|
|
.cfi_offset %rbp, -16
|
|
|
|
movq %rsp, %rbp
|
|
|
|
.cfi_def_cfa_register %rbp
|
|
|
|
popq %rbp
|
|
|
|
retq
|
|
|
|
.cfi_endproc
|
|
|
|
|
|
|
|
.globl _main
|
|
|
|
.p2align 4, 0x90
|
|
|
|
_main:
|
|
|
|
Lfunc_begin0:
|
|
|
|
.cfi_startproc
|
|
|
|
.cfi_personality 155, ___gxx_personality_v0
|
|
|
|
.cfi_lsda 16, Lexception0
|
|
|
|
pushq %rbp
|
|
|
|
.cfi_def_cfa_offset 16
|
|
|
|
.cfi_offset %rbp, -16
|
|
|
|
movq %rsp, %rbp
|
|
|
|
.cfi_def_cfa_register %rbp
|
|
|
|
pushq %rbx
|
|
|
|
pushq %rax
|
|
|
|
.cfi_offset %rbx, -24
|
|
|
|
movl $4, %edi
|
|
|
|
callq ___cxa_allocate_exception
|
|
|
|
movl $0, (%rax)
|
|
|
|
Ltmp0:
|
|
|
|
movq __ZTIi@GOTPCREL(%rip), %rsi
|
|
|
|
movq %rax, %rdi
|
|
|
|
xorl %edx, %edx
|
|
|
|
callq ___cxa_throw
|
|
|
|
Ltmp1:
|
|
|
|
ud2
|
|
|
|
LBB1_2:
|
|
|
|
Ltmp2:
|
|
|
|
movq %rax, %rdi
|
|
|
|
callq ___cxa_begin_catch
|
|
|
|
movl (%rax), %ebx
|
|
|
|
callq ___cxa_end_catch
|
|
|
|
movl %ebx, %eax
|
|
|
|
addq $8, %rsp
|
|
|
|
popq %rbx
|
|
|
|
popq %rbp
|
|
|
|
retq
|
|
|
|
Lfunc_end0:
|
|
|
|
.cfi_endproc
|
|
|
|
|
|
|
|
.section __TEXT,__gcc_except_tab
|
|
|
|
.p2align 2
|
|
|
|
GCC_except_table1:
|
|
|
|
Lexception0:
|
|
|
|
.byte 255 ## @LPStart Encoding = omit
|
|
|
|
.byte 155 ## @TType Encoding = indirect pcrel sdata4
|
|
|
|
.uleb128 Lttbase0-Lttbaseref0
|
|
|
|
Lttbaseref0:
|
|
|
|
.byte 1 ## Call site Encoding = uleb128
|
|
|
|
.uleb128 Lcst_end0-Lcst_begin0
|
|
|
|
Lcst_begin0:
|
|
|
|
.uleb128 Lfunc_begin0-Lfunc_begin0 ## >> Call Site 1 <<
|
|
|
|
.uleb128 Ltmp0-Lfunc_begin0 ## Call between Lfunc_begin0 and Ltmp0
|
|
|
|
.byte 0 ## has no landing pad
|
|
|
|
.byte 0 ## On action: cleanup
|
|
|
|
.uleb128 Ltmp0-Lfunc_begin0 ## >> Call Site 2 <<
|
|
|
|
.uleb128 Ltmp1-Ltmp0 ## Call between Ltmp0 and Ltmp1
|
|
|
|
.uleb128 Ltmp2-Lfunc_begin0 ## jumps to Ltmp2
|
|
|
|
.byte 1 ## On action: 1
|
|
|
|
.uleb128 Ltmp1-Lfunc_begin0 ## >> Call Site 3 <<
|
|
|
|
.uleb128 Lfunc_end0-Ltmp1 ## Call between Ltmp1 and Lfunc_end0
|
|
|
|
.byte 0 ## has no landing pad
|
|
|
|
.byte 0 ## On action: cleanup
|
|
|
|
Lcst_end0:
|
|
|
|
.byte 1 ## >> Action Record 1 <<
|
|
|
|
## Catch TypeInfo 1
|
|
|
|
.byte 0 ## No further actions
|
|
|
|
.p2align 2
|
|
|
|
## >> Catch TypeInfos <<
|
|
|
|
.long __ZTIi@GOTPCREL+4 ## TypeInfo 1
|
|
|
|
Lttbase0:
|
|
|
|
.p2align 2
|
|
|
|
## -- End function
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- weak-ref.s
|
|
|
|
.text
|
|
|
|
.weak_reference _ref_dylib_fun
|
|
|
|
.globl _main
|
|
|
|
_main:
|
|
|
|
callq _ref_dylib_fun
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- strong-dead-ref.s
|
|
|
|
.text
|
|
|
|
.globl _unref_dylib_fun
|
|
|
|
_unref:
|
|
|
|
callq _unref_dylib_fun
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- weak-dylib.s
|
|
|
|
.text
|
|
|
|
.globl _weak_in_dylib
|
|
|
|
.weak_definition _weak_in_dylib
|
|
|
|
_weak_in_dylib:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- dead-weak-override.s
|
|
|
|
|
|
|
|
## Overrides the _weak_in_dylib symbol in weak-dylib, but is dead stripped.
|
|
|
|
.text
|
|
|
|
|
|
|
|
#.no_dead_strip _weak_in_dylib
|
|
|
|
.globl _weak_in_dylib
|
|
|
|
_weak_in_dylib:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _main
|
|
|
|
_main:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|
|
|
|
|
|
|
|
#--- debug.s
|
|
|
|
.text
|
|
|
|
.globl _unref
|
|
|
|
_unref:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.globl _main
|
|
|
|
_main:
|
|
|
|
retq
|
|
|
|
|
|
|
|
.subsections_via_symbols
|