Skip to content

Commit 5818572

Browse files
authored
[Object][Wasm] Generate symbol info from name section names (#81063)
Currently symbol info is generated from a linking section or from export names. This PR generates symbols in a WasmObjectFile from the name section as well, which allows tools like objdump and nm to show useful information for more linked binaries. There are some limitations: most notably that we don't assume any particular ABI, so we don't get detailed information about data symbols if the segments are merged (which is the default). Covers most of the desired functionality from #76107
1 parent 3f9d8d8 commit 5818572

File tree

4 files changed

+172
-4
lines changed

4 files changed

+172
-4
lines changed

llvm/lib/Object/WasmObjectFile.cpp

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -508,10 +508,17 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
508508
llvm::DenseSet<uint64_t> SeenGlobals;
509509
llvm::DenseSet<uint64_t> SeenSegments;
510510

511+
// If there is symbol info from the export section, this info will supersede
512+
// it, but not info from a linking section
513+
if (!HasLinkingSection) {
514+
Symbols.clear();
515+
}
516+
511517
while (Ctx.Ptr < Ctx.End) {
512518
uint8_t Type = readUint8(Ctx);
513519
uint32_t Size = readVaruint32(Ctx);
514520
const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
521+
515522
switch (Type) {
516523
case wasm::WASM_NAMES_FUNCTION:
517524
case wasm::WASM_NAMES_GLOBAL:
@@ -521,6 +528,16 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
521528
uint32_t Index = readVaruint32(Ctx);
522529
StringRef Name = readString(Ctx);
523530
wasm::NameType nameType = wasm::NameType::FUNCTION;
531+
wasm::WasmSymbolInfo Info{Name,
532+
/*Kind */ wasm::WASM_SYMBOL_TYPE_FUNCTION,
533+
/* Flags */ 0,
534+
/* ImportModule */ std::nullopt,
535+
/* ImportName */ std::nullopt,
536+
/* ExportName */ std::nullopt,
537+
{/* ElementIndex */ Index}};
538+
const wasm::WasmSignature *Signature = nullptr;
539+
const wasm::WasmGlobalType *GlobalType = nullptr;
540+
const wasm::WasmTableType *TableType = nullptr;
524541
if (Type == wasm::WASM_NAMES_FUNCTION) {
525542
if (!SeenFunctions.insert(Index).second)
526543
return make_error<GenericBinaryError>(
@@ -529,26 +546,50 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
529546
return make_error<GenericBinaryError>("invalid function name entry",
530547
object_error::parse_failed);
531548

532-
if (isDefinedFunctionIndex(Index))
533-
getDefinedFunction(Index).DebugName = Name;
549+
if (isDefinedFunctionIndex(Index)) {
550+
wasm::WasmFunction &F = getDefinedFunction(Index);
551+
F.DebugName = Name;
552+
Signature = &Signatures[F.SigIndex];
553+
if (F.ExportName) {
554+
Info.ExportName = F.ExportName;
555+
Info.Flags |= wasm::WASM_SYMBOL_BINDING_GLOBAL;
556+
} else {
557+
Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
558+
}
559+
} else {
560+
Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;
561+
}
534562
} else if (Type == wasm::WASM_NAMES_GLOBAL) {
535-
nameType = wasm::NameType::GLOBAL;
536563
if (!SeenGlobals.insert(Index).second)
537564
return make_error<GenericBinaryError>("global named more than once",
538565
object_error::parse_failed);
539566
if (!isValidGlobalIndex(Index) || Name.empty())
540567
return make_error<GenericBinaryError>("invalid global name entry",
541568
object_error::parse_failed);
569+
nameType = wasm::NameType::GLOBAL;
570+
Info.Kind = wasm::WASM_SYMBOL_TYPE_GLOBAL;
571+
if (isDefinedGlobalIndex(Index)) {
572+
GlobalType = &getDefinedGlobal(Index).Type;
573+
} else {
574+
Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;
575+
}
542576
} else {
543-
nameType = wasm::NameType::DATA_SEGMENT;
544577
if (!SeenSegments.insert(Index).second)
545578
return make_error<GenericBinaryError>(
546579
"segment named more than once", object_error::parse_failed);
547580
if (Index > DataSegments.size())
548581
return make_error<GenericBinaryError>("invalid data segment name entry",
549582
object_error::parse_failed);
583+
nameType = wasm::NameType::DATA_SEGMENT;
584+
Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;
585+
Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
586+
assert(Index < DataSegments.size());
587+
Info.DataRef = wasm::WasmDataReference{
588+
Index, 0, DataSegments[Index].Data.Content.size()};
550589
}
551590
DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name});
591+
if (!HasLinkingSection)
592+
Symbols.emplace_back(Info, GlobalType, TableType, Signature);
552593
}
553594
break;
554595
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# RUN: yaml2obj %s -o %t.wasm
2+
# RUN: llvm-nm -P %t.wasm | FileCheck %s
3+
#
4+
# Test that names from the linking section override those from the name section
5+
# CHECK: foo T 1 0
6+
# CHECK-NOT: my_func_local_name
7+
8+
--- !WASM
9+
FileHeader:
10+
Version: 0x1
11+
Sections:
12+
- Type: TYPE
13+
Signatures:
14+
- Index: 0
15+
ParamTypes: []
16+
ReturnTypes: []
17+
- Type: FUNCTION
18+
FunctionTypes: [ 0, 0 ]
19+
- Type: CODE
20+
Functions:
21+
- Index: 0
22+
Locals:
23+
Body: 00
24+
- Index: 1
25+
Locals:
26+
Body: 00
27+
- Type: CUSTOM
28+
Name: linking
29+
Version: 2
30+
SymbolTable:
31+
- Index: 0
32+
Kind: FUNCTION
33+
Name: foo
34+
Flags: [ VISIBILITY_HIDDEN ]
35+
Function: 0
36+
- Type: CUSTOM
37+
Name: name
38+
FunctionNames:
39+
- Index: 1
40+
Name: my_func_local_name
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# RUN: yaml2obj %s -o %t.wasm
2+
# RUN: llvm-objdump -t %t.wasm | FileCheck %s
3+
#
4+
# CHECK: SYMBOL TABLE:
5+
# CHECK-NEXT: 00000000 F *UND* my_func_import_name
6+
# CHECK-NEXT: 00000083 g F CODE my_func_export_name
7+
# CHECK-NEXT: 00000086 l F CODE my_func_local_name
8+
# CHECK-NEXT: 00000000 *UND* my_global_import_name
9+
# CHECK-NEXT: 00000001 g GLOBAL my_global_export_name
10+
# CHECK-NEXT: 00000000 l O DATA my_datasegment_name
11+
12+
--- !WASM
13+
FileHeader:
14+
Version: 0x1
15+
Sections:
16+
- Type: TYPE
17+
Signatures:
18+
- Index: 0
19+
ParamTypes: []
20+
ReturnTypes: []
21+
- Type: IMPORT
22+
Imports:
23+
- Module: env
24+
Field: foo
25+
Kind: FUNCTION
26+
SigIndex: 0
27+
- Module: env
28+
Field: bar
29+
Kind: GLOBAL
30+
GlobalType: I32
31+
GlobalMutable: true
32+
- Module: env
33+
Field: memory
34+
Kind: MEMORY
35+
Memory:
36+
Minimum: 0x1
37+
- Type: FUNCTION
38+
FunctionTypes: [ 0, 0 ]
39+
- Type: GLOBAL
40+
Globals:
41+
- Index: 1
42+
Mutable: false
43+
Type: I32
44+
InitExpr:
45+
Opcode: I32_CONST
46+
Value: 42
47+
- Type: EXPORT
48+
Exports:
49+
- Name: my_func_export
50+
Kind: FUNCTION
51+
Index: 1
52+
- Name: my_global_export
53+
Kind: GLOBAL
54+
Index: 1
55+
- Type: CODE
56+
Functions:
57+
- Index: 1
58+
Locals:
59+
Body: 00
60+
- Index: 2
61+
Locals:
62+
Body: 00
63+
- Type: DATA
64+
Segments:
65+
- SectionOffset: 0
66+
InitFlags: 0
67+
Offset:
68+
Opcode: I32_CONST
69+
Value: 0
70+
Content: 'abcd1234'
71+
- Type: CUSTOM
72+
Name: name
73+
FunctionNames:
74+
- Index: 0
75+
Name: my_func_import_name
76+
- Index: 1
77+
Name: my_func_export_name
78+
- Index: 2
79+
Name: my_func_local_name
80+
GlobalNames:
81+
- Index: 0
82+
Name: my_global_import_name
83+
- Index: 1
84+
Name: my_global_export_name
85+
DataSegmentNames:
86+
- Index: 0
87+
Name: my_datasegment_name

0 commit comments

Comments
 (0)