[WebAssembly] Create synthetic __wasm_call_ctors function

This change create a new synthetic function in the final
output binary which calls the static constructors in sequence.

See: https://github.com/WebAssembly/tool-conventions/issues/25

Differential Revision: https://reviews.llvm.org/D41893

llvm-svn: 322388
This commit is contained in:
Sam Clegg 2018-01-12 18:35:13 +00:00
parent 3d139c527b
commit 5068685678
20 changed files with 343 additions and 87 deletions

View File

@ -9,6 +9,14 @@ entry:
ret void
}
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @myctor, i8* null }]
@llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [
{ i32, void ()*, i8* } { i32 2002, void ()* @myctor, i8* null },
{ i32, void ()*, i8* } { i32 101, void ()* @myctor, i8* null },
{ i32, void ()*, i8* } { i32 202, void ()* @myctor, i8* null }
]
@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @mydtor, i8* null }]
@llvm.global_dtors = appending global [3 x { i32, void ()*, i8* }] [
{ i32, void ()*, i8* } { i32 2002, void ()* @mydtor, i8* null },
{ i32, void ()*, i8* } { i32 101, void ()* @mydtor, i8* null },
{ i32, void ()*, i8* } { i32 202, void ()* @mydtor, i8* null }
]

View File

@ -19,8 +19,11 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0 ]
; CHECK-NEXT: FunctionTypes: [ 0, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@ -55,6 +58,9 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41000B
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: DataSize: 0
@ -63,4 +69,6 @@ entry:
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: start_alias
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: ...

View File

@ -52,7 +52,7 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - I64
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 2 ]
; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 2, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@ -114,6 +114,9 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 42012000118380808000001A0B
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 7

View File

@ -22,7 +22,7 @@ declare i32 @ret32(float) local_unnamed_addr #1
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - F32
; CHECK: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 1 ]
; CHECK-NEXT: FunctionTypes: [ 0, 1, 0 ]
; CHECK: - Type: CODE
; CHECK-NEXT: Functions:
; CHECK-NEXT: - Index: 0
@ -31,6 +31,9 @@ declare i32 @ret32(float) local_unnamed_addr #1
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41000B
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: DataSize: 0
@ -41,4 +44,6 @@ declare i32 @ret32(float) local_unnamed_addr #1
; CHECK-NEXT: Name: _start
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: ret32
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: ...

View File

@ -23,15 +23,18 @@ declare i32 @ret32(float) local_unnamed_addr #1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 1 ]
; CHECK-NEXT: FunctionTypes: [ 0, 1, 1 ]
; CHECK: - Type: CODE
; CHECK-NEXT: Functions:
; CHECK: - Index: 0
; CHECK: - Index: 1
; CHECK: - Index: 2
; CHECK: Name: name
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: ret32
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: _start
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: ...

View File

@ -11,6 +11,16 @@ entry:
ret void
}
define hidden void @func3() {
entry:
ret void
}
define hidden void @func4() {
entry:
ret void
}
define void @__cxa_atexit() {
ret void
}
@ -20,14 +30,31 @@ entry:
ret void
}
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func1, i8* null }]
@llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [
{ i32, void ()*, i8* } { i32 1001, void ()* @func1, i8* null },
{ i32, void ()*, i8* } { i32 101, void ()* @func1, i8* null },
{ i32, void ()*, i8* } { i32 101, void ()* @func2, i8* null }
]
@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func2, i8* null }]
@llvm.global_dtors = appending global [3 x { i32, void ()*, i8* }] [
{ i32, void ()*, i8* } { i32 1001, void ()* @func3, i8* null },
{ i32, void ()*, i8* } { i32 101, void ()* @func3, i8* null },
{ i32, void ()*, i8* } { i32 101, void ()* @func4, i8* null }
]
; RUN: lld -flavor wasm %t.o %t.global-ctor-dtor.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; CHECK: Name: linking
; CHECK: - Type: ELEM
; CHECK-NEXT: Segments:
; CHECK-NEXT: - Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1
; CHECK-NEXT: Functions: [ 6, 9, 13, 15, 17 ]
; CHECK: Body: 100010011007100B100E100B10101000100A100B10120B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: DataSize: 0
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
@ -37,23 +64,41 @@ entry:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: func2
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: __cxa_atexit
; CHECK-NEXT: Name: func3
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Name: _start
; CHECK-NEXT: Name: func4
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Name: .Lcall_dtors
; CHECK-NEXT: Name: __cxa_atexit
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Name: .Lregister_call_dtors
; CHECK-NEXT: Name: _start
; CHECK-NEXT: - Index: 6
; CHECK-NEXT: Name: .Lbitcast
; CHECK-NEXT: Name: .Lcall_dtors.101
; CHECK-NEXT: - Index: 7
; CHECK-NEXT: Name: myctor
; CHECK-NEXT: Name: .Lregister_call_dtors.101
; CHECK-NEXT: - Index: 8
; CHECK-NEXT: Name: mydtor
; CHECK-NEXT: Name: .Lbitcast
; CHECK-NEXT: - Index: 9
; CHECK-NEXT: Name: .Lcall_dtors
; CHECK-NEXT: Name: .Lcall_dtors.1001
; CHECK-NEXT: - Index: 10
; CHECK-NEXT: Name: .Lregister_call_dtors
; CHECK-NEXT: Name: .Lregister_call_dtors.1001
; CHECK-NEXT: - Index: 11
; CHECK-NEXT: Name: myctor
; CHECK-NEXT: - Index: 12
; CHECK-NEXT: Name: mydtor
; CHECK-NEXT: - Index: 13
; CHECK-NEXT: Name: .Lcall_dtors.101
; CHECK-NEXT: - Index: 14
; CHECK-NEXT: Name: .Lregister_call_dtors.101
; CHECK-NEXT: - Index: 15
; CHECK-NEXT: Name: .Lcall_dtors.202
; CHECK-NEXT: - Index: 16
; CHECK-NEXT: Name: .Lregister_call_dtors.202
; CHECK-NEXT: - Index: 17
; CHECK-NEXT: Name: .Lcall_dtors.2002
; CHECK-NEXT: - Index: 18
; CHECK-NEXT: Name: .Lregister_call_dtors.2002
; CHECK-NEXT: - Index: 19
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: ...
@ -63,14 +108,28 @@ entry:
; RELOC: Name: linking
; RELOC-NEXT: DataSize: 0
; RELOC-NEXT: InitFunctions:
; RELOC-NEXT: - Priority: 65535
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 0
; RELOC-NEXT: - Priority: 65535
; RELOC-NEXT: FunctionIndex: 5
; RELOC-NEXT: - Priority: 65535
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 1
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 7
; RELOC-NEXT: - Priority: 65535
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 11
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 14
; RELOC-NEXT: - Priority: 202
; RELOC-NEXT: FunctionIndex: 11
; RELOC-NEXT: - Priority: 202
; RELOC-NEXT: FunctionIndex: 16
; RELOC-NEXT: - Priority: 1001
; RELOC-NEXT: FunctionIndex: 0
; RELOC-NEXT: - Priority: 1001
; RELOC-NEXT: FunctionIndex: 10
; RELOC-NEXT: - Priority: 2002
; RELOC-NEXT: FunctionIndex: 11
; RELOC-NEXT: - Priority: 2002
; RELOC-NEXT: FunctionIndex: 18
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: name
; RELOC-NEXT: FunctionNames:
@ -79,21 +138,37 @@ entry:
; RELOC-NEXT: - Index: 1
; RELOC-NEXT: Name: func2
; RELOC-NEXT: - Index: 2
; RELOC-NEXT: Name: __cxa_atexit
; RELOC-NEXT: Name: func3
; RELOC-NEXT: - Index: 3
; RELOC-NEXT: Name: _start
; RELOC-NEXT: Name: func4
; RELOC-NEXT: - Index: 4
; RELOC-NEXT: Name: .Lcall_dtors
; RELOC-NEXT: Name: __cxa_atexit
; RELOC-NEXT: - Index: 5
; RELOC-NEXT: Name: .Lregister_call_dtors
; RELOC-NEXT: Name: _start
; RELOC-NEXT: - Index: 6
; RELOC-NEXT: Name: .Lbitcast
; RELOC-NEXT: Name: .Lcall_dtors.101
; RELOC-NEXT: - Index: 7
; RELOC-NEXT: Name: myctor
; RELOC-NEXT: Name: .Lregister_call_dtors.101
; RELOC-NEXT: - Index: 8
; RELOC-NEXT: Name: mydtor
; RELOC-NEXT: Name: .Lbitcast
; RELOC-NEXT: - Index: 9
; RELOC-NEXT: Name: .Lcall_dtors
; RELOC-NEXT: Name: .Lcall_dtors.1001
; RELOC-NEXT: - Index: 10
; RELOC-NEXT: Name: .Lregister_call_dtors
; RELOC-NEXT: Name: .Lregister_call_dtors.1001
; RELOC-NEXT: - Index: 11
; RELOC-NEXT: Name: myctor
; RELOC-NEXT: - Index: 12
; RELOC-NEXT: Name: mydtor
; RELOC-NEXT: - Index: 13
; RELOC-NEXT: Name: .Lcall_dtors.101
; RELOC-NEXT: - Index: 14
; RELOC-NEXT: Name: .Lregister_call_dtors.101
; RELOC-NEXT: - Index: 15
; RELOC-NEXT: Name: .Lcall_dtors.202
; RELOC-NEXT: - Index: 16
; RELOC-NEXT: Name: .Lregister_call_dtors.202
; RELOC-NEXT: - Index: 17
; RELOC-NEXT: Name: .Lcall_dtors.2002
; RELOC-NEXT: - Index: 18
; RELOC-NEXT: Name: .Lregister_call_dtors.2002
; RELOC-NEXT: ...

