xref: /llvm-project/lld/test/wasm/shared64.s (revision 22b7b84860d39da71964c9b329937f2ee1d875ba)
1# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-unknown -o %t.o %s
2# RUN: wasm-ld -mwasm64 --experimental-pic --unresolved-symbols=import-dynamic -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, ptr @data, align 4
56  # %1 = load ptr, ptr @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:             Flags:         [ IS_64 ]
158# CHECK-NEXT:             Minimum:         0x2
159# CHECK-NEXT:       - Module:          env
160# CHECK-NEXT:         Field:           __stack_pointer
161# CHECK-NEXT:         Kind:            GLOBAL
162# CHECK-NEXT:         GlobalType:      I64
163# CHECK-NEXT:         GlobalMutable:   true
164# CHECK-NEXT:       - Module:          env
165# CHECK-NEXT:         Field:           __memory_base
166# CHECK-NEXT:         Kind:            GLOBAL
167# CHECK-NEXT:         GlobalType:      I64
168# CHECK-NEXT:         GlobalMutable:   false
169# CHECK-NEXT:       - Module:          env
170# CHECK-NEXT:         Field:           __table_base
171# CHECK-NEXT:         Kind:            GLOBAL
172# CHECK-NEXT:         GlobalType:      I64
173# CHECK-NEXT:         GlobalMutable:   false
174# CHECK-NEXT:       - Module:          GOT.mem
175# CHECK-NEXT:         Field:           indirect_func
176# CHECK-NEXT:         Kind:            GLOBAL
177# CHECK-NEXT:         GlobalType:      I64
178# CHECK-NEXT:         GlobalMutable:   true
179# CHECK-NEXT:       - Module:          GOT.func
180# CHECK-NEXT:         Field:           func_external
181# CHECK-NEXT:         Kind:            GLOBAL
182# CHECK-NEXT:         GlobalType:      I64
183# CHECK-NEXT:         GlobalMutable:   true
184# CHECK-NEXT:       - Module:          GOT.mem
185# CHECK-NEXT:         Field:           data_external
186# CHECK-NEXT:         Kind:            GLOBAL
187# CHECK-NEXT:         GlobalType:      I64
188# CHECK-NEXT:         GlobalMutable:   true
189# CHECK-NEXT:       - Module:          GOT.mem
190# CHECK-NEXT:         Field:           extern_struct
191# CHECK-NEXT:         Kind:            GLOBAL
192# CHECK-NEXT:         GlobalType:      I64
193# CHECK-NEXT:         GlobalMutable:   true
194# CHECK-NEXT:   - Type:            FUNCTION
195
196# CHECK:        - Type:            EXPORT
197# CHECK-NEXT:     Exports:
198# CHECK-NEXT:       - Name:            __wasm_call_ctors
199# CHECK-NEXT:         Kind:            FUNCTION
200# CHECK-NEXT:         Index:           0
201
202# check for elem segment initialized with __table_base global as offset
203
204# CHECK:        - Type:            ELEM
205# CHECK-NEXT:     Segments:
206# CHECK-NEXT:       - Offset:
207# CHECK-NEXT:           Opcode:          GLOBAL_GET
208# CHECK-NEXT:           Index:           2
209# CHECK-NEXT:         Functions:       [ 3, 2 ]
210
211# check the generated code in __wasm_call_ctors and __wasm_apply_data_relocs functions
212
213# DIS:      <__wasm_call_ctors>:
214# DIS-EMPTY:
215# DIS-NEXT:                 end
216
217# DIS:      <__wasm_apply_data_relocs>:
218# DIS-EMPTY:
219# DIS-NEXT:                 i64.const       4
220# DIS-NEXT:                 global.get      1
221# DIS-NEXT:                 i64.add
222# DIS-NEXT:                 global.get      4
223# DIS-NEXT:                 i64.store       0:p2align=2
224# DIS-NEXT:                 i64.const       12
225# DIS-NEXT:                 global.get      1
226# DIS-NEXT:                 i64.add
227# DIS-NEXT:                 global.get      2
228# DIS-NEXT:                 i64.const       1
229# DIS-NEXT:                 i64.add
230# DIS-NEXT:                 i64.store       0:p2align=2
231# DIS-NEXT:                 i64.const       20
232# DIS-NEXT:                 global.get      1
233# DIS-NEXT:                 i64.add
234# DIS-NEXT:                 global.get      1
235# DIS-NEXT:                 i32.const       0
236# DIS-NEXT:                 i32.add
237# DIS-NEXT:                 i32.store       0
238# DIS-NEXT:                 i64.const       24
239# DIS-NEXT:                 global.get      1
240# DIS-NEXT:                 i64.add
241# DIS-NEXT:                 global.get      5
242# DIS-NEXT:                 i64.store       0:p2align=2
243# DIS-NEXT:                 i64.const       32
244# DIS-NEXT:                 global.get      1
245# DIS-NEXT:                 i64.add
246# DIS-NEXT:                 global.get      6
247# DIS-NEXT:                 i32.const       4
248# DIS-NEXT:                 i32.add
249# DIS-NEXT:                 i32.store       0
250# DIS-NEXT:                 end
251
252# check the data segment initialized with __memory_base global as offset
253
254# CHECK:        - Type:            DATA
255# CHECK-NEXT:     Segments:
256# CHECK-NEXT:       - SectionOffset:   6
257# CHECK-NEXT:         InitFlags:       0
258# CHECK-NEXT:         Offset:
259# CHECK-NEXT:           Opcode:          GLOBAL_GET
260# CHECK-NEXT:           Index:           1
261# CHECK-NEXT:         Content:         '020000000000000000000000010000000000000000000000000000000000000000000000'
262