[WebAssembly] Add explicit symbol table

This change modified lld to in response the llvm change which
moved to a more explicit symbol table in the object format.

Based on patches by Nicholas Wilson:
 1. https://reviews.llvm.org/D41955
 2. https://reviews.llvm.org/D42585

The primary difference that we see in the test output is that
for relocatable (-r) output we now have symbol table which
replaces exports/imports and globals.

See: https://github.com/WebAssembly/tool-conventions/issues/38
Differential Revision: https://reviews.llvm.org/D43264

llvm-svn: 325861
This commit is contained in:
Sam Clegg 2018-02-23 05:08:53 +00:00
parent 6c899ba6de
commit 9310297438
26 changed files with 1899 additions and 855 deletions

View File

@ -58,10 +58,10 @@ entry:
; CHECK-NEXT: - Name: memory
; CHECK-NEXT: Kind: MEMORY
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: start_alias
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: - Name: start_alias
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: __heap_base

View File

@ -9,7 +9,7 @@
; CHECK-UNDEFINED: undefined symbol: missing_func
; RUN: echo 'missing_func' > %t.imports
; RUN: wasm-ld --check-signatures %t.a %t.o -o %t.wasm
; RUN: wasm-ld --check-signatures -r %t.a %t.o -o %t.wasm
; RUN: llvm-nm -a %t.wasm | FileCheck %s
@ -25,12 +25,16 @@ entry:
ret void
}
; Verify that multually dependant object files in an archive is handled
; correctly.
; Verify that mutually dependant object files in an archive is handled
; correctly. Since we're using llvm-nm, we must link with --relocatable.
;
; TODO(ncw): Update LLD so that the symbol table is written out for
; non-relocatable output (with an option to strip it)
; CHECK: 00000003 T _start
; CHECK-NEXT: 00000001 T bar
; CHECK-NEXT: 00000002 T foo
; CHECK-NEXT: U missing_func
; Verify that symbols from unused objects don't appear in the symbol table
; CHECK-NOT: hello

View File

@ -46,25 +46,10 @@ target triple = "wasm32-unknown-unknown-wasm"
; RUN: wasm-ld --check-signatures --relocatable -o %t_reloc.wasm %t.o %t.hello.o
; RUN: obj2yaml %t_reloc.wasm | FileCheck %s -check-prefix=RELOC
; RELOC: - Type: GLOBAL
; RELOC-NEXT: Globals:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Type: I32
; RELOC-NEXT: Mutable: false
; RELOC-NEXT: InitExpr:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 0
; RELOC-NEXT: - Index: 1
; RELOC-NEXT: Type: I32
; RELOC-NEXT: Mutable: false
; RELOC-NEXT: InitExpr:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 16
; RELOC: - Type: DATA
; RELOC-NEXT: Relocations:
; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
; RELOC-NEXT: Index: 3
; RELOC-NEXT: Index: 5
; RELOC-NEXT: Offset: 0x00000018
; RELOC-NEXT: Segments:
; RELOC-NEXT: - SectionOffset: 6
@ -92,6 +77,31 @@ target triple = "wasm32-unknown-unknown-wasm"
; RELOC-NEXT: Value: 28
; RELOC-NEXT: Content: 68656C6C6F0A00
; RELOC: - Type: CUSTOM
; RELOC: - Type: CUSTOM
; RELOC-NEXT: Name: linking
; RELOC-NEXT: DataSize: 35
; RELOC-NEXT: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: foo
; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; RELOC-NEXT: Segment: 0
; RELOC-NEXT: Size: 4
; RELOC-NEXT: - Index: 1
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: aligned_bar
; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; RELOC-NEXT: Segment: 1
; RELOC-NEXT: Size: 4
; RELOC-NEXT: - Index: 2
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: external_ref
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Segment: 2
; RELOC-NEXT: Size: 4
; RELOC: - Index: 5
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: hello_str
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Segment: 3
; RELOC-NEXT: Size: 7

View File

@ -107,66 +107,129 @@ entry:
; RELOC: Name: linking
; RELOC-NEXT: DataSize: 0
; RELOC-NEXT: SymbolInfo:
; RELOC-NEXT: - Name: __dso_handle
; RELOC-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN ]
; RELOC-NEXT: - Name: func1
; RELOC-NEXT: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: __dso_handle
; RELOC-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN, UNDEFINED ]
; RELOC-NEXT: - Index: 1
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: func1
; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; RELOC-NEXT: - Name: func2
; RELOC-NEXT: Function: 0
; RELOC-NEXT: - Index: 2
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: func2
; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; RELOC-NEXT: - Name: func3
; RELOC-NEXT: Function: 1
; RELOC-NEXT: - Index: 3
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: func3
; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; RELOC-NEXT: - Name: func4
; RELOC-NEXT: Function: 2
; RELOC-NEXT: - Index: 4
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: func4
; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; RELOC-NEXT: - Name: _start
; RELOC-NEXT: Function: 3
; RELOC-NEXT: - Index: 5
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: __cxa_atexit
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 4
; RELOC-NEXT: - Index: 6
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: _start
; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; RELOC-NEXT: - Name: .Lcall_dtors.101
; RELOC-NEXT: Function: 5
; RELOC-NEXT: - Index: 7
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lcall_dtors.101
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: .Lregister_call_dtors.101
; RELOC-NEXT: Function: 6
; RELOC-NEXT: - Index: 8
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lregister_call_dtors.101
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: .Lcall_dtors.1001
; RELOC-NEXT: Function: 7
; RELOC-NEXT: - Index: 9
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lcall_dtors.1001
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: .Lregister_call_dtors.1001
; RELOC-NEXT: Function: 8
; RELOC-NEXT: - Index: 10
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lregister_call_dtors.1001
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: myctor
; RELOC-NEXT: Function: 9
; RELOC-NEXT: - Index: 11
; RELOC-NEXT: Kind: GLOBAL
; RELOC-NEXT: Name: __stack_pointer
; RELOC-NEXT: Flags: [ UNDEFINED ]
; RELOC-NEXT: Global: 0
; RELOC-NEXT: - Index: 12
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: myctor
; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; RELOC-NEXT: - Name: mydtor
; RELOC-NEXT: Function: 10
; RELOC-NEXT: - Index: 13
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: mydtor
; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; RELOC-NEXT: - Name: .Lcall_dtors.101.1
; RELOC-NEXT: Function: 11
; RELOC-NEXT: - Index: 14
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lcall_dtors.101
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: .Lregister_call_dtors.101.1
; RELOC-NEXT: Function: 12
; RELOC-NEXT: - Index: 15
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lregister_call_dtors.101
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: .Lcall_dtors.202
; RELOC-NEXT: Function: 13
; RELOC-NEXT: - Index: 16
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lcall_dtors.202
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: .Lregister_call_dtors.202
; RELOC-NEXT: Function: 14
; RELOC-NEXT: - Index: 17
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lregister_call_dtors.202
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: .Lcall_dtors.2002
; RELOC-NEXT: Function: 15
; RELOC-NEXT: - Index: 18
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lcall_dtors.2002
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: .Lregister_call_dtors.2002
; RELOC-NEXT: Function: 16
; RELOC-NEXT: - Index: 19
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: .Lregister_call_dtors.2002
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: Function: 17
; RELOC-NEXT: InitFunctions:
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 0
; RELOC-NEXT: Symbol: 1
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 1
; RELOC-NEXT: Symbol: 2
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 7
; RELOC-NEXT: Symbol: 8
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 10
; RELOC-NEXT: Symbol: 12
; RELOC-NEXT: - Priority: 101
; RELOC-NEXT: FunctionIndex: 13
; RELOC-NEXT: Symbol: 15
; RELOC-NEXT: - Priority: 202
; RELOC-NEXT: FunctionIndex: 10
; RELOC-NEXT: Symbol: 12
; RELOC-NEXT: - Priority: 202
; RELOC-NEXT: FunctionIndex: 15
; RELOC-NEXT: Symbol: 17
; RELOC-NEXT: - Priority: 1001
; RELOC-NEXT: FunctionIndex: 0
; RELOC-NEXT: Symbol: 1
; RELOC-NEXT: - Priority: 1001
; RELOC-NEXT: FunctionIndex: 9
; RELOC-NEXT: Symbol: 10
; RELOC-NEXT: - Priority: 2002
; RELOC-NEXT: FunctionIndex: 10
; RELOC-NEXT: Symbol: 12
; RELOC-NEXT: - Priority: 2002
; RELOC-NEXT: FunctionIndex: 17
; RELOC-NEXT: Symbol: 19
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: name
; RELOC-NEXT: FunctionNames:

View File