View File

@ -24,8 +24,11 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 0 ]
; CHECK-NEXT: FunctionTypes: [ 0, 0, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@ -60,6 +63,9 @@ entry:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 41010B
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 7
@ -78,4 +84,6 @@ entry:
; CHECK-NEXT: Name: baz
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: _start
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: ...

View File

@ -18,8 +18,11 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0 ]
; CHECK-NEXT: FunctionTypes: [ 0, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@ -46,6 +49,9 @@ entry:
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: __wasm_call_ctors
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
@ -55,6 +61,9 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 23808080800041106B1A41000B
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: DataSize: 0
@ -63,4 +72,6 @@ entry:
; CHECK-NEXT: FunctionNames:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: _start
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: ...

View File

@ -30,7 +30,7 @@ entry:
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 0, 0, 0 ]
; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 0, 0, 0, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@ -108,6 +108,9 @@ entry:
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Count: 2
; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081082808080002101200041106A24808080800020010B
; CHECK-NEXT: - Index: 7
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: DataSize: 0
@ -128,4 +131,6 @@ entry:
; CHECK-NEXT: Name: call_alias_ptr
; CHECK-NEXT: - Index: 6
; CHECK-NEXT: Name: call_direct_ptr
; CHECK-NEXT: - Index: 7
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: ...

View File

@ -23,8 +23,11 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0 ]
; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@ -99,6 +102,9 @@ entry:
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Count: 2
; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081081808080002101200041106A24808080800020010B
; CHECK-NEXT: - Index: 6
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: DataSize: 0
@ -117,4 +123,6 @@ entry:
; CHECK-NEXT: Name: call_alias_ptr
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Name: call_direct_ptr
; CHECK-NEXT: - Index: 6
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: ...

