65 changes: 51 additions & 14 deletions lld/test/MachO/weak-import.s
Original file line number Diff line number Diff line change
@@ -1,35 +1,72 @@
# REQUIRES: x86
# RUN: 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/weak-ref-only.s -o %t/weak-ref-only.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/weak-ref-sub-library.s -o %t/weak-ref-sub-library.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/mixed-ref.s -o %t/mixed-ref.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
# RUN: %lld -lSystem -dylib %t/foo.o -o %t/libfoo.dylib
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/bar.s -o %t/bar.o
# RUN: %lld -lSystem -dylib %t/bar.o -o %t/libbar.dylib
# RUN: %lld -lSystem -dylib %t/foo.o %t/libbar.dylib -sub_library libbar -o %t/libfoo.dylib

# RUN: %lld -weak-lSystem %t/test.o -weak_framework CoreFoundation -weak_library %t/libfoo.dylib -o %t/test
# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s -DDIR=%t
# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s -DDIR=%t --check-prefixes=WEAK-SYS,WEAK-FOO
# RUN: %lld -weak-lSystem %t/test.o \
# RUN: -framework CoreFoundation -weak_framework CoreFoundation -framework CoreFoundation \
# RUN: %t/libfoo.dylib -weak_library %t/libfoo.dylib %t/libfoo.dylib -o %t/test
# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s -DDIR=%t
# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s -DDIR=%t --check-prefixes=WEAK-SYS,WEAK-FOO
# RUN: %lld -lSystem -dylib %t/libfoo.dylib %t/weak-ref-only.o -o %t/weak-ref-only
# RUN: llvm-objdump --macho --all-headers %t/weak-ref-only | FileCheck %s -DDIR=%t --check-prefixes=SYS,WEAK-FOO
# RUN: %lld -lSystem -dylib %t/libfoo.dylib %t/weak-ref-sub-library.o -o %t/weak-ref-sub-library
# RUN: llvm-objdump --macho --all-headers %t/weak-ref-sub-library | FileCheck %s -DDIR=%t --check-prefixes=SYS,WEAK-FOO
# RUN: %lld -lSystem -dylib %t/libfoo.dylib %t/mixed-ref.o -o %t/mixed-ref
# RUN: llvm-objdump --macho --all-headers %t/mixed-ref | FileCheck %s -DDIR=%t --check-prefixes=SYS,FOO

# CHECK: cmd LC_LOAD_WEAK_DYLIB
# CHECK-NEXT: cmdsize
# CHECK-NEXT: name /usr/lib/libSystem.B.dylib
# WEAK-SYS: cmd LC_LOAD_WEAK_DYLIB
# WEAK-SYS-NEXT: cmdsize
# WEAK-SYS-NEXT: name /usr/lib/libSystem.B.dylib

# CHECK: cmd LC_LOAD_WEAK_DYLIB
# CHECK-NEXT: cmdsize
# CHECK-NEXT: name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
# WEAK-SYS: cmd LC_LOAD_WEAK_DYLIB
# WEAK-SYS-NEXT: cmdsize
# WEAK-SYS-NEXT: name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation

# CHECK: cmd LC_LOAD_WEAK_DYLIB
# CHECK-NEXT: cmdsize
# CHECK-NEXT: name [[DIR]]/libfoo.dylib
# SYS: cmd LC_LOAD_DYLIB
# SYS-NEXT: cmdsize
# SYS-NEXT: name /usr/lib/libSystem.B.dylib

# WEAK-FOO: cmd LC_LOAD_WEAK_DYLIB
# WEAK-FOO-NEXT: cmdsize
# WEAK-FOO-NEXT: name [[DIR]]/libfoo.dylib

# FOO: cmd LC_LOAD_DYLIB
# FOO-NEXT: cmdsize
# FOO-NEXT: name [[DIR]]/libfoo.dylib

#--- foo.s
.globl _foo
_foo:
ret

#--- bar.s
.globl _bar
_bar:

#--- weak-ref-only.s
.weak_reference _foo
.data
.quad _foo

#--- weak-ref-sub-library.s
.weak_reference _bar
.data
.quad _bar

#--- mixed-ref.s
.weak_definition _foo
.data
.quad _foo
.quad _bar

