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