View File

@ -23,8 +23,11 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ]
; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@ -83,6 +86,9 @@ entry:
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4181808080000B
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 7
@ -103,4 +109,6 @@ entry:
; CHECK-NEXT: Name: exportWeak1
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Name: exportWeak2
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: ...

View File

@ -33,8 +33,11 @@ entry:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: NORESULT
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 0, 0 ]
; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
; CHECK-NEXT: - ElemType: ANYFUNC
@ -78,6 +81,9 @@ entry:
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4100280280808080000B
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 0B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: DataSize: 0

View File

@ -40,6 +40,7 @@ struct Configuration {
llvm::StringSet<> AllowUndefinedSymbols;
std::vector<llvm::StringRef> SearchPaths;
Symbol *StackPointerSymbol = nullptr;
Symbol *CtorSymbol = nullptr;
};
// The only instance of Configuration struct.

View File

@ -291,15 +291,16 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
error("undefined symbols specified for relocatable output file");
if (!Config->Relocatable) {
if (!Config->Entry.empty()) {
static WasmSignature Signature = {{}, WASM_TYPE_NORESULT};
static WasmSignature Signature = {{}, WASM_TYPE_NORESULT};
if (!Config->Entry.empty())
addSyntheticUndefinedFunction(Config->Entry, &Signature);
}
// Handle the `--undefined <sym>` options.
for (StringRef S : args::getStrings(Args, OPT_undefined))
addSyntheticUndefinedFunction(S, nullptr);
Config->CtorSymbol = Symtab->addDefinedFunction(
"__wasm_call_ctors", &Signature, WASM_SYMBOL_VISIBILITY_HIDDEN);
Config->StackPointerSymbol = Symtab->addDefinedGlobal("__stack_pointer");
}

View File