#--- test.s
.globl _main
.text
_main:
ret
144 changes: 144 additions & 0 deletions lld/test/MachO/weak-reference.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# 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/strongref.s -o %t/strongref.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/invalid.s -o %t/invalid.o
# RUN: %lld -lSystem -dylib %t/libfoo.o -o %t/libfoo.dylib

# RUN: %lld -lSystem %t/test.o %t/libfoo.dylib -o %t/test
# RUN: llvm-objdump --macho --syms --bind %t/test | FileCheck %s --check-prefixes=SYMS,BIND
## llvm-objdump doesn't print out all the flags info for lazy & weak bindings,
## so we use obj2yaml instead to test them.
# RUN: obj2yaml %t/test | FileCheck %s --check-prefix=YAML

# RUN: %lld -lSystem %t/libfoo.dylib %t/test.o -o %t/test
# RUN: llvm-objdump --macho --syms --bind %t/test | FileCheck %s --check-prefixes=SYMS,BIND
# RUN: obj2yaml %t/test | FileCheck %s --check-prefix=YAML

# SYMS: SYMBOL TABLE:
# SYMS-DAG: 0000000000000000 w *UND* _foo
# SYMS-DAG: 0000000000000000 w *UND* _foo_fn
# SYMS-DAG: 0000000000000000 w *UND* _foo_tlv
# SYMS-DAG: 0000000000000000 w *UND* _weak_foo
# SYMS-DAG: 0000000000000000 w *UND* _weak_foo_fn

# BIND: Bind table:
# BIND-NEXT: segment section address type addend dylib symbol
# BIND-DAG: __DATA __data 0x{{[0-9a-f]+}} pointer 0 libfoo _foo (weak_import)
# BIND-DAG: __DATA_CONST __got 0x{{[0-9a-f]+}} pointer 0 libfoo _foo (weak_import)
# BIND-DAG: __DATA __thread_ptrs 0x{{[0-9a-f]+}} pointer 0 libfoo _foo_tlv (weak_import)
# BIND-DAG: __DATA __data 0x{{[0-9a-f]+}} pointer 0 libfoo _weak_foo (weak_import)
# BIND-DAG: __DATA __la_symbol_ptr 0x{{[0-9a-f]+}} pointer 0 libfoo _weak_foo_fn (weak_import)

# YAML-LABEL: WeakBindOpcodes:
# YAML: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
# YAML-NEXT: Imm: 0
# YAML-NEXT: Symbol: _weak_foo
# YAML: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
# YAML-NEXT: Imm: 0
# YAML-NEXT: Symbol: _weak_foo_fn
# YAML-LABEL: LazyBindOpcodes:
# YAML: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
# YAML-NEXT: Imm: 1
# YAML-NEXT: Symbol: _foo_fn

## Check that if both strong & weak references are present in inputs, the weak
## reference takes priority. NOTE: ld64 actually emits a strong reference if
## the reference is to a function symbol or a TLV. I'm not sure if there's a
## good reason for that, so I'm deviating here for a simpler implementation.
# RUN: %lld -lSystem %t/test.o %t/strongref.o %t/libfoo.dylib -o %t/with-strong
# RUN: llvm-objdump --macho --bind %t/with-strong | FileCheck %s --check-prefix=STRONG-BIND
# RUN: obj2yaml %t/with-strong | FileCheck %s --check-prefix=STRONG-YAML
# RUN: %lld -lSystem %t/strongref.o %t/test.o %t/libfoo.dylib -o %t/with-strong
# RUN: llvm-objdump --macho --bind %t/with-strong | FileCheck %s --check-prefix=STRONG-BIND
# RUN: obj2yaml %t/with-strong | FileCheck %s --check-prefix=STRONG-YAML
# RUN: %lld -lSystem %t/libfoo.dylib %t/strongref.o %t/test.o -o %t/with-strong
# RUN: llvm-objdump --macho --bind %t/with-strong | FileCheck %s --check-prefix=STRONG-BIND
# RUN: obj2yaml %t/with-strong | FileCheck %s --check-prefix=STRONG-YAML
# RUN: %lld -lSystem %t/libfoo.dylib %t/test.o %t/strongref.o -o %t/with-strong
# RUN: llvm-objdump --macho --bind %t/with-strong | FileCheck %s --check-prefix=STRONG-BIND
# RUN: obj2yaml %t/with-strong | FileCheck %s --check-prefix=STRONG-YAML
# RUN: %lld -lSystem %t/test.o %t/libfoo.dylib %t/strongref.o -o %t/with-strong
# RUN: llvm-objdump --macho --bind %t/with-strong | FileCheck %s --check-prefix=STRONG-BIND
# RUN: obj2yaml %t/with-strong | FileCheck %s --check-prefix=STRONG-YAML
# RUN: %lld -lSystem %t/strongref.o %t/libfoo.dylib %t/test.o -o %t/with-strong
# RUN: llvm-objdump --macho --bind %t/with-strong | FileCheck %s --check-prefix=STRONG-BIND
# RUN: obj2yaml %t/with-strong | FileCheck %s --check-prefix=STRONG-YAML

# STRONG-BIND: Bind table:
# STRONG-BIND-NEXT: segment section address type addend dylib symbol
# STRONG-BIND-DAG: __DATA __data 0x{{[0-9a-f]+}} pointer 0 libfoo _foo{{$}}
# STRONG-BIND-DAG: __DATA __data 0x{{[0-9a-f]+}} pointer 0 libfoo _foo{{$}}
# STRONG-BIND-DAG: __DATA_CONST __got 0x{{[0-9a-f]+}} pointer 0 libfoo _foo{{$}}
# STRONG-BIND-DAG: __DATA __thread_ptrs 0x{{[0-9a-f]+}} pointer 0 libfoo _foo_tlv{{$}}
# STRONG-BIND-DAG: __DATA __data 0x{{[0-9a-f]+}} pointer 0 libfoo _weak_foo{{$}}
# STRONG-BIND-DAG: __DATA __data 0x{{[0-9a-f]+}} pointer 0 libfoo _weak_foo{{$}}
# STRONG-BIND-DAG: __DATA __la_symbol_ptr 0x{{[0-9a-f]+}} pointer 0 libfoo _weak_foo_fn{{$}}

# STRONG-YAML-LABEL: WeakBindOpcodes:
# STRONG-YAML: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
# STRONG-YAML-NEXT: Imm: 0
# STRONG-YAML-NEXT: Symbol: _weak_foo
# STRONG-YAML: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
# STRONG-YAML-NEXT: Imm: 0
# STRONG-YAML-NEXT: Symbol: _weak_foo
# STRONG-YAML: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
# STRONG-YAML-NEXT: Imm: 0
# STRONG-YAML-NEXT: Symbol: _weak_foo_fn
# STRONG-YAML-LABEL: LazyBindOpcodes:
# STRONG-YAML: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
# STRONG-YAML-NEXT: Imm: 0
# STRONG-YAML-NEXT: Symbol: _foo_fn

## Weak references must still be satisfied at link time.
# RUN: not %lld -lSystem %t/invalid.o -o /dev/null 2>&1 | FileCheck %s \
# RUN: --check-prefix=INVALID -DDIR=%t
# INVALID: error: undefined symbol _missing, referenced from [[DIR]]/invalid.o

#--- libfoo.s
.globl _foo, _foo_fn, _weak_foo, _weak_foo_fn
.weak_definition _weak_foo, _weak_foo_fn
_foo:
_foo_fn:
_weak_foo:
_weak_foo_fn:

.section __DATA,__thread_vars,thread_local_variables
.globl _foo_tlv
_foo_tlv:

#--- test.s
.globl _main
.weak_reference _foo_fn, _foo, _weak_foo, _weak_foo_fn, _foo_tlv

_main:
mov _foo@GOTPCREL(%rip), %rax
mov _foo_tlv@TLVP(%rip), %rax
callq _foo_fn
callq _weak_foo_fn
ret

.data
.quad _foo
.quad _weak_foo

#--- strongref.s
.globl _strongref
_strongref:
mov _foo@GOTPCREL(%rip), %rax
mov _foo_tlv@TLVP(%rip), %rax
callq _foo_fn
callq _weak_foo_fn
ret

.data
.quad _foo
.quad _weak_foo

#--- invalid.s
.globl _main
.weak_reference _missing
_main:
callq _missing
ret