diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -103,7 +103,8 @@ for (StringRef v : {".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", ".ldata", ".lrodata", ".lbss", ".gcc_except_table", ".init_array", ".fini_array", - ".tbss", ".tdata", ".ARM.exidx", ".ARM.extab", ".ctors", ".dtors"}) + ".tbss", ".tdata", ".ARM.exidx", ".ARM.extab", ".ctors", ".dtors", + ".pseudo_probe"}) if (isSectionPrefix(v, s->name)) return v; diff --git a/lld/test/ELF/pseudo-probe-section.s b/lld/test/ELF/pseudo-probe-section.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/pseudo-probe-section.s @@ -0,0 +1,73 @@ +# REQUIRES: x86_64-linux +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: llvm-readelf -g %t.o | FileCheck %s --check-prefix=CHECK-OBJ +# RUN: ld.lld -shared --soname=t2 %t.o -o %t2.so +# RUN: llvm-objdump --section-headers %t2.so | FileCheck %s --check-prefix=CHECK-ELF + + + .text + .file "" + .section .text.foo,"axG",@progbits,foo,comdat + .globl foo # -- Begin function foo + .p2align 4, 0x90 + .type foo,@function +foo: # @foo + .cfi_startproc +# %bb.0: # %bb0 + .pseudoprobe 6699318081062747564 1 0 0 foo + testl %edi, %edi + je .LBB0_1 +# %bb.2: # %bb2 + .pseudoprobe 6699318081062747564 3 0 0 foo + .pseudoprobe 6699318081062747564 4 0 0 foo + retq +.LBB0_1: # %bb1 + .pseudoprobe 6699318081062747564 2 0 0 foo + .pseudoprobe 6699318081062747564 4 0 0 foo + retq +.Lfunc_end0: + .size foo, .Lfunc_end0-foo + .cfi_endproc + # -- End function + .section .text.foo2,"axG",@progbits,foo2,comdat + .p2align 4, 0x90 # -- Begin function foo2 + .type foo2,@function +foo2: # @foo2 + .cfi_startproc +# %bb.0: # %entry + pushq %rax + .cfi_def_cfa_offset 16 + .pseudoprobe 2494702099028631698 1 0 0 foo2 + movl $1, %edi + .pseudoprobe 2494702099028631698 2 2 0 foo2 + callq foo@PLT + popq %rax + .cfi_def_cfa_offset 8 + retq +.Lfunc_end1: + .size foo2, .Lfunc_end1-foo2 + .cfi_endproc + # -- End function + .type a,@object # @a + .bss + .globl a + .p2align 2, 0x0 +a: + .long 0 # 0x0 + .size a, 4 + + +# CHECK-OBJ: COMDAT group section [ 3] `.group' [foo] contains 2 sections: +# CHECK-OBJ-NEXT: [Index] Name +# CHECK-OBJ-NEXT: [ 4] .text.foo +# CHECK-OBJ-NEXT: [ 11] .pseudo_probe.foo +# CHECK-OBJ: COMDAT group section [ 5] `.group' [foo2] contains 3 sections: +# CHECK-OBJ-NEXT: [Index] Name +# CHECK-OBJ-NEXT: [ 6] .text.foo2 +# CHECK-OBJ-NEXT: [ 7] .rela.text.foo2 +# CHECK-OBJ-NEXT: [ 12] .pseudo_probe.foo2 + +# CHECK-ELF: .text +# CHECK-ELF: .pseudo_probe +# CHECK-ELF-NOT: .pseudo_probe.foo +# CHECK-ELF-NOT: .pseudo_probe.foo2 diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -1171,8 +1171,9 @@ if (const MCSymbol *Group = ElfSec.getGroup()) { auto *S = static_cast(PseudoProbeSection); auto Flags = S->getFlags() | ELF::SHF_GROUP; - return Ctx->getELFSection(S->getName(), S->getType(), Flags, - S->getEntrySize(), Group->getName(), + return Ctx->getELFSection(S->getName() + "." + Group->getName(), + S->getType(), Flags, S->getEntrySize(), + Group->getName(), /*IsComdat=*/true); } } diff --git a/llvm/lib/MC/MCPseudoProbe.cpp b/llvm/lib/MC/MCPseudoProbe.cpp --- a/llvm/lib/MC/MCPseudoProbe.cpp +++ b/llvm/lib/MC/MCPseudoProbe.cpp @@ -584,10 +584,12 @@ const MCDecodedPseudoProbe *CallProbe = nullptr; for (const auto &Probe : Probes) { if (Probe.isCall()) { - assert(!CallProbe && - "There should be only one call probe corresponding to address " - "which is a callsite."); CallProbe = &Probe; + // Return the first call probe seen so far. Subsequent call probes, if + // any, are ignored as they should be a duplication of the first one due + // to the the way .pseudo_probe sections is organized. This should only + // happen to static functions with overlapping names. + break; } } return CallProbe; diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-emit.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-emit.ll --- a/llvm/test/Transforms/SampleProfile/pseudo-probe-emit.ll +++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-emit.ll @@ -6,6 +6,7 @@ ; RUN: FileCheck %s < %t1 --check-prefix=CHECK-ASM ; RUN: llc %t -function-sections -filetype=obj -o %t2 ; RUN: llvm-objdump --section-headers %t2 | FileCheck %s --check-prefix=CHECK-OBJ +; RUN: llvm-readelf -g %t2 | FileCheck %s --check-prefix=CHECK-ELF ; RUN: llvm-mc %t1 -filetype=obj -o %t3 ; RUN: llvm-objdump --section-headers %t3 | FileCheck %s --check-prefix=CHECK-OBJ @@ -13,7 +14,10 @@ @a = dso_local global i32 0, align 4 -define void @foo(i32 %x) !dbg !3 { +$foo = comdat any +$foo2 = comdat any + +define void @foo(i32 %x) comdat !dbg !3 { bb0: %cmp = icmp eq i32 %x, 0 ; CHECK-IL: call void @llvm.pseudoprobe(i64 [[#GUID:]], i64 1, i32 0, i64 -1), !dbg ![[#FAKELINE:]] @@ -46,7 +50,7 @@ declare void @bar(i32 %x) -define internal void @foo2(ptr %f) !dbg !4 { +define internal void @foo2(ptr %f) comdat !dbg !4 { entry: ; CHECK-IL: call void @llvm.pseudoprobe(i64 [[#GUID2:]], i64 1, i32 0, i64 -1) ; CHECK-MIR: PSEUDO_PROBE [[#GUID2:]], 1, 0, 0 @@ -93,9 +97,49 @@ ; CHECK-ASM-NEXT: .ascii "foo2" ; CHECK-OBJ-COUNT-2: .pseudo_probe_desc -; CHECK-OBJ: .pseudo_probe +; CHECK-OBH-COUNT-2: .pseudo_probe ; CHECK-OBJ-NOT: .rela.pseudo_probe +; CHECK-ELF: COMDAT group section [ 3] `.group' [foo] contains 3 sections: +; CHECK-ELF-NEXT: [Index] Name +; CHECK-ELF-NEXT: [ 4] .text.foo +; CHECK-ELF-NEXT: [ 5] .rela.text.foo +; CHECK-ELF-NEXT: [ 17] .pseudo_probe.foo +; CHECK-ELF: COMDAT group section [ 6] `.group' [foo2] contains 3 sections: +; CHECK-ELF-NEXT: [Index] Name +; CHECK-ELF-NEXT: [ 7] .text.foo2 +; CHECK-ELF-NEXT: [ 8] .rela.text.foo2 +; CHECK-ELF-NEXT: [ 18] .pseudo_probe.foo2 +; CHECK-ELF: COMDAT group section [ 10] `.group' [.pseudo_probe_desc_foo] contains 1 sections: +; CHECK-ELF-NEXT: [Index] Name +; CHECK-ELF-NEXT: [ 11] .pseudo_probe_desc + +; CHECK-ELF: COMDAT group section [ 12] `.group' [.pseudo_probe_desc_foo2] contains 1 sections: +; CHECK-ELF-NEXT: [Index] Name +; CHECK-ELF-NEXT: [ 13] .pseudo_probe_desc + +; Check the generation of .pseudo_probe_desc section with CFG encoding. +; CHECK-CFG: .section .pseudo_probe_desc,"",@progbits +; CHECK-CFG-NEXT: .quad [[#GUID:]] +; CHECK-CFG-NEXT: .quad [[#HASH:]] +; CHECK-CFG-NEXT: .byte 3 +; CHECK-CFG-NEXT: .ascii "foo" +; CHECK-CFG-NEXT: .byte 4 +; CHECK-CFG-NEXT: .byte 2 +; CHECK-CFG-NEXT: .byte 2 +; CHECK-CFG-NEXT: .byte 3 +; CHECK-CFG-NEXT: .byte 1 +; CHECK-CFG-NEXT: .byte 4 +; CHECK-CFG-NEXT: .byte 1 +; CHECK-CFG-NEXT: .byte 4 +; CHECK-CFG-NEXT: .byte 0 +; CHECK-CFG-NEXT: .quad [[#GUID2:]] +; CHECK-CFG-NEXT: .quad [[#HASH2:]] +; CHECK-CFG-NEXT: .byte 4 +; CHECK-CFG-NEXT: .ascii "foo2" +; CHECK-CFG-NEXT: .byte 1 +; CHECK-CFG-NEXT: .byte 0 + !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!9, !10}