@ -30,6 +30,8 @@ uint32_t InputSegment::translateVA(uint32_t Address) const {
}
void InputChunk::copyRelocations(const WasmSection &Section) {
if (Section.Relocations.empty())
return;
size_t Start = getInputSectionOffset();
size_t Size = getSize();
for (const WasmRelocation &R : Section.Relocations)
@ -92,8 +94,10 @@ void InputChunk::writeTo(uint8_t *SectionStart) const {
// output section. Calculates the updated index and offset for each relocation
// as well as the value to write out in the final binary.
void InputChunk::calcRelocations() {
if (Relocations.empty())
return;
int32_t Off = getOutputOffset() - getInputSectionOffset();
DEBUG(dbgs() << "calcRelocations: " << File.getName()
DEBUG(dbgs() << "calcRelocations: " << File->getName()
<< " offset=" << Twine(Off) << "\n");
for (const WasmRelocation &Reloc : Relocations) {
OutputRelocation NewReloc;
@ -105,19 +109,25 @@ void InputChunk::calcRelocations() {
<< " newOffset=" << NewReloc.Reloc.Offset << "\n");
if (Config->EmitRelocs)
NewReloc.NewIndex = File.calcNewIndex(Reloc);
NewReloc.NewIndex = File->calcNewIndex(Reloc);
switch (Reloc.Type) {
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
NewReloc.Value = File.getRelocatedAddress(Reloc.Index) + Reloc.Addend;
NewReloc.Value = File->getRelocatedAddress(Reloc.Index) + Reloc.Addend;
break;
default:
NewReloc.Value = File.calcNewIndex(Reloc);
NewReloc.Value = File->calcNewIndex(Reloc);
break;
}
OutRelocations.emplace_back(NewReloc);
}
}
void InputFunction::setOutputIndex(uint32_t Index) {
DEBUG(dbgs() << "InputFunction::setOutputIndex: " << Index << "\n");
assert(!hasOutputIndex());
OutputIndex = Index;
};

View File

@ -50,7 +50,7 @@ public:
std::vector<OutputRelocation> OutRelocations;
protected:
InputChunk(const ObjFile &F) : File(F) {}
InputChunk(const ObjFile *F) : File(F) {}
virtual ~InputChunk() = default;
void calcRelocations();
virtual const uint8_t *getData() const = 0;
@ -58,7 +58,7 @@ protected:
std::vector<WasmRelocation> Relocations;
int32_t OutputOffset = 0;
const ObjFile &File;
const ObjFile *File;
};
// Represents a WebAssembly data segment which can be included as part of
@ -71,7 +71,7 @@ protected:
// each global variable.
class InputSegment : public InputChunk {
public:
InputSegment(const WasmSegment &Seg, const ObjFile &F)
InputSegment(const WasmSegment &Seg, const ObjFile *F)
: InputChunk(F), Segment(Seg) {}
// Translate an offset in the input segment to an offset in the output
@ -108,21 +108,18 @@ protected:
// combined to create the final output CODE section.
class InputFunction : public InputChunk {
public:
InputFunction(const WasmSignature &S, const WasmFunction &Func,
const ObjFile &F)
InputFunction(const WasmSignature &S, const WasmFunction *Func,
const ObjFile *F)
: InputChunk(F), Signature(S), WrittenToNameSec(false), Function(Func) {}
uint32_t getSize() const override { return Function.Size; }
uint32_t getSize() const override { return Function->Size; }
const uint8_t *getData() const override {
return File.CodeSection->Content.data() + getInputSectionOffset();
return File->CodeSection->Content.data() + getInputSectionOffset();
}
uint32_t getOutputIndex() const { return OutputIndex.getValue(); };
bool hasOutputIndex() const { return OutputIndex.hasValue(); };
void setOutputIndex(uint32_t Index) {
assert(!hasOutputIndex());
OutputIndex = Index;
};
void setOutputIndex(uint32_t Index);
const WasmSignature &Signature;
@ -130,12 +127,26 @@ public:
protected:
uint32_t getInputSectionOffset() const override {
return Function.CodeSectionOffset;
return Function->CodeSectionOffset;
}
const WasmFunction &Function;
const WasmFunction *Function;
llvm::Optional<uint32_t> OutputIndex;
};
class SyntheticFunction : public InputFunction {
public:
SyntheticFunction(const WasmSignature &S, StringRef Body)
: InputFunction(S, nullptr, nullptr), Body(Body) {}
uint32_t getSize() const override { return Body.size(); }
const uint8_t *getData() const override {
return reinterpret_cast<const uint8_t *>(Body.data());
}
protected:
StringRef Body;
};
} // namespace wasm
} // namespace lld

View File

@ -188,7 +188,7 @@ void ObjFile::initializeSymbols() {
GlobalSymbols.resize(NumGlobalImports + WasmObj->globals().size());
for (const WasmSegment &S : WasmObj->dataSegments()) {
InputSegment *Seg = make<InputSegment>(S, *this);
InputSegment *Seg = make<InputSegment>(S, this);
Seg->copyRelocations(*DataSection);
Segments.emplace_back(Seg);
}
@ -199,7 +199,7 @@ void ObjFile::initializeSymbols() {
for (size_t I = 0; I < Funcs.size(); ++I) {
const WasmFunction &Func = Funcs[I];
const WasmSignature &Sig = Types[FuncTypes[I]];
InputFunction *F = make<InputFunction>(Sig, Func, *this);
InputFunction *F = make<InputFunction>(Sig, &Func, this);
F->copyRelocations(*CodeSection);
Functions.emplace_back(F);
}
@ -232,14 +232,10 @@ void ObjFile::initializeSymbols() {
Symbols.push_back(S);
if (WasmSym.isFunction()) {
DEBUG(dbgs() << "Function: " << WasmSym.ElementIndex << " -> "
<< toString(*S) << "\n");
FunctionSymbols[WasmSym.ElementIndex] = S;
if (WasmSym.HasAltIndex)
FunctionSymbols[WasmSym.AltIndex] = S;
} else {
DEBUG(dbgs() << "Global: " << WasmSym.ElementIndex << " -> "
<< toString(*S) << "\n");
GlobalSymbols[WasmSym.ElementIndex] = S;
if (WasmSym.HasAltIndex)
GlobalSymbols[WasmSym.AltIndex] = S;

View File

@ -119,6 +119,22 @@ static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
" in " + F.getName());
}
Symbol *SymbolTable::addDefinedFunction(StringRef Name,
const WasmSignature *Type,
uint32_t Flags) {
DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
S->update(Symbol::DefinedFunctionKind, nullptr, Flags);
S->setFunctionType(Type);
} else if (!S->isFunction()) {
error("symbol type mismatch: " + Name);
}
return S;
}
Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n");
Symbol *S;

View File

@ -55,6 +55,8 @@ public:
InputFile *F, const WasmSignature *Signature = nullptr);
Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type);
Symbol *addDefinedGlobal(StringRef Name);
Symbol *addDefinedFunction(StringRef Name, const WasmSignature *Type,
uint32_t Flags);
void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);
private:

View File

@ -9,6 +9,7 @@
#include "Writer.h"
#include "llvm/ADT/DenseSet.h"
#include "Config.h"
#include "InputChunks.h"
#include "OutputSections.h"
@ -70,6 +71,8 @@ private:
uint32_t lookupType(const WasmSignature &Sig);
uint32_t registerType(const WasmSignature &Sig);
void createCtorFunction();
void calculateInitFunctions();
void assignIndexes();
void calculateImports();
void calculateOffsets();
@ -114,12 +117,15 @@ private:
std::vector<const Symbol *> DefinedGlobals;
std::vector<InputFunction *> DefinedFunctions;
std::vector<const Symbol *> IndirectFunctions;
std::vector<WasmInitFunc> InitFunctions;
// Elements that are used to construct the final output
std::string Header;
std::vector<OutputSection *> OutputSections;
std::unique_ptr<FileOutputBuffer> Buffer;
std::unique_ptr<SyntheticFunction> CtorFunction;
std::string CtorFunctionBody;
std::vector<OutputSegment *> Segments;
llvm::SmallDenseMap<StringRef, OutputSegment *> SegmentMap;
@ -410,15 +416,6 @@ void Writer::createLinkingSection() {
SubSection.writeToStream(OS);
}
std::vector<WasmInitFunc> InitFunctions;
for (ObjFile *File : Symtab->ObjectFiles) {
const WasmLinkingData &L = File->getWasmObj()->linkingData();
InitFunctions.reserve(InitFunctions.size() + L.InitFunctions.size());
for (const WasmInitFunc &F : L.InitFunctions)
InitFunctions.emplace_back(WasmInitFunc{
F.Priority, File->relocateFunctionIndex(F.FunctionIndex)});
}
if (!InitFunctions.empty()) {
SubSection SubSection(WASM_INIT_FUNCS);
writeUleb128(SubSection.getStream(), InitFunctions.size(),
@ -437,25 +434,40 @@ void Writer::createNameSection() {
// Create an array of all function sorted by function index space
std::vector<const Symbol *> Names;
auto AddToNames = [&](Symbol* S) {
if (!S->isFunction() || S->WrittenToNameSec)
return;
// 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)
return;
Function->WrittenToNameSec = true;
}
S->WrittenToNameSec = true;
Names.emplace_back(S);
};
for (ObjFile *File : Symtab->ObjectFiles) {
Names.reserve(Names.size() + File->getSymbols().size());
DEBUG(dbgs() << "adding names from: " << File->getName() << "\n");
for (Symbol *S : File->getSymbols()) {
if (!S->isFunction() || S->isWeak() || S->WrittenToNameSec)
if (S->isWeak())
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);
AddToNames(S);
}
}
DEBUG(dbgs() << "adding symtab names\n");
for (Symbol *S : Symtab->getSymbols()) {
DEBUG(dbgs() << "sym: " << S->getName() << "\n");
if (S->getFile())
continue;
AddToNames(S);
}
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name");
std::sort(Names.begin(), Names.end(), [](const Symbol *A, const Symbol *B) {
@ -603,11 +615,15 @@ void Writer::calculateTypes() {
for (const WasmSignature &Sig : File->getWasmObj()->types())
File->TypeMap.push_back(registerType(Sig));
}
for (Symbol *Sym : Symtab->getSymbols())
if (Sym->isFunction())
registerType(Sym->getFunctionType());
}
void Writer::assignIndexes() {
uint32_t GlobalIndex = ImportedGlobals.size();
uint32_t FunctionIndex = ImportedFunctions.size();
uint32_t GlobalIndex = ImportedGlobals.size() + DefinedGlobals.size();
uint32_t FunctionIndex = ImportedFunctions.size() + DefinedFunctions.size();
if (Config->StackPointerSymbol) {
DefinedGlobals.emplace_back(Config->StackPointerSymbol);
@ -686,6 +702,57 @@ void Writer::createOutputSegments() {
}
}
static const int OPCODE_CALL = 0x10;
static const int OPCODE_END = 0xb;
// Create synthetic "__wasm_call_ctors" function based on ctor functions
// in input object.
void Writer::createCtorFunction() {
uint32_t FunctionIndex = ImportedFunctions.size() + DefinedFunctions.size();
Config->CtorSymbol->setOutputIndex(FunctionIndex);
// First write the body bytes to a string.
std::string FunctionBody;
static WasmSignature Signature = {{}, WASM_TYPE_NORESULT};
{
raw_string_ostream OS(FunctionBody);
writeUleb128(OS, 0, "num locals");
for (const WasmInitFunc &F : InitFunctions) {
writeU8(OS, OPCODE_CALL, "CALL");
writeUleb128(OS, F.FunctionIndex, "function index");
}
writeU8(OS, OPCODE_END, "END");
}
// Once we know the size of the body we can create the final function body
raw_string_ostream OS(CtorFunctionBody);
writeUleb128(OS, FunctionBody.size(), "function size");
OS.flush();
CtorFunctionBody += FunctionBody;
CtorFunction =
llvm::make_unique<SyntheticFunction>(Signature, CtorFunctionBody);
DefinedFunctions.emplace_back(CtorFunction.get());
}
// Populate InitFunctions vector with init functions from all input objects.
// This is then used either when creating the output linking section or to
// synthesize the "__wasm_call_ctors" function.
void Writer::calculateInitFunctions() {
for (ObjFile *File : Symtab->ObjectFiles) {
const WasmLinkingData &L = File->getWasmObj()->linkingData();
InitFunctions.reserve(InitFunctions.size() + L.InitFunctions.size());
for (const WasmInitFunc &F : L.InitFunctions)
InitFunctions.emplace_back(WasmInitFunc{
F.Priority, File->relocateFunctionIndex(F.FunctionIndex)});
}
// Sort in order of priority (lowest first) so that they are called
// in the correct order.
std::sort(InitFunctions.begin(), InitFunctions.end(),
[](const WasmInitFunc &L, const WasmInitFunc &R) {
return L.Priority < R.Priority;
});
}
void Writer::run() {
if (!Config->Relocatable)
InitialTableOffset = 1;
@ -696,6 +763,10 @@ void Writer::run() {
calculateImports();
log("-- assignIndexes");
assignIndexes();
log("-- calculateInitFunctions");
calculateInitFunctions();
if (!Config->Relocatable)
createCtorFunction();
if (errorHandler().Verbose) {
log("Defined Functions: " + Twine(DefinedFunctions.size()));