[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:
parent
6c899ba6de
commit
9310297438
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue