[WebAssembly] Don't allow functions to be named more than once
Even though a function can have multiple names in the
linking standards (i.e. due to aliases), there can only
be one name for a given function in the NAME section.
Differential Revision: https://reviews.llvm.org/D41975
llvm-svn: 322383
diff --git a/lld/test/wasm/alias.ll b/lld/test/wasm/alias.ll
new file mode 100644
index 0000000..888bcd2
--- /dev/null
+++ b/lld/test/wasm/alias.ll
@@ -0,0 +1,66 @@
+; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
+; RUN: lld -flavor wasm %t.o -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+@start_alias = alias i32 (), i32 ()* @_start
+
+; Function Attrs: nounwind uwtable
+define i32 @_start() local_unnamed_addr #1 {
+entry:
+ ret i32 0
+}
+
+; CHECK: --- !WASM
+; CHECK-NEXT: FileHeader:
+; CHECK-NEXT: Version: 0x00000001
+; CHECK-NEXT: Sections:
+; CHECK-NEXT: - Type: TYPE
+; CHECK-NEXT: Signatures:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Type: FUNCTION
+; CHECK-NEXT: FunctionTypes: [ 0 ]
+; CHECK-NEXT: - Type: TABLE
+; CHECK-NEXT: Tables:
+; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: Limits:
+; CHECK-NEXT: Flags: [ HAS_MAX ]
+; CHECK-NEXT: Initial: 0x00000001
+; CHECK-NEXT: Maximum: 0x00000001
+; CHECK-NEXT: - Type: MEMORY
+; CHECK-NEXT: Memories:
+; CHECK-NEXT: - Initial: 0x00000002
+; CHECK-NEXT: - Type: GLOBAL
+; CHECK-NEXT: Globals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: true
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66560
+; CHECK-NEXT: - Type: EXPORT
+; CHECK-NEXT: Exports:
+; CHECK-NEXT: - Name: memory
+; CHECK-NEXT: Kind: MEMORY
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: start_alias
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Type: CODE
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Locals:
+; CHECK-NEXT: Body: 41000B
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: linking
+; CHECK-NEXT: DataSize: 0
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: start_alias
+; CHECK-NEXT: ...
diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h
index 7b70c5c..0ddf5a9 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -110,7 +110,7 @@
public:
InputFunction(const WasmSignature &S, const WasmFunction &Func,
const ObjFile &F)
- : InputChunk(F), Signature(S), Function(Func) {}
+ : InputChunk(F), Signature(S), WrittenToNameSec(false), Function(Func) {}
uint32_t getSize() const override { return Function.Size; }
const uint8_t *getData() const override {
@@ -126,6 +126,8 @@
const WasmSignature &Signature;
+ unsigned WrittenToNameSec : 1;
+
protected:
uint32_t getInputSectionOffset() const override {
return Function.CodeSectionOffset;
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index 0e1391f..8376d22 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -74,7 +74,7 @@
}
void Symbol::update(Kind K, InputFile *F, uint32_t Flags_,
- const InputSegment *Seg, const InputFunction *Func,
+ const InputSegment *Seg, InputFunction *Func,
uint32_t Address) {
SymbolKind = K;
File = F;
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 083a8a2..af06d9a 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -93,11 +93,11 @@
void update(Kind K, InputFile *F = nullptr, uint32_t Flags = 0,
const InputSegment *Segment = nullptr,
- const InputFunction *Function = nullptr,
- uint32_t Address = UINT32_MAX);
+ InputFunction *Function = nullptr, uint32_t Address = UINT32_MAX);
void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; }
const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; }
+ InputFunction *getFunction() { return Function; }
// This bit is used by Writer::writeNameSection() to prevent
// symbols from being written to the symbol table more than once.
@@ -113,7 +113,7 @@
Kind SymbolKind = InvalidKind;
InputFile *File = nullptr;
const InputSegment *Segment = nullptr;
- const InputFunction *Function = nullptr;
+ InputFunction *Function = nullptr;
llvm::Optional<uint32_t> OutputIndex;
llvm::Optional<uint32_t> TableIndex;
const WasmSignature *FunctionType = nullptr;
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 23b63c9..0dc6be9 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -442,6 +442,15 @@
for (Symbol *S : File->getSymbols()) {
if (!S->isFunction() || S->isWeak() || S->WrittenToNameSec)
continue;
+ // We also need to guard against two different symbols (two different
+ // names) for the same wasm function. While this is possible (aliases)
+ // it is not legal in the "name" section.
+ InputFunction *Function = S->getFunction();
+ if (Function) {
+ if (Function->WrittenToNameSec)
+ continue;
+ Function->WrittenToNameSec = true;
+ }
S->WrittenToNameSec = true;
Names.emplace_back(S);
}