Skip to content

Commit c102184

Browse files
authored
[ELF] Synthesize STT_FILE if necessary (#209087)
lld groups local symbols in .symtab by input file, appending a symbol converted to STB_LOCAL (hidden visibility, version script `local:`, or --exclude-libs) to its file's group. The nearest preceding STT_FILE then claims the symbol, but the attribution can be wrong: the file may contain multiple STT_FILE symbols (-r output), or lack an STT_FILE for the symbol's unit. ``` FILE LOCAL DEFAULT ABS a.c NOTYPE LOCAL DEFAULT 7 a_local FILE LOCAL DEFAULT ABS b.c NOTYPE LOCAL DEFAULT 7 b_local NOTYPE LOCAL DEFAULT 7 a_localized ``` Follow GNU ld: - If the output contains an STT_FILE symbol, place at the end of the local part, after a synthetic STT_FILE with an empty name, every local that cannot be attributed to a file: symbols converted to STB_LOCAL, linker-synthesized symbols such as `_DYNAMIC`, and range-extension thunks (parented to the internal file, which has no STT_FILE). - For -r output, synthesize an STT_FILE named after the input file for an input that outputs local symbols but no STT_FILE, so that its locals are not attributed to a preceding file. We use the basename instead of the full name for local determinism (#47367). GNU ld synthesizes this per-input STT_FILE for executable and shared-object output as well. Restrict it to -r for now to minimize test updates. Close #47367 and #191478
1 parent 15cd911 commit c102184

12 files changed

Lines changed: 270 additions & 93 deletions

lld/ELF/SyntheticSections.cpp

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,34 +2003,57 @@ void SymbolTableBaseSection::finalizeContents() {
20032003
s.sym->dynsymIndex = ++i;
20042004
}
20052005

2006-
// The ELF spec requires that all local symbols precede global symbols, so we
2007-
// sort symbol entries in this function. (For .dynsym, we don't do that because
2008-
// symbols for dynamic linking are inherently all globals.)
2006+
// The ELF spec requires local symbols to precede globals. We additionally group
2007+
// the locals by file, each led by its first STT_FILE.
20092008
//
2010-
// Aside from above, we put local symbols in groups starting with the STT_FILE
2011-
// symbol. That is convenient for purpose of identifying where are local symbols
2012-
// coming from.
2009+
// From firstGlobalIdx on, a local cannot be attributed to a file (a demoted
2010+
// global, or a thunk/errata patch added later). Move these after the per-file
2011+
// groups, behind the synthetic STT_FILE synthSttFileSym.
20132012
void SymbolTableBaseSection::sortSymTabSymbols() {
2014-
// Move all local symbols before global symbols.
2015-
auto e = std::stable_partition(
2016-
symbols.begin(), symbols.end(),
2017-
[](const SymbolTableEntry &s) { return s.sym->isLocal(); });
2018-
size_t numLocals = e - symbols.begin();
2019-
getParent()->info = numLocals + 1;
2020-
2021-
// We want to group the local symbols by file. For that we rebuild the local
2022-
// part of the symbols vector. We do not need to care about the STT_FILE
2023-
// symbols, they are already naturally placed first in each group. That
2024-
// happens because STT_FILE is always the first symbol in the object and hence
2025-
// precede all other local symbols we add for a file.
2026-
MapVector<InputFile *, SmallVector<SymbolTableEntry, 0>> arr;
2027-
for (const SymbolTableEntry &s : llvm::make_range(symbols.begin(), e))
2028-
arr[s.sym->file].push_back(s);
2013+
MapVector<InputFile *, SmallVector<SymbolTableEntry, 0>> fileToLocals;
2014+
SmallVector<SymbolTableEntry, 0> localized, globals;
2015+
SymbolTableEntry fileEntry{};
2016+
for (size_t i = 0, e = symbols.size(); i != e; ++i) {
2017+
const SymbolTableEntry &s = symbols[i];
2018+
if (!s.sym->isLocal())
2019+
globals.push_back(s);
2020+
else if (s.sym == synthSttFileSym)
2021+
fileEntry = s;
2022+
else if (synthSttFileSym && i >= firstGlobalIdx)
2023+
localized.push_back(s);
2024+
else
2025+
fileToLocals[s.sym->file].push_back(s);
2026+
}
20292027

20302028
auto i = symbols.begin();
2031-
for (auto &p : arr)
2029+
for (auto &p : fileToLocals)
20322030
for (SymbolTableEntry &entry : p.second)
20332031
*i++ = entry;
2032+
if (synthSttFileSym) {
2033+
*i++ = fileEntry;
2034+
i = std::copy(localized.begin(), localized.end(), i);
2035+
}
2036+
getParent()->info = i - symbols.begin() + 1;
2037+
std::copy(globals.begin(), globals.end(), i);
2038+
}
2039+
2040+
// A symbol converted to STB_LOCAL cannot be reliably attributed to a file:
2041+
// within a file's group the wrong STT_FILE would claim it, as a file may hold
2042+
// several STT_FILE symbols (relocatable output) or none. Like GNU ld, when the
2043+
// output has an STT_FILE, add a synthetic empty-name STT_FILE.
2044+
void SymbolTableBaseSection::maybeAddSttFile() {
2045+
ArrayRef<SymbolTableEntry> syms = symbols;
2046+
if (llvm::none_of(syms.take_front(firstGlobalIdx),
2047+
[](const SymbolTableEntry &s) { return s.sym->isFile(); }))
2048+
return;
2049+
if (llvm::any_of(
2050+
syms.drop_front(firstGlobalIdx),
2051+
[](const SymbolTableEntry &s) { return s.sym->isLocal(); })) {
2052+
synthSttFileSym =
2053+
makeDefined(ctx, ctx.internalFile, "", STB_LOCAL, STV_DEFAULT, STT_FILE,
2054+
/*value=*/0, /*size=*/0, nullptr);
2055+
addSymbol(synthSttFileSym);
2056+
}
20342057
}
20352058

20362059
void SymbolTableBaseSection::addSymbol(Symbol *b) {

lld/ELF/SyntheticSections.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,8 @@ class SymbolTableBaseSection : public SyntheticSection {
659659
void finalizeContents() override;
660660
size_t getSize() const override { return getNumSymbols() * entsize; }
661661
void addSymbol(Symbol *sym);
662+
void maybeAddSttFile();
663+
void markGlobalPart() { firstGlobalIdx = symbols.size(); }
662664
unsigned getNumSymbols() const { return symbols.size() + 1; }
663665
size_t getSymbolIndex(const Symbol &sym);
664666
ArrayRef<SymbolTableEntry> getSymbols() const { return symbols; }
@@ -669,6 +671,14 @@ class SymbolTableBaseSection : public SyntheticSection {
669671
// A vector of symbols and their string table offsets.
670672
SmallVector<SymbolTableEntry, 0> symbols;
671673

674+
// Synthetic STT_FILE with an empty name, added by maybeAddSttFile and placed
675+
// by sortSymTabSymbols before all locals that cannot be attributed to a file.
676+
Defined *synthSttFileSym = nullptr;
677+
678+
// symbols.size() before the global loop. Locals from here on are not
679+
// file-attributable and move behind synthSttFileSym.
680+
size_t firstGlobalIdx = 0;
681+
672682
StringTableSection &strTabSec;
673683

674684
llvm::once_flag onceFlag;

lld/ELF/Writer.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "llvm/ADT/StringMap.h"
3131
#include "llvm/Support/BLAKE3.h"
3232
#include "llvm/Support/Parallel.h"
33+
#include "llvm/Support/Path.h"
3334
#include "llvm/Support/RandomNumberGenerator.h"
3435
#include "llvm/Support/TimeProfiler.h"
3536
#include "llvm/Support/xxhash.h"
@@ -466,9 +467,24 @@ static void demoteAndCopyLocalSymbols(Ctx &ctx) {
466467
symsVec[i].push_back(b);
467468
}
468469
});
469-
for (auto &syms : ArrayRef(symsVec.get(), ctx.objectFiles.size()))
470+
for (size_t i = 0, e = ctx.objectFiles.size(); i != e; ++i) {
471+
// For -r, synthesize an STT_FILE named after the input file for an input
472+
// that contributes local symbols but no STT_FILE, so that its symbols are
473+
// not attributed to another file's STT_FILE (matching GNU ld).
474+
// --discard-all discards STT_FILE symbols.
475+
auto &syms = symsVec[i];
476+
if (ctx.arg.relocatable && ctx.arg.discard != DiscardPolicy::All &&
477+
!syms.empty() &&
478+
llvm::none_of(syms, [](Symbol *s) { return s->isFile(); })) {
479+
InputFile *file = ctx.objectFiles[i];
480+
ctx.in.symTab->addSymbol(
481+
makeDefined(ctx, file, sys::path::filename(file->getName()),
482+
STB_LOCAL, /*stOther=*/0, STT_FILE, /*value=*/0,
483+
/*size=*/0, nullptr));
484+
}
470485
for (Symbol *sym : syms)
471486
ctx.in.symTab->addSymbol(sym);
487+
}
472488
}
473489

474490
// Create a section symbol for each output section so that we can represent
@@ -1944,6 +1960,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
19441960

19451961
{
19461962
llvm::TimeTraceScope timeScope("Add symbols to symtabs");
1963+
if (ctx.in.symTab)
1964+
ctx.in.symTab->markGlobalPart();
19471965
// Now that we have defined all possible global symbols including linker-
19481966
// synthesized ones. Visit all symbols to give the finishing touches.
19491967
for (Symbol *sym : ctx.symtab->getSymbols()) {
@@ -1964,7 +1982,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
19641982
addVerneed(ctx, *sym);
19651983
}
19661984
}
1967-
1985+
if (ctx.in.symTab && !ctx.arg.relocatable)
1986+
ctx.in.symTab->maybeAddSttFile();
19681987
}
19691988

19701989
if (ctx.in.mipsGot)

lld/test/ELF/local-symbols-order.s

Lines changed: 145 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,145 @@
1-
# REQUIRES: x86
2-
3-
# RUN: echo '.data; .file "file2"; foo2:; .global bar2; .hidden bar2; bar2:' > %t2.s
4-
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o
5-
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
6-
7-
# RUN: ld.lld -o %t %t1.o %t2.o --emit-relocs
8-
# RUN: llvm-readelf --symbols --sections %t | FileCheck %s
9-
10-
## Check we sort local symbols to match the following order:
11-
## file1, local1, section1, hidden1, file2, local2, section2, hidden2 ...
12-
13-
# CHECK: Section Headers:
14-
# CHECK: [Nr] Name
15-
# CHECK: [ [[ST:.*]]] .text
16-
# CHECK: [ [[SD:.*]]] .data
17-
# CHECK: [ [[SC:.*]]] .comment
18-
19-
# CHECK: Size Type Bind Vis Ndx Name
20-
# CHECK-NEXT: 0 NOTYPE LOCAL DEFAULT UND
21-
# CHECK-NEXT: 0 FILE LOCAL DEFAULT ABS file1
22-
# CHECK-NEXT: 0 NOTYPE LOCAL DEFAULT 1 foo1
23-
# CHECK-NEXT: 0 SECTION LOCAL DEFAULT [[ST]]
24-
# CHECK-NEXT: 0 NOTYPE LOCAL HIDDEN 1 bar1
25-
# CHECK-NEXT: 0 FILE LOCAL DEFAULT ABS file2
26-
# CHECK-NEXT: 0 NOTYPE LOCAL DEFAULT 2 foo2
27-
# CHECK-NEXT: 0 SECTION LOCAL DEFAULT [[SD]]
28-
# CHECK-NEXT: 0 NOTYPE LOCAL HIDDEN 2 bar2
29-
# CHECK-NEXT: 0 SECTION LOCAL DEFAULT [[SC]]
30-
31-
foo1:
32-
33-
.global bar1
34-
.hidden bar1
35-
bar1:
36-
37-
.file "file1"
1+
# REQUIRES: aarch64
2+
## Check the order of local symbols: grouped by file, each group led by the file's STT symbol.
3+
## Symbols converted to STB_LOCAL are placed at the end of the local part after a synthetic
4+
## STT_FILE with an empty name, omitted if the output has no STT_FILE.
5+
6+
# RUN: rm -rf %t && split-file %s %t && cd %t
7+
## -implicit-mapsyms omits the input $x/$d mapping symbols; only the linker's
8+
## own thunk mapping symbols remain (THUNK below).
9+
# RUN: llvm-mc -filetype=obj -triple=aarch64 -implicit-mapsyms a.s -o a.o
10+
# RUN: llvm-mc -filetype=obj -triple=aarch64 -implicit-mapsyms b.s -o b.o
11+
# RUN: mkdir c && llvm-mc -filetype=obj -triple=aarch64 -implicit-mapsyms c.s -o c/a.o
12+
13+
## Only b.c has an STT_FILE. a.o's a_local has no leading STT_FILE; the hidden
14+
## a_hidden follows the synthetic STT_FILE. --emit-relocs adds STT_SECTION
15+
## symbols to their file's group.
16+
# RUN: ld.lld --emit-relocs a.o b.o -o ab
17+
# RUN: llvm-readelf -s ab | FileCheck %s
18+
19+
# CHECK: NOTYPE LOCAL DEFAULT [[#]] a_local
20+
# CHECK-NEXT: SECTION LOCAL DEFAULT [[#]] .text
21+
# CHECK-NEXT: FILE LOCAL DEFAULT ABS b.c
22+
# CHECK-NEXT: NOTYPE LOCAL DEFAULT [[#]] b_local
23+
# CHECK-NEXT: SECTION LOCAL DEFAULT [[#]] .data
24+
# CHECK-NEXT: SECTION LOCAL DEFAULT [[#]] .comment
25+
# CHECK-NEXT: FILE LOCAL DEFAULT ABS{{ $}}
26+
# CHECK-NEXT: NOTYPE LOCAL HIDDEN [[#]] a_hidden
27+
# CHECK-NEXT: NOTYPE GLOBAL DEFAULT [[#]] a_localized
28+
# CHECK-NEXT: NOTYPE GLOBAL DEFAULT [[#]] a_exported
29+
# CHECK-NEXT: NOTYPE GLOBAL DEFAULT [[#]] b_localized
30+
# CHECK-NEXT: NOTYPE GLOBAL DEFAULT [[#]] b_exported
31+
32+
## For -r, synthesize STT_FILE for a.o, which lacks one.
33+
# RUN: ld.lld -r a.o b.o -o ab.o
34+
# RUN: llvm-readelf -s ab.o | FileCheck %s --check-prefix=RO
35+
36+
# RO: FILE LOCAL DEFAULT ABS a.o
37+
# RO-NEXT: NOTYPE LOCAL DEFAULT [[#]] a_local
38+
# RO-NEXT: SECTION LOCAL DEFAULT [[#]] .text
39+
# RO-NEXT: FILE LOCAL DEFAULT ABS b.c
40+
# RO-NEXT: NOTYPE LOCAL DEFAULT [[#]] b_local
41+
# RO-NEXT: SECTION LOCAL DEFAULT [[#]] .data
42+
# RO-NEXT: NOTYPE GLOBAL DEFAULT [[#]] a_localized
43+
# RO-NEXT: NOTYPE GLOBAL HIDDEN [[#]] a_hidden
44+
# RO-NEXT: NOTYPE GLOBAL DEFAULT [[#]] a_exported
45+
# RO-NEXT: NOTYPE GLOBAL DEFAULT [[#]] b_localized
46+
# RO-NEXT: NOTYPE GLOBAL DEFAULT [[#]] b_exported
47+
48+
## Synthesize STT_FILE named after its basename, not its path, for local determinism (#47367).
49+
# RUN: ld.lld -r ab.o c/a.o -o abc.o
50+
# RUN: llvm-readelf -s abc.o | FileCheck %s --check-prefix=MULTI
51+
52+
# MULTI: FILE LOCAL DEFAULT ABS a.o
53+
# MULTI-NEXT: NOTYPE LOCAL DEFAULT [[#]] a_local
54+
# MULTI-NEXT: FILE LOCAL DEFAULT ABS b.c
55+
# MULTI-NEXT: NOTYPE LOCAL DEFAULT [[#]] b_local
56+
# MULTI-NEXT: SECTION LOCAL DEFAULT [[#]] .text
57+
# MULTI-NEXT: SECTION LOCAL DEFAULT [[#]] .data
58+
# MULTI-NEXT: FILE LOCAL DEFAULT ABS a.o
59+
# MULTI-NEXT: NOTYPE LOCAL DEFAULT [[#]] far
60+
61+
## Symbols localized by a version script follow a synthetic STT_FILE with empty name.
62+
# RUN: ld.lld -shared --version-script=ver ab.o -o ab.so
63+
# RUN: llvm-readelf -s ab.so | FileCheck %s --check-prefix=VER
64+
65+
# VER: FILE LOCAL DEFAULT ABS a.o
66+
# VER-NEXT: NOTYPE LOCAL DEFAULT [[#]] a_local
67+
# VER-NEXT: FILE LOCAL DEFAULT ABS b.c
68+
# VER-NEXT: NOTYPE LOCAL DEFAULT [[#]] b_local
69+
# VER-NEXT: FILE LOCAL DEFAULT ABS{{ $}}
70+
# VER-NEXT: NOTYPE LOCAL DEFAULT [[#]] a_localized
71+
# VER-NEXT: NOTYPE LOCAL HIDDEN [[#]] a_hidden
72+
# VER-NEXT: NOTYPE LOCAL DEFAULT [[#]] b_localized
73+
# VER-NEXT: NOTYPE LOCAL HIDDEN [[#]] _DYNAMIC
74+
# VER-NEXT: NOTYPE GLOBAL DEFAULT [[#]] a_exported
75+
# VER-NEXT: NOTYPE GLOBAL DEFAULT [[#]] b_exported
76+
77+
## A range-extension thunk (and its $x/$d) is added by
78+
## finalizeAddressDependentContent and parented to the internal file, which has
79+
## no STT_FILE. Like the demoted c_hidden it cannot be attributed to a file, so
80+
## it follows the synthetic STT_FILE.
81+
# RUN: ld.lld c/a.o b.o -T lds -o cb
82+
# RUN: llvm-readelf -s cb | FileCheck %s --check-prefix=THUNK
83+
84+
# THUNK: NOTYPE LOCAL DEFAULT [[#]] far
85+
# THUNK-NEXT: FILE LOCAL DEFAULT ABS b.c
86+
# THUNK-NEXT: NOTYPE LOCAL DEFAULT [[#]] b_local
87+
# THUNK-NEXT: FILE LOCAL DEFAULT ABS{{ $}}
88+
# THUNK-NEXT: NOTYPE LOCAL HIDDEN [[#]] c_hidden
89+
# THUNK-NEXT: FUNC LOCAL DEFAULT [[#]] __AArch64AbsLongThunk_{{.*}}
90+
# THUNK-NEXT: NOTYPE LOCAL DEFAULT [[#]] $x
91+
# THUNK-NEXT: NOTYPE LOCAL DEFAULT [[#]] $d
92+
# THUNK-NEXT: NOTYPE GLOBAL DEFAULT [[#]] _start
93+
94+
## --discard-all discards STT_FILE symbols as well. With no STT_FILE in the
95+
## output, no synthetic STT_FILE is added.
96+
# RUN: ld.lld -shared --discard-all --version-script=ver ab.o -o ab2.so
97+
# RUN: llvm-readelf -s ab2.so | FileCheck %s --check-prefix=DISCARD --implicit-check-not=FILE
98+
99+
# DISCARD: NOTYPE LOCAL DEFAULT [[#]] a_localized
100+
# DISCARD-NEXT: NOTYPE LOCAL HIDDEN [[#]] a_hidden
101+
# DISCARD-NEXT: NOTYPE LOCAL DEFAULT [[#]] b_localized
102+
# DISCARD-NEXT: NOTYPE LOCAL HIDDEN [[#]] _DYNAMIC
103+
# DISCARD-NEXT: NOTYPE GLOBAL DEFAULT [[#]] a_exported
104+
# DISCARD-NEXT: NOTYPE GLOBAL DEFAULT [[#]] b_exported
105+
106+
#--- a.s
107+
a_local:
108+
.globl a_localized
109+
a_localized:
110+
.globl a_hidden
111+
.hidden a_hidden
112+
a_hidden:
113+
.globl a_exported
114+
a_exported:
115+
nop
116+
117+
#--- b.s
118+
.file "b.c"
119+
.data
120+
b_local:
121+
.globl b_localized
122+
b_localized:
123+
.globl b_exported
124+
b_exported:
125+
.byte 0
126+
127+
#--- c.s
128+
.globl _start, c_hidden
129+
.hidden c_hidden
130+
_start:
131+
bl far
132+
c_hidden:
133+
ret
134+
.section .far,"ax"
135+
far:
136+
ret
137+
138+
#--- lds
139+
SECTIONS {
140+
.text 0x10000 : { *(.text) }
141+
.far 0x10000000 : { *(.far) }
142+
}
143+
144+
#--- ver
145+
v1 { global: *_exported; local: *; };

lld/test/ELF/lto/parallel-internalize.ll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@
3535
; CHECK-NEXT: Section: Absolute
3636
; CHECK-NEXT: }
3737
; CHECK-NEXT: Symbol {
38+
; CHECK-NEXT: Name: (0)
39+
; CHECK-NEXT: Value: 0x0
40+
; CHECK-NEXT: Size: 0
41+
; CHECK-NEXT: Binding: Local
42+
; CHECK-NEXT: Type: File
43+
; CHECK-NEXT: Other: 0
44+
; CHECK-NEXT: Section: Absolute
45+
; CHECK-NEXT: }
46+
; CHECK-NEXT: Symbol {
3847
; CHECK-NEXT: Name: bar
3948
; CHECK-NEXT: Value:
4049
; CHECK-NEXT: Size: 8

lld/test/ELF/ppc64-local-entry.s

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# RUN: llvm-mc -filetype=obj -triple=powerpc64 %s -o %t
44
# RUN: ld.lld -r %t -o %t2
5-
# RUN: llvm-objdump -s --section=.symtab %t2 | FileCheck %s
5+
# RUN: llvm-readelf -s %t2 | FileCheck %s
66

77
.text
88
.abiversion 2
@@ -37,11 +37,6 @@ _start:
3737
.type g,@object # @g
3838
.lcomm g,4,4
3939

40-
// We expect the st_other byte to be 0x60:
41-
// localentry = 011 (gep + 2 instructions), reserved = 000,
42-
// visibility = 00 (STV_DEFAULT)
43-
// Currently, llvm-objdump does not support displaying
44-
// st_other's PPC64 specific flags, thus we check the
45-
// result of the hexdump of .symtab section.
46-
47-
// CHECK: 0060 00000003 12600001 00000000 00000000
40+
## We expect st_other to be 0x60: localentry = 011 (gep + 2 instructions),
41+
## reserved = 000, visibility = 00 (STV_DEFAULT).
42+
# CHECK: FUNC GLOBAL DEFAULT [<other: 0x60>] [[#]] _start

lld/test/ELF/relocatable-comdat-multiple.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# CHECK-NEXT: Name: .group
1010
# CHECK-NEXT: Index: 2
1111
# CHECK-NEXT: Link: 9
12-
# CHECK-NEXT: Info: 1
12+
# CHECK-NEXT: Info: 2
1313
# CHECK-NEXT: Type: COMDAT
1414
# CHECK-NEXT: Signature: aaa
1515
# CHECK-NEXT: Section(s) in group [
@@ -21,7 +21,7 @@
2121
# CHECK-NEXT: Name: .group
2222
# CHECK-NEXT: Index: 5
2323
# CHECK-NEXT: Link: 9
24-
# CHECK-NEXT: Info: 6
24+
# CHECK-NEXT: Info: 8
2525
# CHECK-NEXT: Type: COMDAT
2626
# CHECK-NEXT: Signature: bbb
2727
# CHECK-NEXT: Section(s) in group [

0 commit comments

Comments
 (0)