# REQUIRES: x86 # RUN: rm -rf %t && split-file %s %t && cd %t # RUN: llvm-mc -n -filetype=obj -triple=x86_64 -o shared.o shared.s # RUN: ld.lld -shared shared.o -o a.so # RUN: llvm-mc -n -filetype=obj -triple=x86_64 -o a.o a.s # RUN: llvm-mc -n -filetype=obj -triple=x86_64 -o b.o b.s #--- shared.s .globl test_shared .section .test_shared,"ax",@progbits test_shared: jmp test_shared #--- a.s .weak __start_cident .weak __stop_cident ## Simple live section .globl _start .section ._start,"ax",@progbits _start: jmp test_simple .quad .Lanonymous .quad .Lanonymous_within_symbol jmp test_shared .quad test_local .quad __start_cident - . .quad __stop_cident - . call test_group call test_eh .size _start, .-_start .globl test_simple .section .test_simple,"ax",@progbits test_simple: jmp test_simple jmp test_from_unsized # RUN: ld.lld a.o a.so --gc-sections --why-live=test_simple | FileCheck %s --check-prefix=SIMPLE # SIMPLE: live symbol: a.o:(test_simple) # SIMPLE-NEXT: >>> referenced by: a.o:(_start) (entry point) # SIMPLE-EMPTY: ## Live only by being a member of .test_simple .globl test_incidental test_incidental: jmp test_incidental # RUN: ld.lld a.o a.so --gc-sections --why-live=test_incidental | FileCheck %s --check-prefix=INCIDENTAL # INCIDENTAL: live symbol: a.o:(test_incidental) # INCIDENTAL-NEXT: >>> in live section: a.o:(.test_simple) # INCIDENTAL-NEXT: >>> contained live symbol: a.o:(test_simple) # INCIDENTAL-NEXT: >>> referenced by: a.o:(_start) (entry point) # INCIDENTAL-EMPTY: ## Reached from a reference in section .test_simple directly, since test_simple is an unsized symbol. .globl test_from_unsized .section .test_from_unsized,"ax",@progbits test_from_unsized: jmp test_from_unsized # RUN: ld.lld a.o a.so --gc-sections --why-live=test_from_unsized | FileCheck %s --check-prefix=FROM-UNSIZED # FROM-UNSIZED: live symbol: a.o:(test_from_unsized) # FROM-UNSIZED-NEXT: >>> referenced by: a.o:(.test_simple) # FROM-UNSIZED-NEXT: >>> contained live symbol: a.o:(test_simple) # FROM-UNSIZED-NEXT: >>> referenced by: a.o:(_start) (entry point) # FROM-UNSIZED-EMPTY: ## Symbols in dead sections are dead and not reported. .globl test_dead .section .test_dead,"ax",@progbits test_dead: jmp test_dead # RUN: ld.lld a.o a.so --gc-sections --why-live=test_dead | count 0 ## Undefined symbols are considered live, since they are not in dead sections. # RUN: ld.lld a.o a.so --gc-sections --why-live=test_undef -u test_undef | FileCheck %s --check-prefix=UNDEFINED # UNDEFINED: live symbol: :(test_undef) (no section) # UNDEFINED-EMPTY: ## Defined symbols without input section parents are live. .globl test_absolute test_absolute = 1234 # RUN: ld.lld a.o a.so --gc-sections --why-live=test_absolute | FileCheck %s --check-prefix=ABSOLUTE # ABSOLUTE: live symbol: a.o:(test_absolute) (no section) # ABSOLUTE-EMPTY: ## Retained sections are intrinsically live, and they make contained symbols live. .globl test_retained .section .test_retained,"axR",@progbits test_retained: jmp test_retained # RUN: ld.lld a.o a.so --gc-sections --why-live=test_retained | FileCheck %s --check-prefix=RETAINED # RETAINED: live symbol: a.o:(test_retained) # RETAINED-NEXT: >>> in live section: a.o:(.test_retained) (retained) # RETAINED-EMPTY: ## Relocs that reference offsets from sections (e.g., from anonymous symbols) are considered to point to the section if no enclosing symbol exists. .globl test_section_offset .section .test_section_offset,"ax",@progbits test_section_offset: jmp test_section_offset .Lanonymous: jmp test_section_offset # RUN: ld.lld a.o a.so --gc-sections --why-live=test_section_offset | FileCheck %s --check-prefix=SECTION-OFFSET # SECTION-OFFSET: live symbol: a.o:(test_section_offset) # SECTION-OFFSET-NEXT: >>> in live section: a.o:(.test_section_offset) # SECTION-OFFSET-NEXT: >>> referenced by: a.o:(_start) (entry point) # SECTION-OFFSET-EMPTY: ## Relocs that reference offsets from sections (e.g., from anonymous symbols) are considered to point to the enclosing symbol if one exists. .globl test_section_offset_within_symbol .section .test_section_offset_within_symbol,"ax",@progbits test_section_offset_within_symbol: jmp test_section_offset_within_symbol .Lanonymous_within_symbol: jmp test_section_offset_within_symbol .size test_section_offset_within_symbol, .-test_section_offset_within_symbol # RUN: ld.lld a.o a.so --gc-sections --why-live=test_section_offset_within_symbol | FileCheck %s --check-prefix=SECTION-OFFSET-WITHIN-SYMBOL # SECTION-OFFSET-WITHIN-SYMBOL: live symbol: a.o:(test_section_offset_within_symbol) # SECTION-OFFSET-WITHIN-SYMBOL-NEXT: >>> referenced by: a.o:(_start) (entry point) # SECTION-OFFSET-WITHIN-SYMBOL-EMPTY: ## Local symbols can be queried just like global symbols. .section .test_local,"ax",@progbits test_local: jmp test_local .size test_local, .-test_local # RUN: ld.lld a.o a.so --gc-sections --why-live=test_local | FileCheck %s --check-prefix=LOCAL # LOCAL: live symbol: a.o:(test_local) # LOCAL-NEXT: >>> referenced by: a.o:(_start) (entry point) # LOCAL-EMPTY: ## Shared symbols # RUN: ld.lld a.o a.so --gc-sections --why-live=test_shared | FileCheck %s --check-prefix=SHARED # SHARED: live symbol: a.so:(test_shared) # SHARED-NEXT: >>> referenced by: a.o:(_start) (entry point) # SHARED-EMPTY: ## Globs match multiple cases. Multiple --why-live flags union. # RUN: ld.lld a.o a.so --gc-sections --why-live="test_se*" --why-live="test_se*" | FileCheck %s --check-prefix=MULTIPLE # RUN: ld.lld a.o a.so --gc-sections --why-live=test_section_offset --why-live=test_section_offset_within_symbol | FileCheck %s --check-prefix=MULTIPLE # MULTIPLE-DAG: live symbol: a.o:(test_section_offset) # MULTIPLE-DAG: live symbol: a.o:(test_section_offset_within_symbol) # MULTIPLE-NOT: live symbol .section cident,"a",@progbits .globl test_atexit test_atexit: .quad 0 # RUN: ld.lld a.o a.so --gc-sections --why-live=test_atexit -z nostart-stop-gc | FileCheck %s --check-prefix=ATEXIT # ATEXIT: live symbol: a.o:(test_atexit) # ATEXIT-NEXT: >>> in live section: a.o:(cident) # ATEXIT-NEXT: >>> referenced by: a.o:(_start) (entry point) # ATEXIT-EMPTY: ## A live section's nextInSectionGroup is enqueued from the non-parallel mark(). .section .text.test_group,"axG",@progbits,test_group_signature,comdat .globl test_group test_group: ret .section .data.test_group,"awG",@progbits,test_group_signature,comdat .globl test_group_data test_group_data: .quad 0 # RUN: ld.lld a.o a.so --gc-sections --why-live=test_group_data | FileCheck %s --check-prefix=GROUP # GROUP: live symbol: a.o:(test_group_data) # GROUP-NEXT: >>> in live section: a.o:(.data.test_group) # GROUP-NEXT: >>> in section group with: a.o:(.text.test_group) # GROUP-NEXT: >>> contained live symbol: a.o:(test_group) # GROUP-NEXT: >>> referenced by: a.o:(_start) (entry point) # GROUP-EMPTY: ## CIE personality relocation traced through scanEhFrameSection. .section .text.personality,"ax",@progbits .globl personality personality: ret .section .text.test_eh,"ax",@progbits .globl test_eh test_eh: .cfi_startproc .cfi_personality 3, personality ret .cfi_endproc # RUN: ld.lld a.o a.so --gc-sections --why-live=personality | FileCheck %s --check-prefix=PERSONALITY # PERSONALITY: live symbol: a.o:(personality) # PERSONALITY-NEXT: >>> referenced by: a.o:(.eh_frame) (exception handling frame) # PERSONALITY-EMPTY: ## Symbols exported into the dynamic symbol table are GC roots. .globl test_exported .section .test_exported,"ax",@progbits test_exported: jmp test_exported # RUN: ld.lld a.o a.so --gc-sections --export-dynamic --why-live=test_exported | FileCheck %s --check-prefix=EXPORTED # EXPORTED: live symbol: a.o:(test_exported) (externally visible symbol) # EXPORTED-EMPTY: #--- b.s ## --why-live='*' skips symbol at index 0 and section symbols. # RUN: ld.lld b.o --threads=1 --gc-sections --why-live="*" | FileCheck %s --check-prefix=STAR --match-full-lines # STAR-NOT: {{.}} # STAR: live symbol: b.o:(_start) (entry point) # STAR-NEXT: live symbol: b.o:(b.s) (no section) # STAR-NEXT: live symbol: b.o:(str1) # STAR-NEXT: >>> referenced by: b.o:(.alloc) # STAR-NEXT: >>> referenced by: b.o:(.text) # STAR-NEXT: >>> contained live symbol: b.o:(_start) (entry point) # STAR-NEXT: live symbol: b.o:(note1) # STAR-NEXT: >>> in live section: b.o:(.note.1) (reserved) # STAR-NEXT: live symbol: b.o:(__FRAME_END__) # STAR-NEXT: >>> in live section: b.o:(.eh_frame) (exception handling frame) # STAR-NOT: {{.}} ## STT_FILE symbol .file "b.s" .text .globl _start _start: call .alloc .section .alloc,"a" lea str1(%rip), %rax .section .nonalloc .long .nonalloc .section .note.1,"a",@note note1: ## GCC crtendS.o has such a local symbol relative to an explicit .eh_frame ## section. .section .eh_frame,"a" __FRAME_END__: .long 0 .section .rodata.str1.1,"aMS",@progbits,1 str1: .asciz "str1"