Skip to content

Commit 4e8cb01

Browse files
authored
[WebAssembly] Add symbol information for shared libraries (#75238)
The current (experimental) spec for WebAssembly shared libraries does not include a full symbol table like the object format. This change extracts symbol information from the normal wasm exports. This is the first step in having the linker report undefined symbols when linking with shared libraries. The current behaviour is to ignore all undefined symbols when linking with `-pie` or `-shared`. See emscripten-core/emscripten#18198
1 parent 2c27013 commit 4e8cb01

File tree

4 files changed

+186
-4
lines changed

4 files changed

+186
-4
lines changed

llvm/include/llvm/Object/Wasm.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ class WasmObjectFile : public ObjectFile {
144144
ArrayRef<wasm::WasmGlobal> globals() const { return Globals; }
145145
ArrayRef<wasm::WasmTag> tags() const { return Tags; }
146146
ArrayRef<wasm::WasmExport> exports() const { return Exports; }
147-
ArrayRef<WasmSymbol> syms() const { return Symbols; }
148147
const wasm::WasmLinkingData &linkingData() const { return LinkingData; }
149148
uint32_t getNumberOfSymbols() const { return Symbols.size(); }
150149
ArrayRef<wasm::WasmElemSegment> elements() const { return ElemSegments; }

llvm/lib/Object/WasmObjectFile.cpp

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,10 @@ Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
599599

600600
Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
601601
uint32_t Count = readVaruint32(Ctx);
602+
// Clear out any symbol information that was derived from the exports
603+
// section.
604+
LinkingData.SymbolTable.clear();
605+
Symbols.clear();
602606
LinkingData.SymbolTable.reserve(Count);
603607
Symbols.reserve(Count);
604608
StringSet<> SymbolNames;
@@ -1290,37 +1294,75 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
12901294
Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
12911295
uint32_t Count = readVaruint32(Ctx);
12921296
Exports.reserve(Count);
1297+
LinkingData.SymbolTable.reserve(Count);
1298+
Symbols.reserve(Count);
12931299
for (uint32_t I = 0; I < Count; I++) {
12941300
wasm::WasmExport Ex;
12951301
Ex.Name = readString(Ctx);
12961302
Ex.Kind = readUint8(Ctx);
12971303
Ex.Index = readVaruint32(Ctx);
1304+
const wasm::WasmSignature *Signature = nullptr;
1305+
const wasm::WasmGlobalType *GlobalType = nullptr;
1306+
const wasm::WasmTableType *TableType = nullptr;
1307+
wasm::WasmSymbolInfo Info;
1308+
Info.Name = Ex.Name;
1309+
Info.Flags = 0;
12981310
switch (Ex.Kind) {
1299-
case wasm::WASM_EXTERNAL_FUNCTION:
1300-
1311+
case wasm::WASM_EXTERNAL_FUNCTION: {
13011312
if (!isDefinedFunctionIndex(Ex.Index))
13021313
return make_error<GenericBinaryError>("invalid function export",
13031314
object_error::parse_failed);
13041315
getDefinedFunction(Ex.Index).ExportName = Ex.Name;
1316+
Info.Kind = wasm::WASM_SYMBOL_TYPE_FUNCTION;
1317+
Info.ElementIndex = Ex.Index;
1318+
unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
1319+
wasm::WasmFunction &Function = Functions[FuncIndex];
1320+
Signature = &Signatures[Function.SigIndex];
13051321
break;
1306-
case wasm::WASM_EXTERNAL_GLOBAL:
1322+
}
1323+
case wasm::WASM_EXTERNAL_GLOBAL: {
13071324
if (!isValidGlobalIndex(Ex.Index))
13081325
return make_error<GenericBinaryError>("invalid global export",
13091326
object_error::parse_failed);
1327+
Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;
1328+
uint64_t Offset = 0;
1329+
if (isDefinedGlobalIndex(Ex.Index)) {
1330+
auto Global = getDefinedGlobal(Ex.Index);
1331+
if (!Global.InitExpr.Extended) {
1332+
auto Inst = Global.InitExpr.Inst;
1333+
if (Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1334+
Offset = Inst.Value.Int32;
1335+
} else if (Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1336+
Offset = Inst.Value.Int64;
1337+
}
1338+
}
1339+
}
1340+
Info.DataRef = wasm::WasmDataReference{0, Offset, 0};
13101341
break;
1342+
}
13111343
case wasm::WASM_EXTERNAL_TAG:
13121344
if (!isValidTagIndex(Ex.Index))
13131345
return make_error<GenericBinaryError>("invalid tag export",
13141346
object_error::parse_failed);
1347+
Info.Kind = wasm::WASM_SYMBOL_TYPE_TAG;
1348+
Info.ElementIndex = Ex.Index;
13151349
break;
13161350
case wasm::WASM_EXTERNAL_MEMORY:
1351+
break;
13171352
case wasm::WASM_EXTERNAL_TABLE:
1353+
Info.Kind = wasm::WASM_SYMBOL_TYPE_TABLE;
13181354
break;
13191355
default:
13201356
return make_error<GenericBinaryError>("unexpected export kind",
13211357
object_error::parse_failed);
13221358
}
13231359
Exports.push_back(Ex);
1360+
if (Ex.Kind != wasm::WASM_EXTERNAL_MEMORY) {
1361+
LinkingData.SymbolTable.emplace_back(Info);
1362+
Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType,
1363+
TableType, Signature);
1364+
LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
1365+
}
13241366
}
13251367
if (Ctx.Ptr != Ctx.End)
13261368
return make_error<GenericBinaryError>("export section ended prematurely",
@@ -1644,6 +1686,8 @@ uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
16441686
return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset;
16451687
} else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
16461688
return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset;
1689+
} else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_GLOBAL_GET) {
1690+
return Sym.Info.DataRef.Offset;
16471691
} else {
16481692
llvm_unreachable("unknown init expr opcode");
16491693
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# RUN: yaml2obj %s -o %t.so
2+
# RUN: llvm-nm %t.so | FileCheck %s
3+
#
4+
# CHECK: 00000001 T my_func_export
5+
# CHECK: 0000002a D my_global_export
6+
7+
--- !WASM
8+
FileHeader:
9+
Version: 0x1
10+
Sections:
11+
- Type: CUSTOM
12+
Name: dylink.0
13+
MemorySize: 15
14+
MemoryAlignment: 0
15+
TableSize: 0
16+
TableAlignment: 0
17+
Needed: []
18+
- Type: TYPE
19+
Signatures:
20+
- Index: 0
21+
ParamTypes: []
22+
ReturnTypes: []
23+
- Type: IMPORT
24+
Imports:
25+
- Module: env
26+
Field: foo
27+
Kind: FUNCTION
28+
SigIndex: 0
29+
- Module: env
30+
Field: bar
31+
Kind: GLOBAL
32+
GlobalType: I32
33+
GlobalMutable: true
34+
- Module: env
35+
Field: memory
36+
Kind: MEMORY
37+
Memory:
38+
Minimum: 0x1
39+
- Type: FUNCTION
40+
FunctionTypes: [ 0 ]
41+
- Type: GLOBAL
42+
Globals:
43+
- Index: 1
44+
Mutable: false
45+
Type: I32
46+
InitExpr:
47+
Opcode: I32_CONST
48+
Value: 42
49+
- Type: EXPORT
50+
Exports:
51+
- Name: my_func_export
52+
Kind: FUNCTION
53+
Index: 1
54+
- Name: my_global_export
55+
Kind: GLOBAL
56+
Index: 1
57+
- Type: CODE
58+
Functions:
59+
- Index: 1
60+
Locals:
61+
Body: 00
62+
- Type: DATA
63+
Segments:
64+
- SectionOffset: 0
65+
InitFlags: 0
66+
Offset:
67+
Opcode: I32_CONST
68+
Value: 0
69+
Content: ''
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# RUN: yaml2obj %s -o %t.so
2+
# RUN: llvm-objdump -t %t.so | FileCheck %s
3+
#
4+
# CHECK: SYMBOL TABLE:
5+
# CHECK-NEXT: 00000001 g F CODE my_func_export
6+
# CHECK-NEXT: 0000002a g O DATA my_global_export
7+
8+
--- !WASM
9+
FileHeader:
10+
Version: 0x1
11+
Sections:
12+
- Type: CUSTOM
13+
Name: dylink.0
14+
MemorySize: 15
15+
MemoryAlignment: 0
16+
TableSize: 0
17+
TableAlignment: 0
18+
Needed: []
19+
- Type: TYPE
20+
Signatures:
21+
- Index: 0
22+
ParamTypes: []
23+
ReturnTypes: []
24+
- Type: IMPORT
25+
Imports:
26+
- Module: env
27+
Field: foo
28+
Kind: FUNCTION
29+
SigIndex: 0
30+
- Module: env
31+
Field: bar
32+
Kind: GLOBAL
33+
GlobalType: I32
34+
GlobalMutable: true
35+
- Module: env
36+
Field: memory
37+
Kind: MEMORY
38+
Memory:
39+
Minimum: 0x1
40+
- Type: FUNCTION
41+
FunctionTypes: [ 0 ]
42+
- Type: GLOBAL
43+
Globals:
44+
- Index: 1
45+
Mutable: false
46+
Type: I32
47+
InitExpr:
48+
Opcode: I32_CONST
49+
Value: 42
50+
- Type: EXPORT
51+
Exports:
52+
- Name: my_func_export
53+
Kind: FUNCTION
54+
Index: 1
55+
- Name: my_global_export
56+
Kind: GLOBAL
57+
Index: 1
58+
- Type: CODE
59+
Functions:
60+
- Index: 1
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: ''

0 commit comments

Comments
 (0)