@ -246,118 +246,6 @@
; RELOC-NEXT: - Type: MEMORY
; RELOC-NEXT: Memories:
; RELOC-NEXT: - Initial: 0x00000001
; RELOC-NEXT: - Type: GLOBAL
; RELOC-NEXT: Globals:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Type: I32
; RELOC-NEXT: Mutable: false
; RELOC-NEXT: InitExpr:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 0
; RELOC-NEXT: - Index: 1
; RELOC-NEXT: Type: I32
; RELOC-NEXT: Mutable: false
; RELOC-NEXT: InitExpr:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 8
; RELOC-NEXT: - Index: 2
; RELOC-NEXT: Type: I32
; RELOC-NEXT: Mutable: false
; RELOC-NEXT: InitExpr:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 16
; RELOC-NEXT: - Index: 3
; RELOC-NEXT: Type: I32
; RELOC-NEXT: Mutable: false
; RELOC-NEXT: InitExpr:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 4
; RELOC-NEXT: - Index: 4
; RELOC-NEXT: Type: I32
; RELOC-NEXT: Mutable: false
; RELOC-NEXT: InitExpr:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 12
; RELOC-NEXT: - Index: 5
; RELOC-NEXT: Type: I32
; RELOC-NEXT: Mutable: false
; RELOC-NEXT: InitExpr:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 20
; RELOC-NEXT: - Type: EXPORT
; RELOC-NEXT: Exports:
; RELOC-NEXT: - Name: colliding_func1.1
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 0
; RELOC-NEXT: - Name: colliding_func2
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 1
; RELOC-NEXT: - Name: colliding_func3
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 2
; RELOC-NEXT: - Name: get_global1A
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 3
; RELOC-NEXT: - Name: get_global2A
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 4
; RELOC-NEXT: - Name: get_global3A
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 5
; RELOC-NEXT: - Name: get_func1A
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 6
; RELOC-NEXT: - Name: get_func2A
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 7
; RELOC-NEXT: - Name: get_func3A
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 8
; RELOC-NEXT: - Name: colliding_func1
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 9
; RELOC-NEXT: - Name: colliding_func2.1
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 10
; RELOC-NEXT: - Name: colliding_func3.1
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 11
; RELOC-NEXT: - Name: get_global1B
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 12
; RELOC-NEXT: - Name: get_global2B
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 13
; RELOC-NEXT: - Name: get_global3B
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 14
; RELOC-NEXT: - Name: get_func1B
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 15
; RELOC-NEXT: - Name: get_func2B
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 16
; RELOC-NEXT: - Name: get_func3B
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 17
; RELOC-NEXT: - Name: colliding_global1.1
; RELOC-NEXT: Kind: GLOBAL
; RELOC-NEXT: Index: 0
; RELOC-NEXT: - Name: colliding_global2
; RELOC-NEXT: Kind: GLOBAL
; RELOC-NEXT: Index: 1
; RELOC-NEXT: - Name: colliding_global3
; RELOC-NEXT: Kind: GLOBAL
; RELOC-NEXT: Index: 2
; RELOC-NEXT: - Name: colliding_global1
; RELOC-NEXT: Kind: GLOBAL
; RELOC-NEXT: Index: 3
; RELOC-NEXT: - Name: colliding_global2.1
; RELOC-NEXT: Kind: GLOBAL
; RELOC-NEXT: Index: 4
; RELOC-NEXT: - Name: colliding_global3.1
; RELOC-NEXT: Kind: GLOBAL
; RELOC-NEXT: Index: 5
; RELOC-NEXT: - Type: ELEM
; RELOC-NEXT: Segments:
; RELOC-NEXT: - Offset:
@ -367,13 +255,13 @@
; RELOC-NEXT: - Type: CODE
; RELOC-NEXT: Relocations:
; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
; RELOC-NEXT: Index: 0
; RELOC-NEXT: Index: 4
; RELOC-NEXT: Offset: 0x00000013
; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Index: 6
; RELOC-NEXT: Offset: 0x0000001C
; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
; RELOC-NEXT: Index: 2
; RELOC-NEXT: Index: 8
; RELOC-NEXT: Offset: 0x00000025
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; RELOC-NEXT: Index: 0
@ -385,22 +273,22 @@
; RELOC-NEXT: Index: 2
; RELOC-NEXT: Offset: 0x00000040
; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
; RELOC-NEXT: Index: 3
; RELOC-NEXT: Index: 16
; RELOC-NEXT: Offset: 0x00000058
; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
; RELOC-NEXT: Index: 4
; RELOC-NEXT: Index: 18
; RELOC-NEXT: Offset: 0x00000061
; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
; RELOC-NEXT: Index: 5
; RELOC-NEXT: Index: 20
; RELOC-NEXT: Offset: 0x0000006A
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; RELOC-NEXT: Index: 9
; RELOC-NEXT: Index: 12
; RELOC-NEXT: Offset: 0x00000073
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; RELOC-NEXT: Index: 10
; RELOC-NEXT: Index: 13
; RELOC-NEXT: Offset: 0x0000007C
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; RELOC-NEXT: Index: 11
; RELOC-NEXT: Index: 14
; RELOC-NEXT: Offset: 0x00000085
; RELOC-NEXT: Functions:
; RELOC-NEXT: - Index: 0
@ -480,23 +368,136 @@
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: linking
; RELOC-NEXT: DataSize: 24
; RELOC-NEXT: SymbolInfo:
; RELOC-NEXT: - Name: colliding_func1.1
; RELOC-NEXT: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: colliding_func1
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: colliding_func3
; RELOC-NEXT: Function: 0
; RELOC-NEXT: - Index: 1
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: colliding_func2
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 1
; RELOC-NEXT: - Index: 2
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: colliding_func3
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: colliding_func2.1
; RELOC-NEXT: Function: 2
; RELOC-NEXT: - Index: 3
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_global1A
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 3
; RELOC-NEXT: - Index: 4
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: colliding_global1
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: colliding_func3.1
; RELOC-NEXT: Segment: 0
; RELOC-NEXT: Size: 4
; RELOC-NEXT: - Index: 5
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_global2A
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 4
; RELOC-NEXT: - Index: 6
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: colliding_global2
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Segment: 1
; RELOC-NEXT: Size: 4
; RELOC-NEXT: - Index: 7
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_global3A
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 5
; RELOC-NEXT: - Index: 8
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: colliding_global3
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: colliding_global1.1
; RELOC-NEXT: Segment: 2
; RELOC-NEXT: Size: 4
; RELOC-NEXT: - Index: 9
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_func1A
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 6
; RELOC-NEXT: - Index: 10
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_func2A
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 7
; RELOC-NEXT: - Index: 11
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_func3A
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 8
; RELOC-NEXT: - Index: 12
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: colliding_func1
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 9
; RELOC-NEXT: - Index: 13
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: colliding_func2
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: colliding_global3
; RELOC-NEXT: Function: 10
; RELOC-NEXT: - Index: 14
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: colliding_func3
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: colliding_global2.1
; RELOC-NEXT: Function: 11
; RELOC-NEXT: - Index: 15
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_global1B
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 12
; RELOC-NEXT: - Index: 16
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: colliding_global1
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Segment: 0
; RELOC-NEXT: Offset: 4
; RELOC-NEXT: Size: 4
; RELOC-NEXT: - Index: 17
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_global2B
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 13
; RELOC-NEXT: - Index: 18
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: colliding_global2
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: - Name: colliding_global3.1
; RELOC-NEXT: Segment: 1
; RELOC-NEXT: Offset: 4
; RELOC-NEXT: Size: 4
; RELOC-NEXT: - Index: 19
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_global3B
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 14
; RELOC-NEXT: - Index: 20
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: colliding_global3
; RELOC-NEXT: Flags: [ BINDING_LOCAL ]
; RELOC-NEXT: Segment: 2
; RELOC-NEXT: Offset: 4
; RELOC-NEXT: Size: 4
; RELOC-NEXT: - Index: 21
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_func1B
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 15
; RELOC-NEXT: - Index: 22
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_func2B
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 16
; RELOC-NEXT: - Index: 23
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: get_func3B
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 17
; RELOC-NEXT: SegmentInfo:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Name: .bss.colliding_global1

File diff suppressed because it is too large Load Diff

View File

@ -59,11 +59,6 @@ entry:
; CHECK-NEXT: Field: bar_import
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 1
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: data_import
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: GlobalType: I32
; CHECK-NEXT: GlobalMutable: false
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 2, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
@ -76,73 +71,6 @@ entry:
; CHECK-NEXT: - Type: MEMORY
; CHECK-NEXT: Memories:
; CHECK-NEXT: - Initial: 0x00000001
; CHECK-NEXT: - Type: GLOBAL
; CHECK-NEXT: Globals:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 0
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 28
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 8
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 12
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 16
; CHECK-NEXT: - Index: 6
; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 24
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
; CHECK-NEXT: - Name: hello
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: my_func
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Name: func_comdat
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Name: hello_str
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: data_comdat
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: func_addr1
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: func_addr2
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Name: func_addr3
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Name: data_addr1
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 6
; CHECK-NEXT: - Type: ELEM
; CHECK-NEXT: Segments:
; CHECK-NEXT: - Offset:
@ -152,19 +80,19 @@ entry:
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
; CHECK-NEXT: Index: 1
; CHECK-NEXT: Index: 2
; CHECK-NEXT: Offset: 0x00000004
; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
; CHECK-NEXT: Index: 0
; CHECK-NEXT: Offset: 0x0000000A
; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
; CHECK-NEXT: Index: 1
; CHECK-NEXT: Index: 3
; CHECK-NEXT: Offset: 0x00000013
; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
; CHECK-NEXT: Index: 2
; CHECK-NEXT: Index: 4
; CHECK-NEXT: Offset: 0x0000001A
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB
; CHECK-NEXT: Index: 2
; CHECK-NEXT: Index: 8
; CHECK-NEXT: Offset: 0x00000026
; CHECK-NEXT: Functions:
; CHECK-NEXT: - Index: 3
@ -179,16 +107,16 @@ entry:
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
; CHECK-NEXT: Index: 4
; CHECK-NEXT: Index: 6
; CHECK-NEXT: Offset: 0x00000012
; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
; CHECK-NEXT: Index: 1
; CHECK-NEXT: Index: 3
; CHECK-NEXT: Offset: 0x0000001B
; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
; CHECK-NEXT: Index: 2
; CHECK-NEXT: Index: 4
; CHECK-NEXT: Offset: 0x00000024
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
; CHECK-NEXT: Index: 0
; CHECK-NEXT: Index: 5
; CHECK-NEXT: Offset: 0x0000002D
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 6
@ -230,25 +158,77 @@ entry:
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: DataSize: 31
; CHECK-NEXT: SymbolInfo:
; CHECK-NEXT: - Name: bar_import
; CHECK-NEXT: SymbolTable:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Name: puts
; CHECK-NEXT: Flags: [ UNDEFINED ]
; CHECK-NEXT: Function: 0
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Name: hello
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; CHECK-NEXT: Function: 3
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Kind: DATA
; CHECK-NEXT: Name: hello_str
; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: Segment: 0
; CHECK-NEXT: Size: 7
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Name: foo_import
; CHECK-NEXT: Flags: [ UNDEFINED ]
; CHECK-NEXT: Function: 1
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Name: bar_import
; CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ]
; CHECK-NEXT: Function: 2
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Kind: DATA
; CHECK-NEXT: Name: data_import
; CHECK-NEXT: Flags: [ UNDEFINED ]
; CHECK-NEXT: - Index: 6
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Name: my_func
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; CHECK-NEXT: Function: 4
; CHECK-NEXT: - Index: 7
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Name: func_comdat
; CHECK-NEXT: Flags: [ BINDING_WEAK ]
; CHECK-NEXT: - Name: hello
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; CHECK-NEXT: - Name: my_func
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; CHECK-NEXT: - Name: func_comdat
; CHECK-NEXT: Function: 5
; CHECK-NEXT: - Index: 8
; CHECK-NEXT: Kind: DATA
; CHECK-NEXT: Name: data_comdat
; CHECK-NEXT: Flags: [ BINDING_WEAK ]
; CHECK-NEXT: - Name: data_comdat
; CHECK-NEXT: Flags: [ BINDING_WEAK ]
; CHECK-NEXT: - Name: func_addr1
; CHECK-NEXT: Segment: 5
; CHECK-NEXT: Size: 3
; CHECK-NEXT: - Index: 9
; CHECK-NEXT: Kind: DATA
; CHECK-NEXT: Name: func_addr1
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; CHECK-NEXT: - Name: func_addr2
; CHECK-NEXT: Segment: 1
; CHECK-NEXT: Size: 4
; CHECK-NEXT: - Index: 10
; CHECK-NEXT: Kind: DATA
; CHECK-NEXT: Name: func_addr2
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; CHECK-NEXT: - Name: func_addr3
; CHECK-NEXT: Segment: 2
; CHECK-NEXT: Size: 4
; CHECK-NEXT: - Index: 11
; CHECK-NEXT: Kind: DATA
; CHECK-NEXT: Name: func_addr3
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; CHECK-NEXT: - Name: data_addr1
; CHECK-NEXT: Segment: 3
; CHECK-NEXT: Size: 4
; CHECK-NEXT: - Index: 12
; CHECK-NEXT: Kind: DATA
; CHECK-NEXT: Name: data_addr1
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; CHECK-NEXT: Segment: 4
; CHECK-NEXT: Size: 4
; CHECK-NEXT: SegmentInfo:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: .rodata.hello_str

View File

@ -14,6 +14,6 @@ entry:
ret void
}
; CHECK: error: function signature mismatch: weakFn
; CHECK: error: Function type mismatch: weakFn
; CHECK-NEXT: >>> defined as () -> I32 in {{.*}}signature-mismatch-weak.ll.tmp.o
; CHECK-NEXT: >>> defined as () -> I64 in {{.*}}signature-mismatch-weak.ll.tmp.strong.o

View File

@ -17,10 +17,10 @@ entry:
declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1
; CHECK: error: function signature mismatch: ret32
; CHECK: error: Function type mismatch: ret32
; CHECK-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o
; CHECK-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o
; REVERSE: error: function signature mismatch: ret32
; REVERSE: error: Function type mismatch: ret32
; REVERSE-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o
; REVERSE-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o

View File

@ -26,7 +26,7 @@ entry:
; CHECK-NEXT: Field: __stack_pointer
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: GlobalType: I32
; CHECK-NEXT: GlobalMutable: false
; CHECK-NEXT: GlobalMutable: true
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0 ]
; CHECK-NEXT: - Type: TABLE
@ -39,11 +39,6 @@ entry:
; CHECK-NEXT: - Type: MEMORY
; CHECK-NEXT: Memories:
; CHECK-NEXT: - Initial: 0x00000000
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
@ -56,6 +51,17 @@ entry:
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
; CHECK-NEXT: DataSize: 0
; CHECK-NEXT: SymbolTable:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Name: __stack_pointer
; CHECK-NEXT: Flags: [ UNDEFINED ]
; CHECK-NEXT: Global: 0
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Name: _start
; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: Function: 0
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:

View File

