This arises from https://bugs.llvm.org/show_bug.cgi?id=35625
First Problem - function pointers
Currently, there is no linking metadata for table entries (function pointers). The Wasm table entry itself is used to find out which function the relocation should be generated for. In order for the Wasm module to pass validation, the table entries in object files must point to a valid Function (code definition).
However, this actually semantically wrong. The linker can't generate correct output simply using the Function index, it needs the actual Symbol.
Here's an example to illustrate:
=== file1.c ===
int aliasFn(void) { return 1; }
=== file2.c ===
int directFn(void) { return 2; }
extern int aliasFn(void) __attribute__((weak,alias("directFn")));
int directFnPtr() { return (int)&directFn; }
int aliasFnPtr() { return (int)&aliasFn; }
int callDirect(void) { return directFn(); }
=== Results ===
Compile and link with `lld file1.o file2.o`.
* directFnPtr and aliasFnPtr should point to two different methods, but
unfortunately they don't.
* If file2 is compiled with -O0 (to prevent inlining) then callDirect erroneously
returns 1
(The output Wasm module for this has three functions: directFn, directFnPtr, aliasFnPtr. The table entries can only point to those. It has four exports (=symbols): directFn, aliasFn, directFnPtr, aliasFnPtr.)
The relocations for directFnPtr and aliasFnPtr will both reference Wasm table entries - and those table entries both point to directFn! The relocations are completely indistinguishable... yet, upon linking, we may need those two function to be relocated to point to different functions (if another file provides "aliasFn" more strongly or earlier).
Second problem - function relocations
Even worse, function relocations are also broken by aliases! Oops. In the example above, LLD happens to use the Symbol for "aliasFn" as the Symbol associated with the body of "directFn". That's actually completely reasonable behaviour - we have here two different Symbols/names associated with the same function body, it's a toss of a coin which one is chosen. There is no single "canonical" Symbol referring to the Function body.
Attempts to call "directFn" directly (not even via a pointer!) will also generate incorrect code currently. This is because the last-defined Symbol for a function wins, and so the relocation is generated against aliasFn.
In the linking metadata for relocations, we can't use the Function index, we have to use the Symbol index instead.