blob: 86d5a521ab3340e4ddedebccd3d1aadbb6cab161 [file] [log] [blame]
# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-unknown -o %t.o %s
# RUN: wasm-ld -mwasm64 --experimental-pic -shared -o %t.wasm %t.o
# RUN: obj2yaml %t.wasm | FileCheck %s
.functype func_external () -> ()
# Linker-synthesized globals
.globaltype __stack_pointer, i64
.globaltype __table_base, i64, immutable
.globaltype __memory_base, i64, immutable
.section .data.data,"",@
data:
.p2align 2
.int32 2
.size data, 4
.section .data.indirect_func_external,"",@
indirect_func_external:
.int64 func_external
.size indirect_func_external, 8
.section .data.indirect_func,"",@
indirect_func:
.int64 foo
.size indirect_func, 8
# Test data relocations
.section .data.data_addr,"",@
data_addr:
.int32 data
.size data_addr, 4
# .. against external symbols
.section .data.data_addr_external,"",@
data_addr_external:
.int64 data_external
.size data_addr_external, 8
# .. including addends
.section .data.extern_struct_internal_ptr,"",@
extern_struct_internal_ptr:
.int32 extern_struct + 4
.size extern_struct_internal_ptr, 4
# Test use of __stack_pointer
.section .text,"",@
foo:
# %ptr = alloca i32
# %0 = load i32, i32* @data, align 4
# %1 = load i32 ()*, i32 ()** @indirect_func, align 4
# call i32 %1()
# ret i32 %0
.functype foo () -> (i32)
.local i64, i32
global.get __stack_pointer
i64.const 16
i64.sub
local.tee 0
global.set __stack_pointer
global.get __memory_base
i64.const data@MBREL
i64.add
i32.load 0
local.set 1
global.get indirect_func@GOT
i64.load 0
i32.wrap_i64
call_indirect () -> (i32)
drop
local.get 0
i64.const 16
i64.add
global.set __stack_pointer
local.get 1
end_function
get_func_address:
.functype get_func_address () -> (i64)
global.get func_external@GOT
end_function
get_data_address:
.functype get_data_address () -> (i64)
global.get data_external@GOT
end_function
get_local_func_address:
# Verify that a function which is otherwise not address taken *is* added to
# the wasm table with referenced via R_WASM_TABLE_INDEX_REL_SLEB64
.functype get_local_func_address () -> (i64)
global.get __table_base
i64.const get_func_address@TBREL
i64.add
end_function
.globl foo
.globl data
.globl indirect_func
.globl indirect_func_external
.globl data_addr
.globl data_addr_external
.globl extern_struct_internal_ptr
.globl get_data_address
.globl get_func_address
.globl get_local_func_address
.hidden foo
.hidden data
.hidden get_data_address
.hidden get_func_address
# Without this linking will fail because we import __stack_pointer (a mutable
# global).
# TODO(sbc): We probably want a nicer way to specify target_features section
# in assembly.
.section .custom_section.target_features,"",@
.int8 1
.int8 43
.int8 15
.ascii "mutable-globals"
# check for dylink section at start
# CHECK: Sections:
# CHECK-NEXT: - Type: CUSTOM
# CHECK-NEXT: Name: dylink.0
# CHECK-NEXT: MemorySize: 36
# CHECK-NEXT: MemoryAlignment: 2
# CHECK-NEXT: TableSize: 2
# CHECK-NEXT: TableAlignment: 0
# CHECK-NEXT: Needed: []
# CHECK-NEXT: - Type: TYPE
# check for import of __table_base and __memory_base globals
# CHECK: - Type: IMPORT
# CHECK-NEXT: Imports:
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: memory
# CHECK-NEXT: Kind: MEMORY
# CHECK-NEXT: Memory:
# CHECK-NEXT: Flags: [ IS_64 ]
# CHECK-NEXT: Minimum: 0x1
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: __indirect_function_table
# CHECK-NEXT: Kind: TABLE
# CHECK-NEXT: Table:
# CHECK-NEXT: Index: 0
# CHECK-NEXT: ElemType: FUNCREF
# CHECK-NEXT: Limits:
# CHECK-NEXT: Minimum: 0x2
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: __stack_pointer
# CHECK-NEXT: Kind: GLOBAL
# CHECK-NEXT: GlobalType: I64
# CHECK-NEXT: GlobalMutable: true
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: __memory_base
# CHECK-NEXT: Kind: GLOBAL
# CHECK-NEXT: GlobalType: I64
# CHECK-NEXT: GlobalMutable: false
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: __table_base
# CHECK-NEXT: Kind: GLOBAL
# CHECK-NEXT: GlobalType: I64
# CHECK-NEXT: GlobalMutable: false
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: __table_base32
# CHECK-NEXT: Kind: GLOBAL
# CHECK-NEXT: GlobalType: I32
# CHECK-NEXT: GlobalMutable: false
# CHECK-NEXT: - Module: GOT.mem
# CHECK-NEXT: Field: indirect_func
# CHECK-NEXT: Kind: GLOBAL
# CHECK-NEXT: GlobalType: I64
# CHECK-NEXT: GlobalMutable: true
# CHECK-NEXT: - Module: GOT.func
# CHECK-NEXT: Field: func_external
# CHECK-NEXT: Kind: GLOBAL
# CHECK-NEXT: GlobalType: I64
# CHECK-NEXT: GlobalMutable: true
# CHECK-NEXT: - Module: GOT.mem
# CHECK-NEXT: Field: data_external
# CHECK-NEXT: Kind: GLOBAL
# CHECK-NEXT: GlobalType: I64
# CHECK-NEXT: GlobalMutable: true
# CHECK-NEXT: - Module: GOT.mem
# CHECK-NEXT: Field: extern_struct
# CHECK-NEXT: Kind: GLOBAL
# CHECK-NEXT: GlobalType: I64
# CHECK-NEXT: GlobalMutable: true
# CHECK-NEXT: - Type: FUNCTION
# CHECK: - Type: EXPORT
# CHECK-NEXT: Exports:
# CHECK-NEXT: - Name: __wasm_call_ctors
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: Index: 0
# check for elem segment initialized with __table_base global as offset
# CHECK: - Type: ELEM
# CHECK-NEXT: Segments:
# CHECK-NEXT: - Offset:
# CHECK-NEXT: Opcode: GLOBAL_GET
# CHECK-NEXT: Index: 3
# CHECK-NEXT: Functions: [ 3, 2 ]
# check the generated code in __wasm_call_ctors and __wasm_apply_data_relocs functions
# TODO(sbc): Disassemble and verify instructions.
# CHECK: - Type: CODE
# CHECK-NEXT: Functions:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 10010B
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 230142047C23053702002301420C7C230242017C370200230142147C230141006A360200230142187C2306370200230142207C230741046A3602000B
# check the data segment initialized with __memory_base global as offset
# CHECK: - Type: DATA
# CHECK-NEXT: Segments:
# CHECK-NEXT: - SectionOffset: 6
# CHECK-NEXT: InitFlags: 0
# CHECK-NEXT: Offset:
# CHECK-NEXT: Opcode: GLOBAL_GET
# CHECK-NEXT: Index: 1
# CHECK-NEXT: Content: '020000000000000000000000010000000000000000000000000000000000000000000000'