@ -68,9 +68,6 @@ entry:
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: alias_fn
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: direct_fn
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 1
@ -86,6 +83,9 @@ entry:
; CHECK-NEXT: - Name: call_direct_ptr
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Name: alias_fn
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: __heap_base
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 1
@ -168,7 +168,7 @@ entry:
; RELOC-NEXT: Field: __stack_pointer
; RELOC-NEXT: Kind: GLOBAL
; RELOC-NEXT: GlobalType: I32
; RELOC-NEXT: GlobalMutable: false
; RELOC-NEXT: GlobalMutable: true
; RELOC-NEXT: - Type: FUNCTION
; RELOC-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1 ]
; RELOC-NEXT: - Type: TABLE
@ -181,29 +181,6 @@ entry:
; RELOC-NEXT: - Type: MEMORY
; RELOC-NEXT: Memories:
; RELOC-NEXT: - Initial: 0x00000000
; RELOC-NEXT: - Type: EXPORT
; RELOC-NEXT: Exports:
; RELOC-NEXT: - Name: _start
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 0
; RELOC-NEXT: - Name: alias_fn
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 1
; RELOC-NEXT: - Name: direct_fn
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 1
; RELOC-NEXT: - Name: call_direct
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 2
; RELOC-NEXT: - Name: call_alias
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 3
; RELOC-NEXT: - Name: call_alias_ptr
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 4
; RELOC-NEXT: - Name: call_direct_ptr
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Index: 5
; RELOC-NEXT: - Type: ELEM
; RELOC-NEXT: Segments:
; RELOC-NEXT: - Offset:
@ -213,43 +190,43 @@ entry:
; RELOC-NEXT: - Type: CODE
; RELOC-NEXT: Relocations:
; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Index: 7
; RELOC-NEXT: Offset: 0x00000004
; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Index: 2
; RELOC-NEXT: Offset: 0x00000013
; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Index: 7
; RELOC-NEXT: Offset: 0x0000001C
; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
; RELOC-NEXT: Index: 0
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Offset: 0x00000027
; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
; RELOC-NEXT: Index: 0
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Offset: 0x00000032
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Index: 7
; RELOC-NEXT: Offset: 0x0000003A
; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Index: 7
; RELOC-NEXT: Offset: 0x00000043
; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
; RELOC-NEXT: Index: 0
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Offset: 0x00000050
; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
; RELOC-NEXT: Index: 0
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Offset: 0x0000005D
; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
; RELOC-NEXT: Index: 0
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Offset: 0x00000068
; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Index: 2
; RELOC-NEXT: Offset: 0x00000070
; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Index: 2
; RELOC-NEXT: Offset: 0x00000079
; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
; RELOC-NEXT: Index: 0
; RELOC-NEXT: Index: 1
; RELOC-NEXT: Offset: 0x00000086
; RELOC-NEXT: Functions:
; RELOC-NEXT: - Index: 0
@ -277,9 +254,47 @@ entry:
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: linking
; RELOC-NEXT: DataSize: 0
; RELOC-NEXT: SymbolInfo:
; RELOC-NEXT: - Name: alias_fn
; RELOC-NEXT: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: _start
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 0
; RELOC-NEXT: - Index: 1
; RELOC-NEXT: Kind: GLOBAL
; RELOC-NEXT: Name: __stack_pointer
; RELOC-NEXT: Flags: [ UNDEFINED ]
; RELOC-NEXT: Global: 0
; RELOC-NEXT: - Index: 2
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: direct_fn
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 1
; RELOC-NEXT: - Index: 3
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: call_direct
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 2
; RELOC-NEXT: - Index: 4
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: call_alias
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 3
; RELOC-NEXT: - Index: 5
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: call_alias_ptr
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 4
; RELOC-NEXT: - Index: 6
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: call_direct_ptr
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: Function: 5
; RELOC-NEXT: - Index: 7
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: alias_fn
; RELOC-NEXT: Flags: [ BINDING_WEAK ]
; RELOC-NEXT: Function: 1
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: name
; RELOC-NEXT: FunctionNames:

View File

@ -9,6 +9,7 @@
#include "lld/Common/Driver.h"
#include "Config.h"
#include "InputGlobal.h"
#include "MarkLive.h"
#include "SymbolTable.h"
#include "Writer.h"
@ -59,6 +60,7 @@ private:
void addFile(StringRef Path);
void addLibrary(StringRef Name);
std::vector<InputFile *> Files;
llvm::wasm::WasmGlobal StackPointerGlobal;
};
} // anonymous namespace
@ -222,8 +224,8 @@ static StringRef getEntry(opt::InputArgList &Args, StringRef Default) {
return Arg->getValue();
}
static Symbol* addUndefinedFunction(StringRef Name, const WasmSignature *Type) {
return Symtab->addUndefined(Name, Symbol::UndefinedFunctionKind, 0, nullptr,
static Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type) {
return Symtab->addUndefined(Name, WASM_SYMBOL_TYPE_FUNCTION, 0, nullptr,
Type);
}
@ -296,14 +298,25 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Symbol *EntrySym = nullptr;
if (!Config->Relocatable) {
static WasmSignature NullSignature = {{}, WASM_TYPE_NORESULT};
// Can't export the SP right now because it's mutable, and mutable
// globals aren't yet supported in the official binary format.
// TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN if/when the
// "mutable global" proposal is accepted.
StackPointerGlobal.Type = {WASM_TYPE_I32, true};
StackPointerGlobal.InitExpr.Value.Int32 = 0;
StackPointerGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
InputGlobal *StackPointer = make<InputGlobal>(StackPointerGlobal);
StackPointer->Live = true;
static WasmSignature NullSignature = {{}, WASM_TYPE_NORESULT};
// Add synthetic symbols before any others
WasmSym::CallCtors = Symtab->addSyntheticFunction(
"__wasm_call_ctors", &NullSignature, WASM_SYMBOL_VISIBILITY_HIDDEN);
WasmSym::StackPointer = Symtab->addSyntheticDataSymbol("__stack_pointer");
WasmSym::StackPointer = Symtab->addSyntheticGlobal(
"__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, StackPointer);
WasmSym::HeapBase = Symtab->addSyntheticDataSymbol("__heap_base");
WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol("__dso_handle");
WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol(
"__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);
WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end");
if (!Config->Entry.empty())

View File

@ -27,12 +27,10 @@ std::string lld::toString(const InputChunk *C) {
return (toString(C->File) + ":(" + C->getName() + ")").str();
}
uint32_t InputSegment::translateVA(uint32_t Address) const {
assert(Address >= startVA() && Address < endVA());
int32_t Delta = OutputSeg->StartVA + OutputSegmentOffset - startVA();
DEBUG(dbgs() << "translateVA: " << getName() << " Delta=" << Delta
<< " Address=" << Address << "\n");
return Address + Delta;
uint32_t InputSegment::translateVA(uint32_t Offset) const {
assert(Offset <= getSize());
DEBUG(dbgs() << "translateVA: " << getName() << " Offset=" << Offset << "\n");
return OutputSeg->StartVA + OutputSegmentOffset + Offset;
}
void InputChunk::copyRelocations(const WasmSection &Section) {

View File

@ -7,8 +7,14 @@
//
//===----------------------------------------------------------------------===//
//
// An input chunk represents an indivisible blocks of code or data from an input
// file. i.e. a single wasm data segment or a single wasm function.
// An InputChunks represents an indivisible opaque region of a input wasm file.
// i.e. a single wasm data segment or a single wasm function.
//
// They are written directly to the mmap'd output file after which relocations
// are applied. Because each Chunk is independent they can be written in
// parallel.
//
// Chunks are also unit on which garbage collection (--gc-sections) operates.
//
//===----------------------------------------------------------------------===//
@ -92,7 +98,7 @@ public:
// Translate an offset in the input segment to an offset in the output
// segment.
uint32_t translateVA(uint32_t Address) const;
uint32_t translateVA(uint32_t Offset) const;
const OutputSegment *getOutputSegment() const { return OutputSeg; }
@ -102,8 +108,6 @@ public:
}
uint32_t getAlignment() const { return Segment.Data.Alignment; }
uint32_t startVA() const { return Segment.Data.Offset.Value.Int32; }
uint32_t endVA() const { return startVA() + getSize(); }
StringRef getName() const override { return Segment.Data.Name; }
StringRef getComdat() const override { return Segment.Data.Comdat; }

View File

@ -10,6 +10,7 @@
#include "InputFiles.h"
#include "Config.h"
#include "InputChunks.h"
#include "InputGlobal.h"
#include "SymbolTable.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
@ -43,8 +44,7 @@ Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
void ObjFile::dumpInfo() const {
log("info for: " + getName() + "\n" +
" Total Functions : " + Twine(FunctionSymbols.size()) + "\n" +
" Total Data Symbols : " + Twine(DataSymbols.size()) + "\n" +
" Symbols : " + Twine(Symbols.size()) + "\n" +
" Function Imports : " + Twine(NumFunctionImports) + "\n" +
" Global Imports : " + Twine(NumGlobalImports) + "\n");
}
@ -71,6 +71,8 @@ uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const {
uint32_t ObjFile::relocateTableIndex(uint32_t Original) const {
const FunctionSymbol *Sym = getFunctionSymbol(Original);
// The null case is possible, if you take the address of a weak function
// that's simply not supplied.
uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0;
DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original
<< " -> " << Index << "\n");
@ -78,33 +80,30 @@ uint32_t ObjFile::relocateTableIndex(uint32_t Original) const {
}
uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const {
const Symbol *Sym = getDataSymbol(Original);
const Symbol *Sym = getGlobalSymbol(Original);
uint32_t Index = Sym->getOutputIndex();
DEBUG(dbgs() << "relocateGlobalIndex: " << toString(*Sym) << ": " << Original
<< " -> " << Index << "\n");
return Index;
}
uint32_t ObjFile::relocateSymbolIndex(uint32_t Original) const {
Symbol *Sym = getSymbol(Original);
uint32_t Index = Sym->getOutputSymbolIndex();
DEBUG(dbgs() << "relocateSymbolIndex: " << toString(*Sym) << ": " << Original
<< " -> " << Index << "\n");
return Index;
}
// Relocations contain an index into the function, global or table index
// space of the input file. This function takes a relocation and returns the
// relocated index (i.e. translates from the input index space to the output
// index space).
uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const {
switch (Reloc.Type) {
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB)
return relocateTypeIndex(Reloc.Index);
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case R_WEBASSEMBLY_TABLE_INDEX_I32:
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
return relocateFunctionIndex(Reloc.Index);
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
return relocateGlobalIndex(Reloc.Index);
default:
llvm_unreachable("unknown relocation type");
}
return relocateSymbolIndex(Reloc.Index);
}
// Translate from the relocation's index into the final linked output value.
@ -160,80 +159,60 @@ void ObjFile::parse() {
// Return the InputSegment in which a given symbol is defined.
InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) const {
uint32_t Address = WasmObj->getWasmSymbolValue(WasmSym);
for (InputSegment *Segment : Segments) {
if (Address >= Segment->startVA() && Address < Segment->endVA()) {
DEBUG(dbgs() << "Found symbol in segment: " << WasmSym.Name << " -> "
<< Segment->getName() << "\n");
return Segment;
}
}
error("symbol not found in any segment: " + WasmSym.Name);
return nullptr;
}
// Get the value stored in the wasm global represented by this symbol.
// This represents the virtual address of the symbol in the input file.
uint32_t ObjFile::getGlobalValue(const WasmSymbol &Sym) const {
const WasmGlobal &Global =
getWasmObj()->globals()[Sym.ElementIndex - NumGlobalImports];
assert(Global.Type.Type == llvm::wasm::WASM_TYPE_I32);
return Global.InitExpr.Value.Int32;
}
// Get the signature for a given function symbol, either by looking
// it up in function sections (for defined functions), of the imports section
// (for imported functions).
const WasmSignature *ObjFile::getFunctionSig(const WasmSymbol &Sym) const {
DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n");
return &WasmObj->types()[Sym.FunctionType];
return Segments[WasmSym.Info.DataRef.Segment];
}
InputFunction *ObjFile::getFunction(const WasmSymbol &Sym) const {
uint32_t FunctionIndex = Sym.ElementIndex - NumFunctionImports;
assert(Sym.Info.ElementIndex >= NumFunctionImports);
uint32_t FunctionIndex = Sym.Info.ElementIndex - NumFunctionImports;
return Functions[FunctionIndex];
}
InputGlobal *ObjFile::getGlobal(const WasmSymbol &Sym) const {
assert(Sym.Info.ElementIndex >= NumGlobalImports);
uint32_t GlobalIndex = Sym.Info.ElementIndex - NumGlobalImports;
return Globals[GlobalIndex];
}
bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const {
StringRef Comdat = Chunk->getComdat();
return !Comdat.empty() && Symtab->findComdat(Comdat) != this;
}
FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t Index) const {
return cast<FunctionSymbol>(Symbols[Index]);
}
GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
return cast<GlobalSymbol>(Symbols[Index]);
}
DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const {
return cast<DataSymbol>(Symbols[Index]);
}
void ObjFile::initializeSymbols() {
Symbols.reserve(WasmObj->getNumberOfSymbols());
for (const WasmImport &Import : WasmObj->imports()) {
switch (Import.Kind) {
case WASM_EXTERNAL_FUNCTION:
++NumFunctionImports;
break;
case WASM_EXTERNAL_GLOBAL:
++NumGlobalImports;
break;
}
}
FunctionSymbols.resize(NumFunctionImports + WasmObj->functions().size());
DataSymbols.resize(NumGlobalImports + WasmObj->globals().size());
NumFunctionImports = WasmObj->getNumImportedFunctions();
NumGlobalImports = WasmObj->getNumImportedGlobals();
ArrayRef<WasmFunction> Funcs = WasmObj->functions();
ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
ArrayRef<WasmSignature> Types = WasmObj->types();
ArrayRef<WasmGlobal> Globals = WasmObj->globals();
for (const auto &C : WasmObj->comdats())
Symtab->addComdat(C, this);
FunctionSymbols.resize(NumFunctionImports + Funcs.size());
DataSymbols.resize(NumGlobalImports + Globals.size());
for (const WasmSegment &S : WasmObj->dataSegments()) {
InputSegment *Seg = make<InputSegment>(S, this);
Seg->copyRelocations(*DataSection);
Segments.emplace_back(Seg);
}
for (const WasmGlobal &G : WasmObj->globals())
Globals.emplace_back(make<InputGlobal>(G));
for (size_t I = 0; I < Funcs.size(); ++I) {
const WasmFunction &Func = Funcs[I];
const WasmSignature &Sig = Types[FuncTypes[I]];
@ -242,77 +221,80 @@ void ObjFile::initializeSymbols() {
Functions.emplace_back(F);
}
// Populate `FunctionSymbols` and `DataSymbols` based on the WasmSymbols
// in the object
// Populate `Symbols` based on the WasmSymbols in the object
for (const SymbolRef &Sym : WasmObj->symbols()) {
const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
Symbol *S;
switch (WasmSym.Type) {
case WasmSymbol::SymbolType::FUNCTION_EXPORT: {
InputFunction *Function = getFunction(WasmSym);
if (!isExcludedByComdat(Function)) {
S = createDefinedFunction(WasmSym, Function);
bool IsDefined = WasmSym.isDefined();
if (IsDefined) {
switch (WasmSym.Info.Kind) {
case WASM_SYMBOL_TYPE_FUNCTION: {
InputFunction *Function = getFunction(WasmSym);
if (isExcludedByComdat(Function)) {
Function->Live = false;
IsDefined = false;
break;
}
Symbols.push_back(createDefinedFunction(WasmSym, Function));
break;
}
Function->Live = false;
LLVM_FALLTHROUGH; // Exclude function, and add the symbol as undefined
}
case WasmSymbol::SymbolType::FUNCTION_IMPORT:
S = createUndefined(WasmSym, Symbol::Kind::UndefinedFunctionKind,
getFunctionSig(WasmSym));
break;
case WasmSymbol::SymbolType::GLOBAL_EXPORT: {
InputSegment *Segment = getSegment(WasmSym);
if (!isExcludedByComdat(Segment)) {
S = createDefinedData(WasmSym, Segment, getGlobalValue(WasmSym));
case WASM_SYMBOL_TYPE_DATA: {
InputSegment *Segment = getSegment(WasmSym);
if (isExcludedByComdat(Segment)) {
Segment->Live = false;
IsDefined = false;
break;
}
Symbols.push_back(createDefinedData(WasmSym, Segment,
WasmSym.Info.DataRef.Offset,
WasmSym.Info.DataRef.Size));
break;
}
case WASM_SYMBOL_TYPE_GLOBAL:
Symbols.push_back(createDefinedGlobal(WasmSym, getGlobal(WasmSym)));
break;
default:
llvm_unreachable("unkown symbol kind");
break;
}
Segment->Live = false;
LLVM_FALLTHROUGH; // Exclude global, and add the symbol as undefined
}
case WasmSymbol::SymbolType::GLOBAL_IMPORT:
S = createUndefined(WasmSym, Symbol::Kind::UndefinedDataKind);
break;
}
Symbols.push_back(S);
if (WasmSym.isTypeFunction()) {
FunctionSymbols[WasmSym.ElementIndex] = S;
if (WasmSym.HasAltIndex)
FunctionSymbols[WasmSym.AltIndex] = S;
} else {
DataSymbols[WasmSym.ElementIndex] = S;
if (WasmSym.HasAltIndex)
DataSymbols[WasmSym.AltIndex] = S;
}
// Either the the symbol itself was undefined, or was excluded via comdat
// in which case this simply insertes the existing symbol into the correct
// slot in the Symbols array.
if (!IsDefined)
Symbols.push_back(createUndefined(WasmSym));
}
DEBUG(for (size_t I = 0; I < FunctionSymbols.size(); ++I)
assert(FunctionSymbols[I] != nullptr);
for (size_t I = 0; I < DataSymbols.size(); ++I)
assert(DataSymbols[I] != nullptr););
DEBUG(dbgs() << "Functions : " << FunctionSymbols.size() << "\n");
DEBUG(dbgs() << "Globals : " << DataSymbols.size() << "\n");
}
Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,
const WasmSignature *Signature) {
return Symtab->addUndefined(Sym.Name, Kind, Sym.Flags, this, Signature);
Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
return Symtab->addUndefined(
Sym.Info.Name, static_cast<WasmSymbolType>(Sym.Info.Kind), Sym.Info.Flags,
this, Sym.FunctionType, Sym.GlobalType);
}
Symbol *ObjFile::createDefinedFunction(const WasmSymbol &Sym,
InputFunction *Function) {
if (Sym.isBindingLocal())
return make<DefinedFunction>(Sym.Name, Sym.Flags, this, Function);
return Symtab->addDefinedFunction(Sym.Name, Sym.Flags, this, Function);
return make<DefinedFunction>(Sym.Info.Name, Sym.Info.Flags, this, Function);
return Symtab->addDefinedFunction(Sym.Info.Name, Sym.Info.Flags, this,
Function);
}
Symbol *ObjFile::createDefinedData(const WasmSymbol &Sym, InputSegment *Segment,
uint32_t Address) {
uint32_t Offset, uint32_t Size) {
if (Sym.isBindingLocal())
return make<DefinedData>(Sym.Name, Sym.Flags, this, Segment, Address);
return Symtab->addDefinedData(Sym.Name, Sym.Flags, this, Segment, Address);
return make<DefinedData>(Sym.Info.Name, Sym.Info.Flags, this, Segment,
Offset, Size);
return Symtab->addDefinedData(Sym.Info.Name, Sym.Info.Flags, this, Segment,
Offset, Size);
}
Symbol *ObjFile::createDefinedGlobal(const WasmSymbol &Sym,
InputGlobal *Global) {
if (Sym.isBindingLocal())
return make<DefinedGlobal>(Sym.Info.Name, Sym.Info.Flags, this, Global);
return Symtab->addDefinedGlobal(Sym.Info.Name, Sym.Info.Flags, this, Global);
}
void ArchiveFile::parse() {

View File

@ -23,6 +23,7 @@ using llvm::object::Archive;
using llvm::object::WasmObjectFile;
using llvm::object::WasmSection;
using llvm::object::WasmSymbol;
using llvm::wasm::WasmGlobal;
using llvm::wasm::WasmImport;
using llvm::wasm::WasmSignature;
using llvm::wasm::WasmRelocation;
@ -33,6 +34,7 @@ namespace wasm {
class InputChunk;
class InputFunction;
class InputSegment;
class InputGlobal;
class InputFile {
public:
@ -90,7 +92,6 @@ public:
void dumpInfo() const;
uint32_t relocateFunctionIndex(uint32_t Original) const;
uint32_t calcNewIndex(const WasmRelocation &Reloc) const;
uint32_t calcNewValue(const WasmRelocation &Reloc) const;
@ -101,44 +102,37 @@ public:
std::vector<bool> TypeIsUsed;
std::vector<InputSegment *> Segments;
std::vector<InputFunction *> Functions;
std::vector<InputGlobal *> Globals;
ArrayRef<Symbol *> getSymbols() const { return Symbols; }
FunctionSymbol *getFunctionSymbol(uint32_t Index) const {
return cast<FunctionSymbol>(FunctionSymbols[Index]);
}
DataSymbol *getDataSymbol(uint32_t Index) const {
return cast<DataSymbol>(DataSymbols[Index]);
}
Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; }
FunctionSymbol *getFunctionSymbol(uint32_t Index) const;
DataSymbol *getDataSymbol(uint32_t Index) const;
GlobalSymbol *getGlobalSymbol(uint32_t Index) const;
private:
uint32_t relocateVirtualAddress(uint32_t Index) const;
uint32_t relocateFunctionIndex(uint32_t Original) const;
uint32_t relocateTypeIndex(uint32_t Original) const;
uint32_t relocateGlobalIndex(uint32_t Original) const;
uint32_t relocateTableIndex(uint32_t Original) const;
uint32_t relocateSymbolIndex(uint32_t Original) const;
Symbol *createDefinedData(const WasmSymbol &Sym, InputSegment *Segment,
uint32_t Address);
uint32_t Offset, uint32_t DataSize);
Symbol *createDefinedFunction(const WasmSymbol &Sym, InputFunction *Function);
Symbol *createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,
const WasmSignature *Signature = nullptr);
Symbol *createDefinedGlobal(const WasmSymbol &Sym, InputGlobal *Global);
Symbol *createUndefined(const WasmSymbol &Sym);
void initializeSymbols();
InputSegment *getSegment(const WasmSymbol &WasmSym) const;
const WasmSignature *getFunctionSig(const WasmSymbol &Sym) const;
uint32_t getGlobalValue(const WasmSymbol &Sym) const;
InputFunction *getFunction(const WasmSymbol &Sym) const;
InputGlobal *getGlobal(const WasmSymbol &Sym) const;
bool isExcludedByComdat(InputChunk *Chunk) const;
// List of all symbols referenced or defined by this file.
std::vector<Symbol *> Symbols;
// List of all function symbols indexed by the function index space
std::vector<Symbol *> FunctionSymbols;
// List of all global symbols indexed by the global index space
std::vector<Symbol *> DataSymbols;
uint32_t NumGlobalImports = 0;
uint32_t NumFunctionImports = 0;
std::unique_ptr<WasmObjectFile> WasmObj;

52
lld/wasm/InputGlobal.h Normal file
View File

@ -0,0 +1,52 @@
//===- InputGlobal.h --------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_WASM_INPUT_GLOBAL_H
#define LLD_WASM_INPUT_GLOBAL_H
#include "Config.h"
#include "InputFiles.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Object/Wasm.h"
using llvm::wasm::WasmGlobal;
using llvm::wasm::WasmInitExpr;
namespace lld {
namespace wasm {
// Represents a single Wasm Global Variable within an input file. These are
// combined to form the final GLOBALS section.
class InputGlobal {
public:
InputGlobal(const WasmGlobal &G) : Global(G) {}
const WasmGlobalType &getType() const { return Global.Type; }
uint32_t getOutputIndex() const { return OutputIndex.getValue(); }
bool hasOutputIndex() const { return OutputIndex.hasValue(); }
void setOutputIndex(uint32_t Index) {
assert(!hasOutputIndex());
OutputIndex = Index;
}
bool Live = false;
WasmGlobal Global;
protected:
llvm::Optional<uint32_t> OutputIndex;
};
} // namespace wasm
} // namespace lld
#endif // LLD_WASM_INPUT_GLOBAL_H

View File

@ -65,7 +65,7 @@ void lld::wasm::markLive() {
for (const ObjFile *Obj : Symtab->ObjectFiles) {
const WasmLinkingData &L = Obj->getWasmObj()->linkingData();
for (const WasmInitFunc &F : L.InitFunctions)
Enqueue(Obj->getFunctionSymbol(F.FunctionIndex));
Enqueue(Obj->getFunctionSymbol(F.Symbol));
}
// Follow relocations to mark all reachable chunks.
@ -73,19 +73,8 @@ void lld::wasm::markLive() {
InputChunk *C = Q.pop_back_val();
for (const WasmRelocation Reloc : C->getRelocations()) {
switch (Reloc.Type) {
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case R_WEBASSEMBLY_TABLE_INDEX_I32:
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
Enqueue(C->File->getFunctionSymbol(Reloc.Index));
break;
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
Enqueue(C->File->getDataSymbol(Reloc.Index));
break;
}
if (Reloc.Type != R_WEBASSEMBLY_TYPE_INDEX_LEB)
Enqueue(C->File->getSymbol(Reloc.Index));
}
}

View File

@ -21,7 +21,7 @@ class InputSegment;
class OutputSegment {
public:
OutputSegment(StringRef N) : Name(N) {}
OutputSegment(StringRef N, uint32_t Index) : Name(N), Index(Index) {}
void addInputSegment(InputSegment *Segment) {
Alignment = std::max(Alignment, Segment->getAlignment());
@ -36,6 +36,7 @@ public:
void setSectionOffset(uint32_t Offset) { SectionOffset = Offset; }
StringRef Name;
const uint32_t Index;
uint32_t Alignment = 0;
uint32_t StartVA = 0;
std::vector<InputSegment *> InputSegments;

View File

@ -10,6 +10,7 @@
#include "SymbolTable.h"
#include "Config.h"
#include "InputChunks.h"
#include "InputGlobal.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
@ -73,50 +74,58 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
// Check the type of new symbol matches that of the symbol is replacing.
// For functions this can also involve verifying that the signatures match.
static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
bool NewIsFunction, const WasmSignature *NewSig) {
WasmSymbolType NewType,
const WasmSignature *NewFunctionSig,
const WasmGlobalType *NewGlobalType) {
if (Existing.isLazy())
return;
WasmSymbolType ExistingType = Existing.getWasmType();
// First check the symbol types match (i.e. either both are function
// symbols or both are data symbols).
if (isa<FunctionSymbol>(Existing) != NewIsFunction) {
if (NewType != ExistingType) {
error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " +
(isa<FunctionSymbol>(Existing) ? "Function" : "Data") + " in " +
toString(Existing.getFile()) + "\n>>> defined as " +
(NewIsFunction ? "Function" : "Data") + " in " + F.getName());
toString(ExistingType) + " in " + toString(Existing.getFile()) +
"\n>>> defined as " + toString(NewType) + " in " + F.getName());
return;
}
// For function symbols, optionally check the function signature matches too.
auto *ExistingFunc = dyn_cast<FunctionSymbol>(&Existing);
if (!ExistingFunc || !Config->CheckSignatures)
// For function/global symbols, optionally check the type matches too.
if (NewType == WASM_SYMBOL_TYPE_DATA || !Config->CheckSignatures)
return;
const WasmSignature *OldSig = ExistingFunc->getFunctionType();
DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n");
// Skip the signature check if the existing function has no signature (e.g.
// if it is an undefined symbol generated by --undefined command line flag).
if (OldSig == nullptr)
return;
auto ReportError = [&](const Twine &Old, const Twine &New) {
error(toString(NewType) + " type mismatch: " + Existing.getName() +
"\n>>> defined as " + Old + " in " + toString(Existing.getFile()) +
"\n>>> defined as " + New + " in " + F.getName());
};
DEBUG(dbgs() << "checkSymbolTypes: " << ExistingFunc->getName() << "\n");
assert(NewSig);
if (NewType == WASM_SYMBOL_TYPE_FUNCTION) {
// Skip the signature check if the existing function has no signature (e.g.
// if it is an undefined symbol generated by --undefined command line flag).
auto &Sym = cast<FunctionSymbol>(Existing);
const WasmSignature *OldSig = Sym.getFunctionType();
if (!OldSig)
return;
if (*NewSig == *OldSig)
return;
assert(NewFunctionSig);
if (*NewFunctionSig == *OldSig)
return;
error("function signature mismatch: " + ExistingFunc->getName() +
"\n>>> defined as " + toString(*OldSig) + " in " +
toString(ExistingFunc->getFile()) + "\n>>> defined as " +
toString(*NewSig) + " in " + F.getName());
}
ReportError(toString(*OldSig), toString(*NewFunctionSig));
} else {
auto &Sym = cast<GlobalSymbol>(Existing);
static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
bool IsFunction, const InputChunk *Chunk) {
const WasmSignature *Sig = nullptr;
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
Sig = &F->Signature;
return checkSymbolTypes(Existing, F, IsFunction, Sig);
assert(NewGlobalType != nullptr);
const WasmGlobalType *OldType = Sym.getGlobalType();
if (*NewGlobalType == *OldType)
return;
ReportError(toString(*OldType), toString(*NewGlobalType));
}
}
DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
@ -140,9 +149,21 @@ DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
return replaceSymbol<DefinedData>(S, Name, Flags);
}
DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
InputGlobal *Global) {
DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
assert(WasInserted);
return replaceSymbol<DefinedGlobal>(S, Name, Flags, nullptr, Global);
}
static bool shouldReplace(const Symbol &Existing, InputFile *NewFile,
uint32_t NewFlags, InputChunk *NewChunk,
bool NewIsFunction) {
WasmSymbolType NewType, uint32_t NewFlags,
const WasmSignature *NewFuncType = nullptr,
const WasmGlobalType *NewGlobalType = nullptr) {
// If existing symbol is lazy, replace it without checking types since
// lazy symbols don't have any type information.
if (Existing.isLazy()) {
@ -155,7 +176,7 @@ static bool shouldReplace(const Symbol &Existing, InputFile *NewFile,
// symbol name must have the same type, even if they are undefined. This
// is different from ELF because symbol types are not that significant
// in ELF, and undefined symbols in ELF don't have type in the first place.
checkSymbolTypes(Existing, *NewFile, NewIsFunction, NewChunk);
checkSymbolTypes(Existing, *NewFile, NewType, NewFuncType, NewGlobalType);
// If existing symbol is undefined, replace it.
if (!Existing.isDefined()) {
@ -188,38 +209,58 @@ Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted || shouldReplace(*S, F, Flags, Function, true))
if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_FUNCTION, Flags,
&Function->Signature))
replaceSymbol<DefinedFunction>(S, Name, Flags, F, Function);
return S;
}
Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
InputFile *F, InputSegment *Segment,
uint32_t Address) {
InputFile *F, InputSegment *Segment,
uint32_t Address, uint32_t Size) {
DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted || shouldReplace(*S, F, Flags, Segment, false))
replaceSymbol<DefinedData>(S, Name, Flags, F, Segment, Address);
if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_DATA, Flags))
replaceSymbol<DefinedData>(S, Name, Flags, F, Segment, Address, Size);
return S;
}
Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind,
Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
InputFile *F, InputGlobal *Global) {
DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_GLOBAL, Flags,
nullptr, &Global->getType()))
replaceSymbol<DefinedGlobal>(S, Name, Flags, F, Global);
return S;
}
Symbol *SymbolTable::addUndefined(StringRef Name, WasmSymbolType Type,
uint32_t Flags, InputFile *F,
const WasmSignature *Type) {
DEBUG(dbgs() << "addUndefined: " << Name << "\n");
const WasmSignature *FunctionType,
const WasmGlobalType *GlobalType) {
DEBUG(dbgs() << "addUndefined type=" << Type << ": " << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
bool IsFunction = Kind == Symbol::UndefinedFunctionKind;
if (WasInserted) {
if (IsFunction)
replaceSymbol<UndefinedFunction>(S, Name, Flags, F, Type);
else
switch (Type) {
case WASM_SYMBOL_TYPE_FUNCTION:
replaceSymbol<UndefinedFunction>(S, Name, Flags, F, FunctionType);
break;
case WASM_SYMBOL_TYPE_GLOBAL:
replaceSymbol<UndefinedGlobal>(S, Name, Flags, F, GlobalType);
break;
case WASM_SYMBOL_TYPE_DATA:
replaceSymbol<UndefinedData>(S, Name, Flags, F);
break;
}
return S;
}
@ -231,8 +272,9 @@ Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind,
if (S->isDefined()) {
DEBUG(dbgs() << "resolved by existing\n");
checkSymbolTypes(*S, *F, IsFunction, Type);
checkSymbolTypes(*S, *F, Type, FunctionType, GlobalType);
}
return S;
}

View File

@ -17,6 +17,7 @@
#include "llvm/Support/raw_ostream.h"
using llvm::wasm::WasmSignature;
using llvm::wasm::WasmGlobalType;
namespace lld {
namespace wasm {
@ -50,17 +51,26 @@ public:
Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
InputFunction *Function = nullptr);
Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *F,
InputSegment *Segment = nullptr, uint32_t Address = 0);
InputSegment *Segment = nullptr, uint32_t Address = 0,
uint32_t Size = 0);
Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *F,
InputGlobal *G);
Symbol *addUndefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,
InputFile *F, const WasmSignature *Signature = nullptr);
Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type);
Symbol *addUndefined(StringRef Name, WasmSymbolType Type, uint32_t Flags,
InputFile *F, const WasmSignature *Signature = nullptr,
const WasmGlobalType *GlobalType = nullptr);
void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);
bool addComdat(StringRef Name, ObjFile *);
DefinedData *addSyntheticDataSymbol(StringRef Name, uint32_t Flags = 0);
DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags,
InputGlobal *Global);
DefinedFunction *addSyntheticFunction(StringRef Name,
const WasmSignature *Type,
uint32_t Flags = 0);
private:
std::pair<Symbol *, bool> insert(StringRef Name);

View File

@ -11,6 +11,8 @@
#include "Config.h"
#include "InputChunks.h"
#include "InputFiles.h"
#include "InputGlobal.h"
#include "OutputSegment.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Strings.h"
@ -25,19 +27,42 @@ DefinedFunction *WasmSym::CallCtors;
DefinedData *WasmSym::DsoHandle;
DefinedData *WasmSym::DataEnd;
DefinedData *WasmSym::HeapBase;
DefinedData *WasmSym::StackPointer;
DefinedGlobal *WasmSym::StackPointer;
WasmSymbolType Symbol::getWasmType() const {
switch (SymbolKind) {
case Symbol::DefinedFunctionKind:
case Symbol::UndefinedFunctionKind:
return llvm::wasm::WASM_SYMBOL_TYPE_FUNCTION;
case Symbol::DefinedDataKind:
case Symbol::UndefinedDataKind:
return llvm::wasm::WASM_SYMBOL_TYPE_DATA;
case Symbol::DefinedGlobalKind:
case Symbol::UndefinedGlobalKind:
return llvm::wasm::WASM_SYMBOL_TYPE_GLOBAL;
default:
llvm_unreachable("invalid symbol kind");
}
}
bool Symbol::hasOutputIndex() const {
if (auto *F = dyn_cast<DefinedFunction>(this))
if (F->Function)
return F->Function->hasOutputIndex();
if (auto *G = dyn_cast<DefinedGlobal>(this))
if (G->Global)
return G->Global->hasOutputIndex();
return OutputIndex != INVALID_INDEX;
}
uint32_t Symbol::getOutputIndex() const {
assert(!isa<DataSymbol>(this));
if (auto *F = dyn_cast<DefinedFunction>(this))
if (F->Function)
return F->Function->getOutputIndex();
if (auto *G = dyn_cast<DefinedGlobal>(this))
if (G->Global)
return G->Global->getOutputIndex();
assert(OutputIndex != INVALID_INDEX);
return OutputIndex;
}
@ -45,13 +70,34 @@ uint32_t Symbol::getOutputIndex() const {
InputChunk *Symbol::getChunk() const {
if (auto *F = dyn_cast<DefinedFunction>(this))
return F->Function;
if (auto *G = dyn_cast<DefinedData>(this))
return G->Segment;
if (auto *D = dyn_cast<DefinedData>(this))
return D->Segment;
return nullptr;
}
bool Symbol::isLive() const {
if (auto *G = dyn_cast<DefinedGlobal>(this))
return G->Global->Live;
if (InputChunk *C = getChunk())
return C->Live;
// Assume any other kind of symbol is live.
return true;
}
uint32_t Symbol::getOutputSymbolIndex() const {
assert(OutputSymbolIndex != INVALID_INDEX);
return OutputSymbolIndex;
}
void Symbol::setOutputSymbolIndex(uint32_t Index) {
DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index << "\n");
assert(OutputSymbolIndex == INVALID_INDEX);
OutputSymbolIndex = Index;
}
void Symbol::setOutputIndex(uint32_t Index) {
DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n");
assert(!isa<DataSymbol>(this));
assert(OutputIndex == INVALID_INDEX);
OutputIndex = Index;
}
@ -111,14 +157,31 @@ DefinedFunction::DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
uint32_t DefinedData::getVirtualAddress() const {
DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
return Segment ? Segment->translateVA(VirtualAddress) : VirtualAddress;
return Segment ? Segment->translateVA(Offset) : Offset;
}
void DefinedData::setVirtualAddress(uint32_t Value) {
DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
VirtualAddress = Value;
assert(!Segment);
Offset = Value;
}
uint32_t DefinedData::getOutputSegmentOffset() const {
DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
return Segment->OutputSegmentOffset + Offset;
}
uint32_t DefinedData::getOutputSegmentIndex() const {
DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
return Segment->getOutputSegment()->Index;
}
DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
InputGlobal *Global)
: GlobalSymbol(Name, DefinedGlobalKind, Flags, File,
Global ? &Global->getType() : nullptr),
Global(Global) {}
std::string lld::toString(const wasm::Symbol &Sym) {
if (Config->Demangle)
if (Optional<std::string> S = demangleItanium(Sym.getName()))
@ -132,12 +195,28 @@ std::string lld::toString(wasm::Symbol::Kind Kind) {
return "DefinedFunction";
case wasm::Symbol::DefinedDataKind:
return "DefinedData";
case wasm::Symbol::DefinedGlobalKind:
return "DefinedGlobal";
case wasm::Symbol::UndefinedFunctionKind:
return "UndefinedFunction";
case wasm::Symbol::UndefinedDataKind:
return "UndefinedData";
case wasm::Symbol::UndefinedGlobalKind:
return "UndefinedGlobal";
case wasm::Symbol::LazyKind:
return "LazyKind";
}
llvm_unreachable("Invalid symbol kind!");
llvm_unreachable("invalid symbol kind");
}
std::string lld::toString(WasmSymbolType Type) {
switch (Type) {
case llvm::wasm::WASM_SYMBOL_TYPE_FUNCTION:
return "Function";
case llvm::wasm::WASM_SYMBOL_TYPE_DATA:
return "Data";
case llvm::wasm::WASM_SYMBOL_TYPE_GLOBAL:
return "Global";
}
llvm_unreachable("invalid symbol type");
}

View File

@ -15,7 +15,11 @@
#include "llvm/Object/Wasm.h"
using llvm::object::Archive;
using llvm::object::WasmSymbol;
using llvm::wasm::WasmSignature;
using llvm::wasm::WasmGlobal;
using llvm::wasm::WasmGlobalType;
using llvm::wasm::WasmSymbolType;
namespace lld {
namespace wasm {
@ -24,6 +28,7 @@ class InputFile;
class InputChunk;
class InputSegment;
class InputFunction;
class InputGlobal;
#define INVALID_INDEX UINT32_MAX
@ -33,12 +38,14 @@ public:
enum Kind {
DefinedFunctionKind,
DefinedDataKind,
DefinedGlobalKind,
LazyKind,
UndefinedFunctionKind,
UndefinedDataKind,
UndefinedGlobalKind,
LastDefinedKind = DefinedDataKind,
LastDefinedKind = DefinedGlobalKind,
InvalidKind,
};
@ -47,8 +54,8 @@ public:
bool isLazy() const { return SymbolKind == LazyKind; }
bool isDefined() const { return SymbolKind <= LastDefinedKind; }
bool isUndefined() const {
return SymbolKind == UndefinedDataKind ||
SymbolKind == UndefinedFunctionKind;
return SymbolKind == UndefinedFunctionKind ||
SymbolKind == UndefinedDataKind || SymbolKind == UndefinedGlobalKind;
}
bool isLocal() const;
bool isWeak() const;
@ -59,8 +66,12 @@ public:
// Returns the file from which this symbol was created.
InputFile *getFile() const { return File; }
InputChunk *getChunk() const;
// Indicates that this symbol will be included in the final image.
bool isLive() const;
void setHidden(bool IsHidden);
uint32_t getOutputIndex() const;
@ -68,10 +79,18 @@ public:
// Returns true if an output index has been set for this symbol
bool hasOutputIndex() const;
// Set the output index of the symbol (in the function or global index
// space of the output object.
// Set the output index of the symbol, in the Wasm index space of the output
// object - that is, for defined symbols only, its position in the list of
// Wasm imports+code for functions, imports+globals for globals.
void setOutputIndex(uint32_t Index);
// Get/set the output symbol index, in the Symbol index space. This is
// only used for relocatable output.
uint32_t getOutputSymbolIndex() const;
void setOutputSymbolIndex(uint32_t Index);
WasmSymbolType getWasmType() const;
protected:
Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
: Name(Name), SymbolKind(K), Flags(Flags), File(F) {}
@ -81,6 +100,7 @@ protected:
uint32_t Flags;
InputFile *File;
uint32_t OutputIndex = INVALID_INDEX;
uint32_t OutputSymbolIndex = INVALID_INDEX;
};
class FunctionSymbol : public Symbol {
@ -112,9 +132,11 @@ protected:
class DefinedFunction : public FunctionSymbol {
public:
// Primary constructor for file-defined functions.
DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
InputFunction *Function);
// Second constructor used when creating synthetic functions.
DefinedFunction(StringRef Name, uint32_t Flags, const WasmSignature *Type)
: FunctionSymbol(Name, DefinedFunctionKind, Flags, nullptr, Type) {}
@ -149,22 +171,32 @@ protected:
class DefinedData : public DataSymbol {
public:
DefinedData(StringRef Name, uint32_t Flags, InputFile *F = nullptr,
InputSegment *Segment = nullptr, uint32_t Address = 0)
// Constructor for for regular data symbols originating from input files.
DefinedData(StringRef Name, uint32_t Flags, InputFile *F,
InputSegment *Segment, uint32_t Offset, uint32_t Size)
: DataSymbol(Name, DefinedDataKind, Flags, F), Segment(Segment),
VirtualAddress(Address) {}
Offset(Offset), Size(Size) {}
static bool classof(const Symbol *S) {
return S->kind() == DefinedDataKind;
}
// Constructor for linker synthetic data symbols.
DefinedData(StringRef Name, uint32_t Flags)
: DataSymbol(Name, DefinedDataKind, Flags, nullptr) {}
static bool classof(const Symbol *S) { return S->kind() == DefinedDataKind; }
// Returns the output virtual address of a defined data symbol.
uint32_t getVirtualAddress() const;
void setVirtualAddress(uint32_t VA);
InputSegment *Segment;
// Returns the offset of a defined data symbol within its OutputSegment.
uint32_t getOutputSegmentOffset() const;
uint32_t getOutputSegmentIndex() const;
uint32_t getSize() const { return Size; }
InputSegment *Segment = nullptr;
protected:
uint32_t VirtualAddress;
uint32_t Offset = 0;
uint32_t Size = 0;
};
class UndefinedData : public DataSymbol {
@ -176,6 +208,47 @@ public:
}
};
class GlobalSymbol : public Symbol {
public:
static bool classof(const Symbol *S) {
return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind;
}
const WasmGlobalType *getGlobalType() const { return GlobalType; }
protected:
GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
const WasmGlobalType *GlobalType)
: Symbol(Name, K, Flags, F), GlobalType(GlobalType) {}
// Explicit function type, needed for undefined or synthetic functions only.
// For regular defined globals this information comes from the InputChunk.
const WasmGlobalType *GlobalType;
};
class DefinedGlobal : public GlobalSymbol {
public:
DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
InputGlobal *Global);
static bool classof(const Symbol *S) {
return S->kind() == DefinedGlobalKind;
}
InputGlobal *Global;
};
class UndefinedGlobal : public GlobalSymbol {
public:
UndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File = nullptr,
const WasmGlobalType *Type = nullptr)
: GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, Type) {}
static bool classof(const Symbol *S) {
return S->kind() == UndefinedGlobalKind;
}
};
class LazySymbol : public Symbol {
public:
LazySymbol(StringRef Name, InputFile *File, const Archive::Symbol &Sym)
@ -194,7 +267,7 @@ struct WasmSym {
// __stack_pointer
// Global that holds the address of the top of the explicit value stack in
// linear memory.
static DefinedData *StackPointer;
static DefinedGlobal *StackPointer;
// __data_end
// Symbol marking the end of the data and bss.
@ -221,9 +294,11 @@ struct WasmSym {
union SymbolUnion {
alignas(DefinedFunction) char A[sizeof(DefinedFunction)];
alignas(DefinedData) char B[sizeof(DefinedData)];
alignas(LazySymbol) char C[sizeof(LazySymbol)];
alignas(UndefinedFunction) char D[sizeof(UndefinedFunction)];
alignas(UndefinedData) char E[sizeof(UndefinedFunction)];
alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)];
alignas(LazySymbol) char D[sizeof(LazySymbol)];
alignas(UndefinedFunction) char E[sizeof(UndefinedFunction)];
alignas(UndefinedData) char F[sizeof(UndefinedData)];
alignas(UndefinedGlobal) char G[sizeof(UndefinedGlobal)];
};
template <typename T, typename... ArgT>
@ -243,6 +318,7 @@ T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
// Returns a symbol name for an error message.
std::string toString(const wasm::Symbol &Sym);
std::string toString(wasm::Symbol::Kind Kind);
std::string toString(WasmSymbolType Type);
} // namespace lld

View File

