diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1453,6 +1453,14 @@ r.sym->stOther & STO_AARCH64_VARIANT_PCS; }) != in.relaPlt->relocs.end()) addInt(DT_AARCH64_VARIANT_PCS, 0); + addInSec(DT_PLTGOT, in.gotPlt); + break; + case EM_RISCV: + if (llvm::find_if(in.relaPlt->relocs, [](const DynamicReloc &r) { + return r.type == target->pltRel && + (r.sym->stOther & STO_RISCV_VARIANT_CC); + }) != in.relaPlt->relocs.end()) + addInt(DT_RISCV_VARIANT_CC, 0); LLVM_FALLTHROUGH; default: addInSec(DT_PLTGOT, in.gotPlt); @@ -2243,6 +2251,8 @@ // variant PCS. else if (config->emachine == EM_AARCH64) eSym->st_other |= sym->stOther & STO_AARCH64_VARIANT_PCS; + else if (config->emachine == EM_RISCV) + eSym->st_other |= sym->stOther & STO_RISCV_VARIANT_CC; eSym->st_name = ent.strTabOffset; if (isDefinedHere) diff --git a/lld/test/ELF/riscv-variant-cc.s b/lld/test/ELF/riscv-variant-cc.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/riscv-variant-cc.s @@ -0,0 +1,130 @@ +# REQUIRES: riscv +# RUN: split-file %s %t + +# RUN: llvm-mc -filetype=obj -triple=riscv32 %t/test1 -o %t.o +# RUN: ld.lld %t.o --shared -o %t.so +# RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix T1-CCDYN %s +# RUN: llvm-readelf --symbols %t.so | FileCheck --check-prefix T1-CCSYM %s + +# T1-CCDYN-NOT: (RISCV_VARIANT_CC) +# T1-CCSYM: Symbol table '.dynsym' +# T1-CCSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_CC] [[#]] func_global_def + +# RUN: llvm-mc -filetype=obj -triple=riscv64 %t/test2 -o %t.o +# RUN: ld.lld %t.o --shared -o %t.so +# RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix T2-CCDYN %s +# RUN: llvm-readelf --symbols %t.so | FileCheck --check-prefix T2-CCSYM %s + +# T2-CCDYN: 0x0000000070000001 (RISCV_VARIANT_CC) 0 +# T2-CCSYM: Symbol table '.dynsym' +# T2-CCSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_CC] [[#]] func_global_def + +# RUN: llvm-mc -filetype=obj -triple=riscv32 %t/test3 -o %t.o +# RUN: ld.lld %t.o --shared -o %t.so +# RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix T3-CCDYN %s +# RUN: llvm-readelf --symbols %t.so | FileCheck --check-prefix T3-CCSYM %s + +# T3-CCDYN: 0x70000001 (RISCV_VARIANT_CC) 0 +# T3-CCSYM: Symbol table '.dynsym' +# T3-CCSYM: 0 IFUNC GLOBAL DEFAULT [VARIANT_CC] UND ifunc_global_def +# T3-CCSYM: 0 NOTYPE GLOBAL DEFAULT [[#]] func_global_def + +# RUN: llvm-mc -filetype=obj -triple=riscv64 %t/test4 -o %t.o +# RUN: ld.lld %t.o --shared -o %t.so +# RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix T4-CCDYN %s +# RUN: llvm-readelf --symbols %t.so | FileCheck --check-prefix T4-CCSYM %s + +# T4-CCDYN-NOT: 0x0000000070000001 (RISCV_VARIANT_CC) 0 +# T4-CCSYM: Symbol table '.dynsym' +# T4-CCSYM: 0 IFUNC GLOBAL DEFAULT [VARIANT_CC] [[#]] ifunc_global_def + +# RUN: llvm-mc -filetype=obj -triple=riscv64 %t/test5 -o %t.o +# RUN: ld.lld %t.o --shared -o %t.so +# RUN: llvm-readelf --symbols %t.so | FileCheck --check-prefix T5-CCSYM %s + +# T5-CCSYM: Symbol table '.dynsym' +# T5-CCSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_CC] UND func_global_undef +# T5-CCSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT [VARIANT_CC] [[#]] func_global_def +# T5-CCSYM-NEXT: 0 IFUNC GLOBAL DEFAULT [VARIANT_CC] [[#]] ifunc_global_def +# T5-CCSYM: Symbol table '.symtab' contains 10 entries: +# T5-CCSYM: 0 NOTYPE LOCAL DEFAULT [VARIANT_CC] [[#]] func_local +# T5-CCSYM-NEXT: 0 IFUNC LOCAL DEFAULT [VARIANT_CC] [[#]] ifunc_local +# T5-CCSYM: 0 NOTYPE LOCAL HIDDEN [VARIANT_CC] [[#]] func_global_hidden +# T5-CCSYM-NEXT: 0 IFUNC LOCAL HIDDEN [VARIANT_CC] [[#]] ifunc_global_hidden +# T5-CCSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_CC] [[#]] func_global_def +# T5-CCSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT [VARIANT_CC] UND func_global_undef +# T5-CCSYM-NEXT: 0 IFUNC GLOBAL DEFAULT [VARIANT_CC] [[#]] ifunc_global_def + + +#--- test1 +## An object with a variant_pcs symbol but without a R_RISCV_JMP_SLOT +## should not generate a DT_RISCV_VARIANT_CC. +.text +.global func_global_def +.variant_cc func_global_def + +func_global_def: + ret + +#--- test2 +## An object with a variant_cc symbol and with a R_RISCV_JMP_SLOT +## should generate a DT_RISCV_VARIANT_CC. +.text +.global func_global_def +.variant_cc func_global_def + +func_global_def: + bl func_global_def + +#--- test3 +## Same as before, but targeting a GNU IFUNC. +.text +.global ifunc_global_def +.global func_global_def +.variant_cc ifunc_global_def +.type ifunc_global_def, %gnu_indirect_function + +func_global_def: + bl ifunc_global_def + +#--- test4 +## An object with a variant_cc symbol and with a R_RISCV_IRELATIVE +## should not generate a DT_RISCV_VARIANT_CC. +.text +.global ifunc_global_def +.global func_global_def +.variant_cc ifunc_global_def +.type ifunc_global_def, %gnu_indirect_function + +ifunc_global_def: + bl func_global_def + +#--- test5 +## Check if STO_RISCV_VARIANT_CC is kept on symbol st_other for both undef, +## local, and hidden visibility. +.text +.global func_global_def, func_global_undef, func_global_hidden +.global ifunc_global_def, ifunc_global_hidden +.local func_local + +.hidden func_global_hidden, ifunc_global_hidden + +.type ifunc_global_def, %gnu_indirect_function +.type ifunc_global_hidden, %gnu_indirect_function +.type ifunc_local, %gnu_indirect_function + +.variant_cc func_global_def +.variant_cc func_global_undef +.variant_cc func_global_hidden +.variant_cc func_local +.variant_cc ifunc_global_def +.variant_cc ifunc_global_hidden +.variant_cc ifunc_local + +func_global_def: +func_global_hidden: +func_local: +ifunc_global_def: +ifunc_global_hidden: +ifunc_local: + ret