101 lines · plain
1# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s2 3## A `.tdata` (initialised thread-local) pointer initialised to the address of a4## non-TLS global -- the `__thread T *p = &global;` shape (e.g. glibc's5## `__thread locale_t __libc_tsd_LOCALE = &_nl_global_locale;`). The initialiser6## is a non-PIC link-time-constant address carried by an R_WASM_MEMORY_ADDR_I327## relocation inside the .tdata segment.8##9## Such a relocation must be applied BOTH ways:10## (1) baked into the .tdata template image bytes (the per-thread copy source),11## (2) emitted into __wasm_apply_tls_relocs so the value is (re)applied to the12## live per-thread TLS block at runtime -- __wasm_init_tls calls it.13##14## Before the fix, __wasm_apply_tls_relocs only emitted code for PIC/GOT15## relocations, so a non-PIC absolute TLS relocation was silently dropped and the16## function was a 3-byte no-op (just `end`). A libc that establishes the17## per-thread block by zero-filling it rather than copying the wasm passive18## template verbatim (glibc's _dl_allocate_tls_init memsets the block because a19## wasm TLS segment has no linear init-image) then leaves the `.tdata` pointer20## slot NULL: a silent miscompile. The checks below assert the store is emitted21## (it is absent pre-fix -> RED, present post-fix -> GREEN) and that the template22## image still carries the baked constant.23 24.globaltype __tls_base, i3225 26## Keep `tp` live (referenced through an initial-exec-style TLS access).27.text28.globl tp_addr29tp_addr:30 .functype tp_addr () -> (i32)31 global.get __tls_base32 i32.const tp@TLSREL33 i32.add34 end_function35 36## A non-TLS global; the thread-local pointer below is initialised to its address.37.section .data.g,"",@38.globl g39.p2align 240g:41 .int32 123442 .size g, 443 44## `__thread int *tp = &g;` -- a .tdata pointer initialised to &g. Emits an45## R_WASM_MEMORY_ADDR_I32 relocation (a non-PIC absolute address) at TLS offset 0.46.section .tdata.tp,"T",@47.globl tp48.p2align 249tp:50 .int32 g51 .size tp, 452 53.section .custom_section.target_features,"",@54 .int8 255 .int8 4356 .int8 757 .ascii "atomics"58 .int8 4359 .int8 1160 .ascii "bulk-memory"61 62# RUN: wasm-ld -no-gc-sections --shared-memory --max-memory=131072 --no-entry -o %t.wasm %t.o63# RUN: llvm-objdump -d --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck --check-prefix=ASM %s64# RUN: obj2yaml %t.wasm | FileCheck --check-prefix=YAML %s65 66## __wasm_init_tls must materialise the per-thread block (memory.init of the67## passive .tdata template) AND call __wasm_apply_tls_relocs.68# ASM-LABEL: <__wasm_init_tls>:69# ASM-EMPTY:70# ASM-NEXT: local.get 071# ASM-NEXT: global.set 172# ASM-NEXT: local.get 073# ASM-NEXT: i32.const 074# ASM-NEXT: i32.const 475# ASM-NEXT: memory.init 0, 076# ASM-NEXT: call [[APPLY:[0-9]+]]77# ASM-NEXT: end78 79## GREEN assertion: __wasm_apply_tls_relocs applies the non-PIC absolute TLS80## relocation by storing &g into the live slot __tls_base + 0. Pre-fix this81## function body was empty (just `end`), so the `global.get 1` line below is82## absent and FileCheck fails -- the RED arm.83# ASM-LABEL: <__wasm_apply_tls_relocs>:84# ASM-EMPTY:85# ASM-NEXT: global.get 186# ASM-NEXT: i32.const 087# ASM-NEXT: i32.add88# ASM-NEXT: i32.const [[ADDR:[0-9]+]]89# ASM-NEXT: i32.store90# ASM-NEXT: end91 92## The .tdata template image must ALSO carry the baked constant &g (little-endian93## 4-byte pointer): .tdata is the first data segment, tp is at TLS offset 0, and94## g is placed right after it, so &g == .tdata base + 4 and the image bytes are95## the little-endian encoding of that address.96# YAML: - Type: DATA{{$}}97# YAML-NEXT: Segments:98# YAML-NEXT: - SectionOffset: {{.*}}99# YAML-NEXT: InitFlags: 1100# YAML-NEXT: Content: {{'?}}04000100{{'?}}101