@ -10,6 +10,7 @@
#include "Writer.h"
#include "Config.h"
#include "InputChunks.h"
#include "InputGlobal.h"
#include "OutputSections.h"
#include "OutputSegment.h"
#include "SymbolTable.h"
@ -18,6 +19,7 @@
#include "lld/Common/Memory.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
@ -62,10 +64,11 @@ struct WasmSignatureDenseMapInfo {
}
};
// A Wasm export to be written into the export section.
struct WasmExportEntry {
// An init entry to be written to either the synthetic init func or the
// linking metadata.
struct WasmInitEntry {
const Symbol *Sym;
StringRef FieldName; // may not match the Symbol name
uint32_t Priority;
};
// The writer writes a SymbolTable result to a file.
@ -78,11 +81,13 @@ private:
uint32_t lookupType(const WasmSignature &Sig);
uint32_t registerType(const WasmSignature &Sig);
void createCtorFunction();
void calculateInitFunctions();
void assignIndexes();
void calculateImports();
void calculateExports();
void assignSymtab();
void calculateTypes();
void createOutputSegments();
void layoutMemory();
@ -118,13 +123,16 @@ private:
std::vector<const WasmSignature *> Types;
DenseMap<WasmSignature, int32_t, WasmSignatureDenseMapInfo> TypeIndices;
std::vector<const FunctionSymbol *> ImportedFunctions;
std::vector<const DataSymbol *> ImportedGlobals;
std::vector<WasmExportEntry> ExportedSymbols;
std::vector<const DefinedData *> DefinedDataSymbols;
std::vector<const Symbol *> ImportedSymbols;
unsigned NumImportedFunctions = 0;
unsigned NumImportedGlobals = 0;
std::vector<Symbol *> ExportedSymbols;
std::vector<const DefinedData *> DefinedFakeGlobals;
std::vector<InputGlobal *> InputGlobals;
std::vector<InputFunction *> InputFunctions;
std::vector<const FunctionSymbol *> IndirectFunctions;
std::vector<WasmInitFunc> InitFunctions;
std::vector<const Symbol *> SymtabEntries;
std::vector<WasmInitEntry> InitFunctions;
// Elements that are used to construct the final output
std::string Header;
@ -150,7 +158,7 @@ static void debugPrint(const char *fmt, ...) {
}
void Writer::createImportSection() {
uint32_t NumImports = ImportedFunctions.size() + ImportedGlobals.size();
uint32_t NumImports = ImportedSymbols.size();
if (Config->ImportMemory)
++NumImports;
@ -162,15 +170,6 @@ void Writer::createImportSection() {
writeUleb128(OS, NumImports, "import count");
for (const FunctionSymbol *Sym : ImportedFunctions) {
WasmImport Import;
Import.Module = "env";
Import.Field = Sym->getName();
Import.Kind = WASM_EXTERNAL_FUNCTION;
Import.SigIndex = lookupType(*Sym->getFunctionType());
writeImport(OS, Import);
}
if (Config->ImportMemory) {
WasmImport Import;
Import.Module = "env";
@ -181,13 +180,18 @@ void Writer::createImportSection() {
writeImport(OS, Import);
}
for (const Symbol *Sym : ImportedGlobals) {
for (const Symbol *Sym : ImportedSymbols) {
WasmImport Import;
Import.Module = "env";
Import.Field = Sym->getName();
Import.Kind = WASM_EXTERNAL_GLOBAL;
Import.Global.Mutable = false;
Import.Global.Type = WASM_TYPE_I32;
if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
Import.Kind = WASM_EXTERNAL_FUNCTION;
Import.SigIndex = lookupType(*FunctionSym->getFunctionType());
} else {
auto *GlobalSym = cast<GlobalSymbol>(Sym);
Import.Kind = WASM_EXTERNAL_GLOBAL;
Import.Global = *GlobalSym->getGlobalType();
}
writeImport(OS, Import);
}
}
@ -225,17 +229,19 @@ void Writer::createMemorySection() {
}
void Writer::createGlobalSection() {
if (DefinedDataSymbols.empty())
unsigned NumGlobals = InputGlobals.size() + DefinedFakeGlobals.size();
if (NumGlobals == 0)
return;
SyntheticSection *Section = createSyntheticSection(WASM_SEC_GLOBAL);
raw_ostream &OS = Section->getStream();
writeUleb128(OS, DefinedDataSymbols.size(), "global count");
for (const DefinedData *Sym : DefinedDataSymbols) {
writeUleb128(OS, NumGlobals, "global count");
for (const InputGlobal *G : InputGlobals)
writeGlobal(OS, G->Global);
for (const DefinedData *Sym : DefinedFakeGlobals) {
WasmGlobal Global;
Global.Type.Type = WASM_TYPE_I32;
Global.Type.Mutable = Sym == WasmSym::StackPointer;
Global.Type = {WASM_TYPE_I32, false};
Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
Global.InitExpr.Value.Int32 = Sym->getVirtualAddress();
writeGlobal(OS, Global);
@ -283,15 +289,23 @@ void Writer::createExportSection() {
writeExport(OS, MemoryExport);
}
for (const WasmExportEntry &E : ExportedSymbols) {
DEBUG(dbgs() << "Export: " << E.Sym->getName() << "\n");
unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size();
for (const Symbol *Sym : ExportedSymbols) {
DEBUG(dbgs() << "Export: " << Sym->getName() << "\n");
WasmExport Export;
Export.Name = E.FieldName;
Export.Index = E.Sym->getOutputIndex();
if (isa<FunctionSymbol>(E.Sym))
Export.Name = Sym->getName();
if (isa<FunctionSymbol>(Sym)) {
Export.Index = Sym->getOutputIndex();
Export.Kind = WASM_EXTERNAL_FUNCTION;
else
} else if (isa<GlobalSymbol>(Sym)) {
Export.Index = Sym->getOutputIndex();
Export.Kind = WASM_EXTERNAL_GLOBAL;
} else if (isa<DataSymbol>(Sym)) {
Export.Index = FakeGlobalIndex++;
Export.Kind = WASM_EXTERNAL_GLOBAL;
} else {
llvm_unreachable("unexpected symbol type");
}
writeExport(OS, Export);
}
}
@ -383,28 +397,39 @@ void Writer::createLinkingSection() {
if (!Config->Relocatable)
return;
std::vector<std::pair<StringRef, uint32_t>> SymbolInfo;
auto addSymInfo = [&](const Symbol *Sym, StringRef ExternalName) {
uint32_t Flags =
(Sym->isLocal() ? WASM_SYMBOL_BINDING_LOCAL :
Sym->isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0) |
(Sym->isHidden() ? WASM_SYMBOL_VISIBILITY_HIDDEN : 0);
if (Flags)
SymbolInfo.emplace_back(ExternalName, Flags);
};
// (Imports can't have internal linkage, their names don't need to be budged.)
for (const Symbol *Sym : ImportedFunctions)
addSymInfo(Sym, Sym->getName());
for (const Symbol *Sym : ImportedGlobals)
addSymInfo(Sym, Sym->getName());
for (const WasmExportEntry &E : ExportedSymbols)
addSymInfo(E.Sym, E.FieldName);
if (!SymbolInfo.empty()) {
SubSection SubSection(WASM_SYMBOL_INFO);
writeUleb128(SubSection.getStream(), SymbolInfo.size(), "num sym info");
for (auto Pair: SymbolInfo) {
writeStr(SubSection.getStream(), Pair.first, "sym name");
writeUleb128(SubSection.getStream(), Pair.second, "sym flags");
if (!SymtabEntries.empty()) {
SubSection SubSection(WASM_SYMBOL_TABLE);
writeUleb128(SubSection.getStream(), SymtabEntries.size(), "num symbols");
for (const Symbol *Sym : SymtabEntries) {
assert(Sym->isDefined() || Sym->isUndefined());
WasmSymbolType Kind = Sym->getWasmType();
uint32_t Flags = Sym->isLocal() ? WASM_SYMBOL_BINDING_LOCAL : 0;
if (Sym->isWeak())
Flags |= WASM_SYMBOL_BINDING_WEAK;
if (Sym->isHidden())
Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
if (Sym->isUndefined())
Flags |= WASM_SYMBOL_UNDEFINED;
writeUleb128(SubSection.getStream(), Kind, "sym kind");
writeUleb128(SubSection.getStream(), Flags, "sym flags");
switch (Kind) {
case llvm::wasm::WASM_SYMBOL_TYPE_FUNCTION:
case llvm::wasm::WASM_SYMBOL_TYPE_GLOBAL:
writeUleb128(SubSection.getStream(), Sym->getOutputIndex(), "index");
if (Sym->isDefined())
writeStr(SubSection.getStream(), Sym->getName(), "sym name");
break;
case llvm::wasm::WASM_SYMBOL_TYPE_DATA:
writeStr(SubSection.getStream(), Sym->getName(), "sym name");
if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
writeUleb128(SubSection.getStream(), DataSym->getOutputSegmentIndex(),
"index");
writeUleb128(SubSection.getStream(),
DataSym->getOutputSegmentOffset(), "data offset");
writeUleb128(SubSection.getStream(), DataSym->getSize(), "data size");
}
break;
}
}
SubSection.finalizeContents();
SubSection.writeToStream(OS);
@ -426,9 +451,10 @@ void Writer::createLinkingSection() {
SubSection SubSection(WASM_INIT_FUNCS);
writeUleb128(SubSection.getStream(), InitFunctions.size(),
"num init functions");
for (const WasmInitFunc &F : InitFunctions) {
for (const WasmInitEntry &F : InitFunctions) {
writeUleb128(SubSection.getStream(), F.Priority, "priority");
writeUleb128(SubSection.getStream(), F.FunctionIndex, "function index");
writeUleb128(SubSection.getStream(), F.Sym->getOutputSymbolIndex(),
"function index");
}
SubSection.finalizeContents();
SubSection.writeToStream(OS);
@ -475,7 +501,7 @@ void Writer::createLinkingSection() {
// Create the custom "name" section containing debug symbol names.
void Writer::createNameSection() {
unsigned NumNames = ImportedFunctions.size();
unsigned NumNames = NumImportedFunctions;
for (const InputFunction *F : InputFunctions)
if (!F->getName().empty())
++NumNames;
@ -489,10 +515,12 @@ void Writer::createNameSection() {
raw_ostream &OS = FunctionSubsection.getStream();
writeUleb128(OS, NumNames, "name count");
// Names must appear in function index order. As it happens ImportedFunctions
// and InputFunctions are numbers in order with imported functions coming
// Names must appear in function index order. As it happens ImportedSymbols
// and InputFunctions are numbered in order with imported functions coming
// first.
for (const Symbol *S : ImportedFunctions) {
for (const Symbol *S : ImportedSymbols) {
if (!isa<FunctionSymbol>(S))
continue;
writeUleb128(OS, S->getOutputIndex(), "import index");
writeStr(OS, S->getName(), "symbol name");
}
@ -562,8 +590,9 @@ void Writer::layoutMemory() {
debugPrint("mem: stack size = %d\n", Config->ZStackSize);
debugPrint("mem: stack base = %d\n", MemoryPtr);
MemoryPtr += Config->ZStackSize;
WasmSym::StackPointer->setVirtualAddress(MemoryPtr);
WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
debugPrint("mem: stack top = %d\n", MemoryPtr);
// Set `__heap_base` to directly follow the end of the stack. We don't
// allocate any heap memory up front, but instead really on the malloc/brk
// implementation growing the memory at runtime.
@ -614,69 +643,85 @@ void Writer::createSections() {
void Writer::calculateImports() {
for (Symbol *Sym : Symtab->getSymbols()) {
if (!Sym->isUndefined() || (Sym->isWeak() && !Config->Relocatable))
if (!Sym->isUndefined())
continue;
if (isa<DataSymbol>(Sym))
continue;
if (Sym->isWeak() && !Config->Relocatable)
continue;
if (auto *F = dyn_cast<FunctionSymbol>(Sym)) {
F->setOutputIndex(ImportedFunctions.size());
ImportedFunctions.push_back(F);
} else if (auto *G = dyn_cast<DataSymbol>(Sym)) {
G->setOutputIndex(ImportedGlobals.size());
ImportedGlobals.push_back(G);
}
DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
Sym->setOutputIndex(ImportedSymbols.size());
ImportedSymbols.emplace_back(Sym);
if (isa<FunctionSymbol>(Sym))
++NumImportedFunctions;
else
++NumImportedGlobals;
}
}
void Writer::calculateExports() {
bool ExportHidden = Config->Relocatable;
StringSet<> UsedNames;
if (Config->Relocatable)
return;
auto BudgeLocalName = [&](const Symbol *Sym) {
StringRef SymName = Sym->getName();
// We can't budge non-local names.
if (!Sym->isLocal())
return SymName;
// We must budge local names that have a collision with a symbol that we
// haven't yet processed.
if (!Symtab->find(SymName) && UsedNames.insert(SymName).second)
return SymName;
for (unsigned I = 1; ; ++I) {
std::string NameBuf = (SymName + "." + Twine(I)).str();
if (!UsedNames.count(NameBuf)) {
StringRef Name = Saver.save(NameBuf);
UsedNames.insert(Name); // Insert must use safe StringRef from save()
return Name;
}
auto ExportSym = [&](Symbol *Sym) {
if (!Sym->isDefined())
return;
if (Sym->isHidden() || Sym->isLocal())
return;
if (!Sym->isLive())
return;
DEBUG(dbgs() << "exporting sym: " << Sym->getName() << "\n");
if (auto *D = dyn_cast<DefinedData>(Sym)) {
// TODO Remove this check here; for non-relocatable output we actually
// used only to create fake-global exports for the synthetic symbols. Fix
// this in a future commit
if (Sym != WasmSym::DataEnd && Sym != WasmSym::HeapBase)
return;
DefinedFakeGlobals.emplace_back(D);
}
ExportedSymbols.emplace_back(Sym);
};
if (WasmSym::CallCtors && (!WasmSym::CallCtors->isHidden() || ExportHidden))
ExportedSymbols.emplace_back(
WasmExportEntry{WasmSym::CallCtors, WasmSym::CallCtors->getName()});
// TODO The two loops below should be replaced with this single loop, with
// ExportSym inlined:
// for (Symbol *Sym : Symtab->getSymbols())
// ExportSym(Sym);
// Making that change would reorder the output though, so it should be done as
// a separate commit.
for (ObjFile *File : Symtab->ObjectFiles)
for (Symbol *Sym : File->getSymbols())
if (File == Sym->getFile())
ExportSym(Sym);
for (Symbol *Sym : Symtab->getSymbols())
if (Sym->getFile() == nullptr)
ExportSym(Sym);
}
void Writer::assignSymtab() {
if (!Config->Relocatable)
return;
unsigned SymbolIndex = SymtabEntries.size();
for (ObjFile *File : Symtab->ObjectFiles) {
DEBUG(dbgs() << "Symtab entries: " << File->getName() << "\n");
for (Symbol *Sym : File->getSymbols()) {
if (!Sym->isDefined() || File != Sym->getFile())
if (Sym->getFile() != File)
continue;
if (!isa<FunctionSymbol>(Sym))
continue;
if (!Sym->getChunk()->Live)
continue;
if ((Sym->isHidden() || Sym->isLocal()) && !ExportHidden)
continue;
ExportedSymbols.emplace_back(WasmExportEntry{Sym, BudgeLocalName(Sym)});
if (!Sym->isLive())
return;
Sym->setOutputSymbolIndex(SymbolIndex++);
SymtabEntries.emplace_back(Sym);
}
}
for (const Symbol *Sym : DefinedDataSymbols) {
// Can't export the SP right now because its mutable, and mutuable globals
// are yet supported in the official binary format.
// TODO(sbc): Remove this if/when the "mutable global" proposal is accepted.
if (Sym == WasmSym::StackPointer)
continue;
ExportedSymbols.emplace_back(WasmExportEntry{Sym, BudgeLocalName(Sym)});
}
// For the moment, relocatable output doesn't contain any synthetic functions,
// so no need to look through the Symtab for symbols not referenced by
// Symtab->ObjectFiles.
}
uint32_t Writer::lookupType(const WasmSignature &Sig) {
@ -710,45 +755,16 @@ void Writer::calculateTypes() {
File->TypeMap[I] = registerType(Types[I]);
}
for (const FunctionSymbol *Sym : ImportedFunctions)
registerType(*Sym->getFunctionType());
for (const Symbol *Sym : ImportedSymbols)
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
registerType(*F->getFunctionType());
for (const InputFunction *F : InputFunctions)
registerType(F->Signature);
}
void Writer::assignIndexes() {
uint32_t GlobalIndex = ImportedGlobals.size() + DefinedDataSymbols.size();
uint32_t FunctionIndex = ImportedFunctions.size() + InputFunctions.size();
auto AddDefinedData = [&](DefinedData *Sym) {
if (Sym) {
DefinedDataSymbols.emplace_back(Sym);
Sym->setOutputIndex(GlobalIndex++);
}
};
AddDefinedData(WasmSym::StackPointer);
AddDefinedData(WasmSym::HeapBase);
AddDefinedData(WasmSym::DataEnd);
if (Config->Relocatable)
DefinedDataSymbols.reserve(Symtab->getSymbols().size());
uint32_t TableIndex = kInitialTableOffset;
if (Config->Relocatable) {
for (ObjFile *File : Symtab->ObjectFiles) {
DEBUG(dbgs() << "Globals: " << File->getName() << "\n");
for (Symbol *Sym : File->getSymbols()) {
// Create wasm globals for data symbols defined in this file
if (File != Sym->getFile())
continue;
if (auto *G = dyn_cast<DefinedData>(Sym))
AddDefinedData(G);
}
}
}
uint32_t FunctionIndex = NumImportedFunctions + InputFunctions.size();
for (ObjFile *File : Symtab->ObjectFiles) {
DEBUG(dbgs() << "Functions: " << File->getName() << "\n");
for (InputFunction *Func : File->Functions) {
@ -759,12 +775,13 @@ void Writer::assignIndexes() {
}
}
uint32_t TableIndex = kInitialTableOffset;
auto HandleRelocs = [&](InputChunk *Chunk) {
if (!Chunk->Live)
return;
ObjFile *File = Chunk->File;
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
for (const WasmRelocation& Reloc : Chunk->getRelocations()) {
for (const WasmRelocation &Reloc : Chunk->getRelocations()) {
if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 ||
Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB) {
FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index);
@ -773,19 +790,44 @@ void Writer::assignIndexes() {
Sym->setTableIndex(TableIndex++);
IndirectFunctions.emplace_back(Sym);
} else if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) {
// Mark target type as live
File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]);
File->TypeIsUsed[Reloc.Index] = true;
} else if (Reloc.Type == R_WEBASSEMBLY_GLOBAL_INDEX_LEB) {
// Mark target global as live
GlobalSymbol *Sym = File->getGlobalSymbol(Reloc.Index);
if (auto *G = dyn_cast<DefinedGlobal>(Sym)) {
DEBUG(dbgs() << "marking global live: " << Sym->getName() << "\n");
G->Global->Live = true;
}
}
}
};
for (ObjFile *File : Symtab->ObjectFiles) {
DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n");
for (InputChunk *Chunk : File->Functions)
HandleRelocs(Chunk);
for (InputChunk *Chunk : File->Segments)
HandleRelocs(Chunk);
}
for (InputChunk* Chunk : File->Functions)
HandleRelocs(Chunk);
for (InputChunk* Chunk : File->Segments)
HandleRelocs(Chunk);
uint32_t GlobalIndex = NumImportedGlobals + InputGlobals.size();
auto AddDefinedGlobal = [&](InputGlobal *Global) {
if (Global->Live) {
DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n");
Global->setOutputIndex(GlobalIndex++);
InputGlobals.push_back(Global);
}
};
if (WasmSym::StackPointer)
AddDefinedGlobal(WasmSym::StackPointer->Global);
for (ObjFile *File : Symtab->ObjectFiles) {
DEBUG(dbgs() << "Globals: " << File->getName() << "\n");
for (InputGlobal *Global : File->Globals)
AddDefinedGlobal(Global);
}
}
@ -814,7 +856,7 @@ void Writer::createOutputSegments() {
OutputSegment *&S = SegmentMap[Name];
if (S == nullptr) {
DEBUG(dbgs() << "new segment: " << Name << "\n");
S = make<OutputSegment>(Name);
S = make<OutputSegment>(Name, Segments.size());
Segments.push_back(S);
}
S->addInputSegment(Segment);
@ -829,18 +871,18 @@ 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() + InputFunctions.size();
uint32_t FunctionIndex = NumImportedFunctions + InputFunctions.size();
WasmSym::CallCtors->setOutputIndex(FunctionIndex);
// First write the body bytes to a string.
std::string FunctionBody;
static WasmSignature Signature = {{}, WASM_TYPE_NORESULT};
const WasmSignature *Signature = WasmSym::CallCtors->getFunctionType();
{
raw_string_ostream OS(FunctionBody);
writeUleb128(OS, 0, "num locals");
for (const WasmInitFunc &F : InitFunctions) {
for (const WasmInitEntry &F : InitFunctions) {
writeU8(OS, OPCODE_CALL, "CALL");
writeUleb128(OS, F.FunctionIndex, "function index");
writeUleb128(OS, F.Sym->getOutputIndex(), "function index");
}
writeU8(OS, OPCODE_END, "END");
}
@ -853,9 +895,11 @@ void Writer::createCtorFunction() {
ArrayRef<uint8_t> BodyArray(
reinterpret_cast<const uint8_t *>(CtorFunctionBody.data()),
CtorFunctionBody.size());
SyntheticFunction *F = make<SyntheticFunction>(Signature, BodyArray,
SyntheticFunction *F = make<SyntheticFunction>(*Signature, BodyArray,
WasmSym::CallCtors->getName());
F->setOutputIndex(FunctionIndex);
F->Live = true;
WasmSym::CallCtors->Function = F;
InputFunctions.emplace_back(F);
}
@ -867,13 +911,13 @@ void Writer::calculateInitFunctions() {
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)});
InitFunctions.emplace_back(
WasmInitEntry{File->getFunctionSymbol(F.Symbol), F.Priority});
}
// Sort in order of priority (lowest first) so that they are called
// in the correct order.
std::stable_sort(InitFunctions.begin(), InitFunctions.end(),
[](const WasmInitFunc &L, const WasmInitFunc &R) {
[](const WasmInitEntry &L, const WasmInitEntry &R) {
return L.Priority < R.Priority;
});
}
@ -883,29 +927,28 @@ void Writer::run() {
calculateImports();
log("-- assignIndexes");
assignIndexes();
log("-- calculateExports");
calculateExports();
log("-- calculateInitFunctions");
calculateInitFunctions();
if (!Config->Relocatable)
createCtorFunction();
log("-- calculateTypes");
calculateTypes();
log("-- layoutMemory");
layoutMemory();
log("-- calculateExports");
calculateExports();
log("-- assignSymtab");
assignSymtab();
if (errorHandler().Verbose) {
log("Defined Functions: " + Twine(InputFunctions.size()));
log("Defined Data Syms: " + Twine(DefinedDataSymbols.size()));
log("Function Imports : " + Twine(ImportedFunctions.size()));
log("Global Imports : " + Twine(ImportedGlobals.size()));
log("Total Imports : " +
Twine(ImportedFunctions.size() + ImportedGlobals.size()));
log("Defined Globals : " + Twine(InputGlobals.size()));
log("Function Imports : " + Twine(NumImportedFunctions));
log("Global Imports : " + Twine(NumImportedGlobals));
for (ObjFile *File : Symtab->ObjectFiles)
File->dumpInfo();
}
log("-- layoutMemory");
layoutMemory();
createHeader();
log("-- createSections");
createSections();

View File

@ -190,3 +190,10 @@ std::string lld::toString(const WasmSignature &Sig) {
S += toString(static_cast<ValType>(Sig.ReturnType));
return S.str();
}
std::string lld::toString(const WasmGlobalType &Sig) {
std::string S = toString(static_cast<ValType>(Sig.Type));
if (Sig.Mutable)
return "mutable " + S;
return S;
}

View File

@ -28,6 +28,17 @@ inline bool operator!=(const llvm::wasm::WasmSignature &LHS,
return !(LHS == RHS);
}
// Used for general comparison
inline bool operator==(const llvm::wasm::WasmGlobalType &LHS,
const llvm::wasm::WasmGlobalType &RHS) {
return LHS.Type == RHS.Type && LHS.Mutable == RHS.Mutable;
}
inline bool operator!=(const llvm::wasm::WasmGlobalType &LHS,
const llvm::wasm::WasmGlobalType &RHS) {
return !(LHS == RHS);
}
namespace lld {
namespace wasm {
@ -65,6 +76,7 @@ void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export);
std::string toString(const llvm::wasm::ValType Type);
std::string toString(const llvm::wasm::WasmSignature &Sig);
std::string toString(const llvm::wasm::WasmGlobalType &Sig);
} // namespace lld