# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s # RUN: wasm-ld --experimental-pic -shared -o %t.wasm %t.o # RUN: obj2yaml %t.wasm | FileCheck %s # RUN: llvm-objdump --disassemble-symbols=__wasm_call_ctors,__wasm_apply_data_relocs --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s --check-prefixes DIS .functype func_external () -> () # Linker-synthesized globals .globaltype __stack_pointer, i32 .globaltype __table_base, i32, immutable .globaltype __memory_base, i32, immutable .section .data.data,"",@ data: .p2align 2 .int32 2 .size data, 4 .section .data.indirect_func_external,"",@ indirect_func_external: .int32 func_external .size indirect_func_external, 4 .section .data.indirect_func,"",@ indirect_func: .int32 foo .size indirect_func, 4 # 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: .int32 data_external .size data_addr_external, 4 # .. 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, ptr @data, align 4 # %1 = load ptr, ptr @indirect_func, align 4 # call i32 %1() # ret i32 %0 .functype foo () -> (i32) .local i32, i32 global.get __stack_pointer i32.const 16 i32.sub local.tee 0 global.set __stack_pointer global.get __memory_base i32.const data@MBREL i32.add i32.load 0 local.set 1 global.get indirect_func@GOT i32.load 0 call_indirect () -> (i32) drop local.get 0 i32.const 16 i32.add global.set __stack_pointer local.get 1 end_function get_func_address: .functype get_func_address () -> (i32) global.get func_external@GOT end_function get_data_address: .functype get_data_address () -> (i32) 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_SLEB .functype get_local_func_address () -> (i32) global.get __table_base i32.const get_func_address@TBREL i32.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: 24 # 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: 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: I32 # CHECK-NEXT: GlobalMutable: true # CHECK-NEXT: - Module: env # CHECK-NEXT: Field: __memory_base # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 # CHECK-NEXT: GlobalMutable: false # CHECK-NEXT: - Module: env # CHECK-NEXT: Field: __table_base # 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: I32 # CHECK-NEXT: GlobalMutable: true # CHECK-NEXT: - Module: GOT.func # CHECK-NEXT: Field: func_external # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 # CHECK-NEXT: GlobalMutable: true # CHECK-NEXT: - Module: GOT.mem # CHECK-NEXT: Field: data_external # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 # CHECK-NEXT: GlobalMutable: true # CHECK-NEXT: - Module: GOT.mem # CHECK-NEXT: Field: extern_struct # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: GlobalType: I32 # 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: 2 # CHECK-NEXT: Functions: [ 3, 2 ] # check the generated code in __wasm_call_ctors and __wasm_apply_data_relocs functions # DIS: <__wasm_call_ctors>: # DIS-EMPTY: # DIS-NEXT: end # DIS: <__wasm_apply_data_relocs>: # DIS-EMPTY: # DIS-NEXT: i32.const 4 # DIS-NEXT: global.get 1 # DIS-NEXT: i32.add # DIS-NEXT: global.get 4 # DIS-NEXT: i32.store 0 # DIS-NEXT: i32.const 8 # DIS-NEXT: global.get 1 # DIS-NEXT: i32.add # DIS-NEXT: global.get 2 # DIS-NEXT: i32.const 1 # DIS-NEXT: i32.add # DIS-NEXT: i32.store 0 # DIS-NEXT: i32.const 12 # DIS-NEXT: global.get 1 # DIS-NEXT: i32.add # DIS-NEXT: global.get 1 # DIS-NEXT: i32.const 0 # DIS-NEXT: i32.add # DIS-NEXT: i32.store 0 # DIS-NEXT: i32.const 16 # DIS-NEXT: global.get 1 # DIS-NEXT: i32.add # DIS-NEXT: global.get 5 # DIS-NEXT: i32.store 0 # DIS-NEXT: i32.const 20 # DIS-NEXT: global.get 1 # DIS-NEXT: i32.add # DIS-NEXT: global.get 6 # DIS-NEXT: i32.const 4 # DIS-NEXT: i32.add # DIS-NEXT: i32.store 0 # DIS-NEXT: end # 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: '020000000000000001000000000000000000000000000000'