[lld] [WebAssembly] Allow absolute symbols in the linking section (symbol table) (PR #67493)
Sam Clegg via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 26 15:30:44 PDT 2023
https://github.com/sbc100 updated https://github.com/llvm/llvm-project/pull/67493
>From 1c4c9eff5122ec04a326dc43eb039e2320a2de4e Mon Sep 17 00:00:00 2001
From: Sam Clegg <sbc at chromium.org>
Date: Tue, 26 Sep 2023 14:37:15 -0700
Subject: [PATCH] [WebAssembly] Allow absolute symbols in the linking section
(symbol table)
Fixes a crash in `-Wl,-emit-relocs` where the linker was not able to
write linker-synthetic absolute symbols to the symbol table.
This change adds a new symbol flag (`WASM_SYMBOL_ABS`), which means that
the symbol's offset is absolute and not relative to a given segment.
Such symbols include `__stack_low` and `__stack_high`.
Note that wasm object files never contains such symbols, only binaries
linked with `-Wl,-emit-relocs`.
Fixes: #67111
---
lld/test/wasm/emit-relocs.s | 8 ++++++++
lld/wasm/SymbolTable.cpp | 6 ++++--
lld/wasm/SyntheticSections.cpp | 11 ++++++++---
llvm/include/llvm/BinaryFormat/Wasm.h | 1 +
llvm/lib/Object/WasmObjectFile.cpp | 22 +++++++++++++---------
llvm/lib/ObjectYAML/WasmYAML.cpp | 5 ++++-
6 files changed, 38 insertions(+), 15 deletions(-)
diff --git a/lld/test/wasm/emit-relocs.s b/lld/test/wasm/emit-relocs.s
index 28ce607167382e0..91de6116164f727 100644
--- a/lld/test/wasm/emit-relocs.s
+++ b/lld/test/wasm/emit-relocs.s
@@ -17,6 +17,8 @@ _start:
drop
i32.const foo
drop
+ i32.const __stack_low
+ drop
end_function
.section .bss.data,"",@
@@ -54,3 +56,9 @@ foo:
# CHECK-NEXT: Name: ret32
# CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
# CHECK-NEXT: Function: 1
+# CHECK-NEXT: - Index: 2
+# CHECK-NEXT: Kind: DATA
+# CHECK-NEXT: Name: __stack_low
+# CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN, ABSOLUTE ]
+# CHECK-NEXT: Offset: 1040
+# CHECK-NEXT: Size: 0
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index 9a381e95f3d9fa5..a00e336118d8c84 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -233,7 +233,8 @@ DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name,
else if (!s || s->isDefined())
return nullptr;
LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n");
- auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN);
+ auto *rtn = replaceSymbol<DefinedData>(
+ s, name, WASM_SYMBOL_VISIBILITY_HIDDEN | WASM_SYMBOL_ABSOLUTE);
rtn->setVA(value);
rtn->referenced = true;
return rtn;
@@ -243,7 +244,8 @@ DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name,
uint32_t flags) {
LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n");
assert(!find(name));
- return replaceSymbol<DefinedData>(insertName(name).first, name, flags);
+ return replaceSymbol<DefinedData>(insertName(name).first, name,
+ flags | WASM_SYMBOL_ABSOLUTE);
}
DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags,
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index ef9547593acdcd0..3a9c147161a2d38 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -665,9 +665,14 @@ void LinkingSection::writeBody() {
} else if (isa<DataSymbol>(sym)) {
writeStr(sub.os, sym->getName(), "sym name");
if (auto *dataSym = dyn_cast<DefinedData>(sym)) {
- writeUleb128(sub.os, dataSym->getOutputSegmentIndex(), "index");
- writeUleb128(sub.os, dataSym->getOutputSegmentOffset(),
- "data offset");
+ if (dataSym->segment) {
+ writeUleb128(sub.os, dataSym->getOutputSegmentIndex(), "index");
+ writeUleb128(sub.os, dataSym->getOutputSegmentOffset(),
+ "data offset");
+ } else {
+ writeUleb128(sub.os, 0, "index");
+ writeUleb128(sub.os, dataSym->getVA(), "data offset");
+ }
writeUleb128(sub.os, dataSym->getSize(), "data size");
}
} else {
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 749d43b840d5c2c..c7658cc7b7432b3 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -412,6 +412,7 @@ const unsigned WASM_SYMBOL_EXPORTED = 0x20;
const unsigned WASM_SYMBOL_EXPLICIT_NAME = 0x40;
const unsigned WASM_SYMBOL_NO_STRIP = 0x80;
const unsigned WASM_SYMBOL_TLS = 0x100;
+const unsigned WASM_SYMBOL_ABSOLUTE = 0x200;
#define WASM_RELOC(name, value) name = value,
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index e9471adf66eda5d..0982c7e2efbb956 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -723,17 +723,21 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
Info.Name = readString(Ctx);
if (IsDefined) {
auto Index = readVaruint32(Ctx);
- if (Index >= DataSegments.size())
- return make_error<GenericBinaryError>("invalid data segment index",
- object_error::parse_failed);
auto Offset = readVaruint64(Ctx);
auto Size = readVaruint64(Ctx);
- size_t SegmentSize = DataSegments[Index].Data.Content.size();
- if (Offset > SegmentSize)
- return make_error<GenericBinaryError>(
- "invalid data symbol offset: `" + Info.Name + "` (offset: " +
- Twine(Offset) + " segment size: " + Twine(SegmentSize) + ")",
- object_error::parse_failed);
+ if (!(Info.Flags & wasm::WASM_SYMBOL_ABSOLUTE)) {
+ if (static_cast<size_t>(Index) >= DataSegments.size())
+ return make_error<GenericBinaryError>(
+ "invalid data segment index: " + Twine(Index),
+ object_error::parse_failed);
+ size_t SegmentSize = DataSegments[Index].Data.Content.size();
+ if (Offset > SegmentSize)
+ return make_error<GenericBinaryError>(
+ "invalid data symbol offset: `" + Info.Name +
+ "` (offset: " + Twine(Offset) +
+ " segment size: " + Twine(SegmentSize) + ")",
+ object_error::parse_failed);
+ }
Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
}
break;
diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp
index ef47766a2394207..9502fe5e4077881 100644
--- a/llvm/lib/ObjectYAML/WasmYAML.cpp
+++ b/llvm/lib/ObjectYAML/WasmYAML.cpp
@@ -518,7 +518,9 @@ void MappingTraits<WasmYAML::SymbolInfo>::mapping(IO &IO,
IO.mapRequired("Tag", Info.ElementIndex);
} else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA) {
if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
- IO.mapRequired("Segment", Info.DataRef.Segment);
+ if ((Info.Flags & wasm::WASM_SYMBOL_ABSOLUTE) == 0) {
+ IO.mapRequired("Segment", Info.DataRef.Segment);
+ }
IO.mapOptional("Offset", Info.DataRef.Offset, 0u);
IO.mapRequired("Size", Info.DataRef.Size);
}
@@ -573,6 +575,7 @@ void ScalarBitSetTraits<WasmYAML::SymbolFlags>::bitset(
BCaseMask(EXPLICIT_NAME, EXPLICIT_NAME);
BCaseMask(NO_STRIP, NO_STRIP);
BCaseMask(TLS, TLS);
+ BCaseMask(ABSOLUTE, ABSOLUTE);
#undef BCaseMask
}
More information about the llvm-commits
mailing list