# A memory-address (data) relocation may, after symbol resolution, take the
# address of a symbol that resolves to a FUNCTION: an undefined symbol that MC
# was forced to type WASM_SYMBOL_TYPE_DATA (e.g. the target of a GNU-as alias,
# as glibc's libc_hidden_builtin redirect emits) can bind to a real FUNCTION
# definition of the same name (lld commit 12776b692). Taking that symbol's
# address must compute the wasm function pointer -- its index in
# __indirect_function_table -- instead of crashing in
# ObjFile::calcNewValue/InputChunk::getVA on a symbol with no data layout, and
# the re-emitted relocation must be the table-index form (a memory-address
# relocation against a function symbol is invalid in the wasm object format).
#
# This is the direct completion of 12776b692 (which resolved the *type*; this
# resolves the *relocation that takes the address*).

# RUN: rm -rf %t && split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %t/ref.s -o %t/ref.o
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %t/func.s -o %t/func.o
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %t/refadd.s -o %t/refadd.o
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %t/datadata.s -o %t/datadata.o
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %t/code.s -o %t/code.o

## GREEN: a data relocation that takes the address of a symbol resolving to a
## FUNCTION links (no crash), in either object order, and is re-emitted as a
## table-index relocation against the function.
# RUN: wasm-ld -r -o %t/r1.o %t/ref.o %t/func.o
# RUN: llvm-objdump --syms %t/r1.o | FileCheck %s --check-prefix=SYMS
# RUN: llvm-objdump -r %t/r1.o | FileCheck %s --check-prefix=RELOC
# RUN: wasm-ld -r -o %t/r2.o %t/func.o %t/ref.o
# RUN: llvm-objdump -r %t/r2.o | FileCheck %s --check-prefix=RELOC

## The re-emitted relocatable object is itself valid and links again cleanly.
# RUN: wasm-ld -r -o %t/r1b.o %t/r1.o

## A code-section function-address reference (i32.const &func -> a SLEB
## memory-address relocation, as glibc's _nl_make_l10nflist emits taking
## &__GI_strcpy) is likewise re-emitted as a table-index relocation.
# RUN: wasm-ld -r -o %t/c.o %t/code.o %t/func.o
# RUN: llvm-objdump -r %t/c.o | FileCheck %s --check-prefix=CODE
# RUN: wasm-ld -r -o %t/cb.o %t/c.o

## A normal data-to-data relocation is unaffected: it stays a memory-address
## relocation.
# RUN: wasm-ld -r -o %t/dd.o %t/datadata.o
# RUN: llvm-objdump -r %t/dd.o | FileCheck %s --check-prefix=DATADATA

## NEVER-SILENT: a function address with a non-zero addend cannot be represented
## as a table index, so it diagnoses loudly instead of crashing or emitting a
## wrong value.
# RUN: not wasm-ld -r -o %t/bad.o %t/refadd.o %t/func.o 2>&1 | FileCheck %s --check-prefix=ADDEND

# SYMS-DAG: F {{.*}}__GI_memset
# SYMS-DAG: O DATA {{.*}}p
# RELOC: R_WASM_TABLE_INDEX_I32 __GI_memset
# CODE: R_WASM_TABLE_INDEX_SLEB __GI_memset
# DATADATA: R_WASM_MEMORY_ADDR_I32 data_target
# ADDEND: error: {{.*}}cannot take the address of function `__GI_memset`{{.*}}non-zero addend

#--- ref.s
## `p` holds the address of __GI_memset, which is undefined here and referenced
## only as a data address, so MC types it DATA. It resolves to the FUNCTION
## defined in func.s.
.globl p
.section .data.p,"",@
p:
  .int32 __GI_memset
.size p, 4

#--- func.s
.globl __GI_memset
__GI_memset:
  .functype __GI_memset (i32, i32, i32) -> (i32)
  local.get 0
  end_function

#--- refadd.s
## Same, but takes __GI_memset + 4: a function pointer is a table index, so a
## non-zero byte addend is not representable.
.globl q
.section .data.q,"",@
q:
  .int32 __GI_memset+4
.size q, 4

#--- code.s
## A function body that takes the address of __GI_memset (undefined data here,
## referenced as an i32.const operand -> R_WASM_MEMORY_ADDR_SLEB). It resolves
## to the FUNCTION in func.s.
.globl caller
caller:
  .functype caller () -> (i32)
  i32.const __GI_memset
  end_function

#--- datadata.s
## A plain data-to-data address relocation; must remain a memory-address reloc.
.globl data_target
.section .data.data_target,"",@
data_target:
  .int32 7
.size data_target, 4
.globl dp
.section .data.dp,"",@
dp:
  .int32 data_target
.size dp, 4
