1# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-unknown -o %t.o %s
2# RUN: wasm-ld -mwasm64 --experimental-pic -shared -o %t.wasm %t.o
3# RUN: obj2yaml %t.wasm | FileCheck %s
4# 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
5
6.functype func_external () -> ()
7
8# Linker-synthesized globals
9.globaltype __stack_pointer, i64
10.globaltype	__table_base, i64, immutable
11.globaltype	__memory_base, i64, immutable
12
13.section .data.data,"",@
14data:
15  .p2align 2
16  .int32 2
17  .size data, 4
18
19.section .data.indirect_func_external,"",@
20indirect_func_external:
21  .int64 func_external
22.size indirect_func_external, 8
23
24.section .data.indirect_func,"",@
25indirect_func:
26  .int64 foo
27  .size indirect_func, 8
28
29# Test data relocations
30
31.section .data.data_addr,"",@
32data_addr:
33  .int32 data
34  .size data_addr, 4
35
36# .. against external symbols
37
38.section .data.data_addr_external,"",@
39data_addr_external:
40  .int64 data_external
41  .size data_addr_external, 8
42
43# .. including addends
44
45.section .data.extern_struct_internal_ptr,"",@
46extern_struct_internal_ptr:
47  .int32 extern_struct + 4
48  .size extern_struct_internal_ptr, 4
49
50# Test use of __stack_pointer
51
52.section .text,"",@
53foo:
54  # %ptr = alloca i32
55  # %0 = load i32, i32* @data, align 4
56  # %1 = load i32 ()*, i32 ()** @indirect_func, align 4
57  # call i32 %1()
58  # ret i32 %0
59  .functype foo () -> (i32)
60  .local    i64, i32
61  global.get  __stack_pointer
62  i64.const 16
63  i64.sub
64  local.tee 0
65  global.set  __stack_pointer
66  global.get  __memory_base
67  i64.const data@MBREL
68  i64.add
69  i32.load  0
70  local.set 1
71  global.get  indirect_func@GOT
72  i64.load  0
73  i32.wrap_i64
74  call_indirect  () -> (i32)
75  drop
76  local.get 0
77  i64.const 16
78  i64.add
79  global.set  __stack_pointer
80  local.get 1
81  end_function
82
83get_func_address:
84  .functype get_func_address () -> (i64)
85  global.get func_external@GOT
86  end_function
87
88get_data_address:
89  .functype get_data_address () -> (i64)
90  global.get  data_external@GOT
91  end_function
92
93get_local_func_address:
94  # Verify that a function which is otherwise not address taken *is* added to
95  # the wasm table with referenced via R_WASM_TABLE_INDEX_REL_SLEB64
96  .functype get_local_func_address () -> (i64)
97  global.get  __table_base
98  i64.const get_func_address@TBREL
99  i64.add
100  end_function
101
102.globl foo
103.globl data
104.globl indirect_func
105.globl indirect_func_external
106.globl data_addr
107.globl data_addr_external
108.globl extern_struct_internal_ptr
109.globl get_data_address
110.globl get_func_address
111.globl get_local_func_address
112
113.hidden foo
114.hidden data
115.hidden get_data_address
116.hidden get_func_address
117
118# Without this linking will fail because we import __stack_pointer (a mutable
119# global).
120# TODO(sbc): We probably want a nicer way to specify target_features section
121# in assembly.
122.section .custom_section.target_features,"",@
123.int8 1
124.int8 43
125.int8 15
126.ascii "mutable-globals"
127
128# check for dylink section at start
129
130# CHECK:      Sections:
131# CHECK-NEXT:   - Type:            CUSTOM
132# CHECK-NEXT:     Name:            dylink.0
133# CHECK-NEXT:     MemorySize:      36
134# CHECK-NEXT:     MemoryAlignment: 2
135# CHECK-NEXT:     TableSize:       2
136# CHECK-NEXT:     TableAlignment:  0
137# CHECK-NEXT:     Needed:          []
138# CHECK-NEXT:   - Type:            TYPE
139
140# check for import of __table_base and __memory_base globals
141
142# CHECK:        - Type:            IMPORT
143# CHECK-NEXT:     Imports:
144# CHECK-NEXT:       - Module:          env
145# CHECK-NEXT:         Field:           memory
146# CHECK-NEXT:         Kind:            MEMORY
147# CHECK-NEXT:         Memory:
148# CHECK-NEXT:           Flags:         [ IS_64 ]
149# CHECK-NEXT:           Minimum:       0x1
150# CHECK-NEXT:       - Module:          env
151# CHECK-NEXT:         Field:           __indirect_function_table
152# CHECK-NEXT:         Kind:            TABLE
153# CHECK-NEXT:         Table:
154# CHECK-NEXT:           Index:           0
155# CHECK-NEXT:           ElemType:        FUNCREF
156# CHECK-NEXT:           Limits:
157# CHECK-NEXT:             Minimum:         0x2
158# CHECK-NEXT:       - Module:          env
159# CHECK-NEXT:         Field:           __stack_pointer
160# CHECK-NEXT:         Kind:            GLOBAL
161# CHECK-NEXT:         GlobalType:      I64
162# CHECK-NEXT:         GlobalMutable:   true
163# CHECK-NEXT:       - Module:          env
164# CHECK-NEXT:         Field:           __memory_base
165# CHECK-NEXT:         Kind:            GLOBAL
166# CHECK-NEXT:         GlobalType:      I64
167# CHECK-NEXT:         GlobalMutable:   false
168# CHECK-NEXT:       - Module:          env
169# CHECK-NEXT:         Field:           __table_base
170# CHECK-NEXT:         Kind:            GLOBAL
171# CHECK-NEXT:         GlobalType:      I64
172# CHECK-NEXT:         GlobalMutable:   false
173# CHECK-NEXT:       - Module:          env
174# CHECK-NEXT:         Field:           __table_base32
175# CHECK-NEXT:         Kind:            GLOBAL
176# CHECK-NEXT:         GlobalType:      I32
177# CHECK-NEXT:         GlobalMutable:   false
178# CHECK-NEXT:       - Module:          GOT.mem
179# CHECK-NEXT:         Field:           indirect_func
180# CHECK-NEXT:         Kind:            GLOBAL
181# CHECK-NEXT:         GlobalType:      I64
182# CHECK-NEXT:         GlobalMutable:   true
183# CHECK-NEXT:       - Module:          GOT.func
184# CHECK-NEXT:         Field:           func_external
185# CHECK-NEXT:         Kind:            GLOBAL
186# CHECK-NEXT:         GlobalType:      I64
187# CHECK-NEXT:         GlobalMutable:   true
188# CHECK-NEXT:       - Module:          GOT.mem
189# CHECK-NEXT:         Field:           data_external
190# CHECK-NEXT:         Kind:            GLOBAL
191# CHECK-NEXT:         GlobalType:      I64
192# CHECK-NEXT:         GlobalMutable:   true
193# CHECK-NEXT:       - Module:          GOT.mem
194# CHECK-NEXT:         Field:           extern_struct
195# CHECK-NEXT:         Kind:            GLOBAL
196# CHECK-NEXT:         GlobalType:      I64
197# CHECK-NEXT:         GlobalMutable:   true
198# CHECK-NEXT:   - Type:            FUNCTION
199
200# CHECK:        - Type:            EXPORT
201# CHECK-NEXT:     Exports:
202# CHECK-NEXT:       - Name:            __wasm_call_ctors
203# CHECK-NEXT:         Kind:            FUNCTION
204# CHECK-NEXT:         Index:           0
205
206# check for elem segment initialized with __table_base global as offset
207
208# CHECK:        - Type:            ELEM
209# CHECK-NEXT:     Segments:
210# CHECK-NEXT:       - Offset:
211# CHECK-NEXT:           Opcode:          GLOBAL_GET
212# CHECK-NEXT:           Index:           3
213# CHECK-NEXT:         Functions:       [ 3, 2 ]
214
215# check the generated code in __wasm_call_ctors and __wasm_apply_data_relocs functions
216
217# DIS:      <__wasm_call_ctors>:
218# DIS-EMPTY:
219# DIS-NEXT:                 end
220
221# DIS:      <__wasm_apply_data_relocs>:
222# DIS-EMPTY:
223# DIS-NEXT:                 i64.const       4
224# DIS-NEXT:                 global.get      1
225# DIS-NEXT:                 i64.add
226# DIS-NEXT:                 global.get      5
227# DIS-NEXT:                 i64.store       0:p2align=2
228# DIS-NEXT:                 i64.const       12
229# DIS-NEXT:                 global.get      1
230# DIS-NEXT:                 i64.add
231# DIS-NEXT:                 global.get      2
232# DIS-NEXT:                 i64.const       1
233# DIS-NEXT:                 i64.add
234# DIS-NEXT:                 i64.store       0:p2align=2
235# DIS-NEXT:                 i64.const       20
236# DIS-NEXT:                 global.get      1
237# DIS-NEXT:                 i64.add
238# DIS-NEXT:                 global.get      1
239# DIS-NEXT:                 i32.const       0
240# DIS-NEXT:                 i32.add
241# DIS-NEXT:                 i32.store       0
242# DIS-NEXT:                 i64.const       24
243# DIS-NEXT:                 global.get      1
244# DIS-NEXT:                 i64.add
245# DIS-NEXT:                 global.get      6
246# DIS-NEXT:                 i64.store       0:p2align=2
247# DIS-NEXT:                 i64.const       32
248# DIS-NEXT:                 global.get      1
249# DIS-NEXT:                 i64.add
250# DIS-NEXT:                 global.get      7
251# DIS-NEXT:                 i32.const       4
252# DIS-NEXT:                 i32.add
253# DIS-NEXT:                 i32.store       0
254# DIS-NEXT:                 end
255
256# check the data segment initialized with __memory_base global as offset
257
258# CHECK:        - Type:            DATA
259# CHECK-NEXT:     Segments:
260# CHECK-NEXT:       - SectionOffset:   6
261# CHECK-NEXT:         InitFlags:       0
262# CHECK-NEXT:         Offset:
263# CHECK-NEXT:           Opcode:          GLOBAL_GET
264# CHECK-NEXT:           Index:           1
265# CHECK-NEXT:         Content:         '020000000000000000000000010000000000000000000000000000000000000000000000'
266