diff --git a/lld/test/ELF/symver.s b/lld/test/ELF/symver.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/symver.s @@ -0,0 +1,205 @@ +# REQUIRES: x86 +## Test symbol resolution related to .symver produced symbols in object files. + +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/ref.s -o %t/ref.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/ref1.s -o %t/ref1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/ref1p.s -o %t/ref1p.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/def1.s -o %t/def1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/def1w.s -o %t/def1w.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/hid1.s -o %t/hid1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/hid1w.s -o %t/hid1w.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/def2.s -o %t/def2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/wrap.s -o %t/wrap.o +# RUN: ld.lld -shared --soname=def1.so --version-script=%t/ver %t/def1.o -o %t/def1.so +# RUN: ld.lld -shared --soname=hid1.so --version-script=%t/ver %t/hid1.o -o %t/hid1.so + +## TODO Report a duplicate definition error for foo@v1 and foo@@v1. +# RUN: ld.lld -shared --version-script=%t/ver %t/def1.o %t/hid1.o -o /dev/null + +# RUN: ld.lld -shared --version-script=%t/ver %t/def1w.o %t/hid1.o -o /dev/null +# RUN: ld.lld -shared --version-script=%t/ver %t/def1.o %t/hid1w.o -o /dev/null +# RUN: ld.lld -shared --version-script=%t/ver %t/def1w.o %t/hid1w.o -o /dev/null + +## TODO foo@@v1 should resolve undefined foo@v1. +# RUN: not ld.lld -shared --version-script=%t/ver %t/ref1p.o %t/def1.o -o /dev/null + +## TODO +## foo@@v1 resolves both undefined foo and foo@v1. There is one single definition. +## Note: set soname so that the name string referenced by .gnu.version_d is fixed. +# RUN: ld.lld -shared --soname=t --version-script=%t/ver %t/ref.o %t/ref1.o %t/def1.o -o %t1 +# RUN: llvm-readelf -r --dyn-syms %t1 | FileCheck %s + +# CHECK: Relocation section '.rela.plt' at offset {{.*}} contains 2 entries: +# CHECK-NEXT: {{.*}} Type {{.*}} +# CHECK-NEXT: {{.*}} R_X86_64_JUMP_SLOT {{.*}} foo@@v1 + 0 +# CHECK-NEXT: {{.*}} R_X86_64_JUMP_SLOT {{.*}} foo + 0 + +# CHECK: 1: {{.*}} NOTYPE GLOBAL DEFAULT UND foo{{$}} +# CHECK-NEXT: 2: {{.*}} NOTYPE GLOBAL DEFAULT [[#]] foo@@v1 +# CHECK-EMPTY: + +## foo@@v2 does not resolve undefined foo@v1. +## TODO Undefined 'foo@v1' should be errored. +# RUN: ld.lld -shared --soname=t --version-script=%t/ver %t/ref.o %t/ref1.o %t/def2.o -o %t2 +# RUN: llvm-readelf --dyn-syms %t2 | FileCheck %s --check-prefix=CHECK2 + +# CHECK2: 1: {{.*}} NOTYPE GLOBAL DEFAULT UND foo{{$}} +# CHECK2-NEXT: 2: {{.*}} NOTYPE GLOBAL DEFAULT [[#]] foo@@v2 +# CHECK2-EMPTY: + +## foo@@v2 resolves undefined foo while foo@v1 resolves undefined foo@v1. +# RUN: ld.lld -shared --soname=t --version-script=%t/ver %t/ref.o %t/ref1.o %t/hid1.o %t/def2.o -o %t3 +# RUN: llvm-readelf -r --dyn-syms %t3 | FileCheck %s --check-prefix=CHECK3 +# RUN: llvm-objdump -d --no-show-raw-insn %t3 | FileCheck %s --check-prefix=DIS3 + +# CHECK3: 00000000000034a8 {{.*}} R_X86_64_JUMP_SLOT {{.*}} foo@@v2 + 0 +# CHECK3-NEXT: 00000000000034b0 {{.*}} R_X86_64_JUMP_SLOT {{.*}} foo@v1 + 0 + +# CHECK3: 1: {{.*}} NOTYPE GLOBAL DEFAULT [[#]] foo@@v2 +# CHECK3-NEXT: 2: {{.*}} NOTYPE GLOBAL DEFAULT [[#]] foo@v1 +# CHECK3-NEXT: 3: {{.*}} NOTYPE GLOBAL DEFAULT [[#]] foo_v1 +# CHECK3-EMPTY: + +# DIS3-LABEL: <.text>: +# DIS3-NEXT: callq 0x1380 +# DIS3-COUNT-3: int3 +# DIS3-NEXT: callq 0x1390 +# DIS3-LABEL: : +# DIS3-NEXT: jmpq *{{.*}}(%rip) # 34a8 +# DIS3-LABEL: : +# DIS3-NEXT: jmpq *{{.*}}(%rip) # 34b0 + +## Then, test the interaction with versioned definitions in shared objects. + +## TODO Both foo and foo@v1 are undefined. Ideally we should not create two .dynsym entries. +# RUN: ld.lld -shared --soname=t --version-script=%t/ver %t/ref.o %t/ref1.o %t/def1.so -o %t4 +# RUN: llvm-readelf --dyn-syms %t4 | FileCheck %s --check-prefix=CHECK4 + +# CHECK4: 1: {{.*}} NOTYPE GLOBAL DEFAULT UND foo@v1 +# CHECK4-NEXT: 2: {{.*}} NOTYPE GLOBAL DEFAULT UND foo@v1 +# CHECK4-EMPTY: + +## hid1.so resolves undefined foo@v1. foo is undefined. +# RUN: ld.lld -shared --soname=t --version-script=%t/ver %t/ref.o %t/ref1.o %t/hid1.so -o %t5 +# RUN: llvm-readelf --dyn-syms %t5 | FileCheck %s --check-prefix=CHECK5 + +# CHECK5: 1: {{.*}} NOTYPE GLOBAL DEFAULT UND foo{{$}} +# CHECK5-NEXT: 2: {{.*}} NOTYPE GLOBAL DEFAULT UND foo@v1 +# CHECK5-EMPTY: + +## Test the interaction with --wrap. + +## The reference from ref.o is redirected. The reference from ref1.o is not. +# RUN: ld.lld -shared --soname=t --version-script=%t/ver --wrap=foo %t/ref.o %t/ref1.o %t/def1.o %t/wrap.o -o %t.w1 +# RUN: llvm-readobj -r %t.w1 | FileCheck %s --check-prefix=W1REL +# RUN: llvm-objdump -d --no-show-raw-insn %t.w1 | FileCheck %s --check-prefix=W1DIS + +## TODO foo should be foo@@v1. +# W1REL: .rela.plt { +# W1REL-NEXT: R_X86_64_JUMP_SLOT __wrap_foo 0x0 +# W1REL-NEXT: R_X86_64_JUMP_SLOT foo 0x0 +# W1REL-NEXT: } + +# W1DIS-LABEL: <.text>: +# W1DIS-NEXT: callq {{.*}} <__wrap_foo@plt> +# W1DIS-COUNT-3: int3 +# W1DIS-NEXT: callq {{.*}} + +## The reference from ref.o is redirected. The reference from ref1.o is not. +## Note: this case demonstrates the typical behavior wrapping a glibc libc.so definition. +# RUN: ld.lld -shared --soname=t --version-script=%t/ver --wrap=foo %t/ref.o %t/ref1.o %t/def1.so %t/wrap.o -o %t.w2 +# RUN: llvm-readobj -r %t.w2 | FileCheck %s --check-prefix=W2REL +# RUN: llvm-objdump -d --no-show-raw-insn %t.w2 | FileCheck %s --check-prefix=W2DIS + +# W2REL: .rela.plt { +# W2REL-NEXT: R_X86_64_JUMP_SLOT __wrap_foo 0x0 +# W2REL-NEXT: R_X86_64_JUMP_SLOT foo@v1 0x0 +# W2REL-NEXT: } + +# W2DIS-LABEL: <.text>: +# W2DIS-NEXT: callq {{.*}} <__wrap_foo@plt> +# W2DIS-COUNT-3: int3 +# W2DIS-NEXT: callq {{.*}} + +## The following two tests are just used to demonstrate the behavior of --wrap +## on @ and @@. It is unclear what the reasonable behavior should be. + +## Note: GNU ld errors "no symbol version section for versioned symbol `__wrap_foo@v1'". +# RUN: ld.lld -shared --soname=t --version-script=%t/ver --wrap=foo@v1 %t/ref.o %t/ref1.o %t/def1.o %t/wrap.o -o %t.w2 +# RUN: llvm-readobj -r %t.w2 | FileCheck %s --check-prefix=W3REL +# RUN: llvm-objdump -d --no-show-raw-insn %t.w2 | FileCheck %s --check-prefix=W3DIS + +# W3REL: .rela.plt { +# W3REL-NEXT: R_X86_64_JUMP_SLOT foo@@v1 0x0 +# W3REL-NEXT: R_X86_64_JUMP_SLOT - 0x0 +# W3REL-NEXT: } + +# W3DIS-LABEL: <.text>: +# W3DIS-NEXT: callq {{.*}} +# W3DIS-COUNT-3: int3 +# W3DIS-NEXT: callq {{.*}} + +## Note: GNU ld errors "no symbol version section for versioned symbol `__wrap_foo@@v1'". +# RUN: ld.lld -shared --soname=t --version-script=%t/ver --wrap=foo@@v1 %t/ref.o %t/ref1.o %t/def1.o %t/wrap.o -o %t.w4 +# RUN: llvm-readobj -r %t.w4 | FileCheck %s --check-prefix=W4REL +# RUN: llvm-objdump -d --no-show-raw-insn %t.w4 | FileCheck %s --check-prefix=W4DIS + +# W4REL: .rela.plt { +# W4REL-NEXT: R_X86_64_JUMP_SLOT foo@@v1 0x0 +# W4REL-NEXT: R_X86_64_JUMP_SLOT foo 0x0 +# W4REL-NEXT: } + +# W4DIS-LABEL: <.text>: +# W4DIS-NEXT: callq 0x1380 +# W4DIS-COUNT-3: int3 +# W4DIS-NEXT: callq 0x1390 + +#--- ver +v1 {}; +v2 {}; + +#--- ref.s +call foo + +#--- ref1.s +.symver foo, foo@@@v1 +call foo + +#--- ref1p.s +.protected foo +.symver foo, foo@@@v1 +call foo + +#--- def1.s +.globl foo +.symver foo, foo@@@v1 +foo: + +#--- def1w.s +.weak foo +.symver foo, foo@@@v1 +foo: + +#--- hid1.s +.globl foo_v1 +.symver foo_v1, foo@v1 +foo_v1: + ret + +#--- hid1w.s +.weak foo_v1 +.symver foo_v1, foo@v1 +foo_v1: + ret + +#--- def2.s +.globl foo +.symver foo, foo@@@v2 +foo: + ret + +#--- wrap.s +.globl __wrap_foo +__wrap_foo: + nop