<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/76046>76046</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
lld-link LTO fails on symbol references to symbols within inline assembly within functions
</td>
</tr>
<tr>
<th>Labels</th>
<td>
lld:COFF,
platform:windows,
LTO
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
mstorsjo
</td>
</tr>
</table>
<pre>
LTO builds of FFmpeg on Windows on x86 fail, because LLD believes that the link has unresolved symbols, so it errors out before proceeding to the actual LTO compile (where those symbols would appear). This has been reported to FFmpeg at https://trac.ffmpeg.org/ticket/10548. The original, problematic piece of code can be viewed at https://github.com/FFmpeg/FFmpeg/blob/n6.1/libavcodec/x86/mlpdsp_init.c.
The issue can be reproduced with a very minimal reduced case that looks like this:
```c
extern char func_pos;
static const void *const jumptable[] = { &func_pos };
void func(void) {
__asm__ volatile(
"func_pos:\n"
:: "r"(jumptable)
);
}
```
Attempting to build and link it with LTO:
```
$ clang -target x86_64-windows-msvc -c lto-repro.c -flto
$ lld-link lto-repro.o -out:lto-repro.exe -entry:func -subsystem:console
lld-link: error: undefined symbol: func_pos
>>> referenced by lto-repro.c
>>> lto-repro.o
```
Without the option `-flto`, linking succeeds.
The same experiment also succeeds with Clang when targeting Linux:
```
$ clang -target x86_64-linux-gnu -c lto-repro.c -flto
$ ld.lld lto-repro.o -o lto-repro.exe -e func
```
The same experiment also succeeds with GCC, for both Linux and Windows targets.
The root issue is that the inline assembly block, within the function `func`, defines a symbol `func_pos`, which the C code outside of it refers to, but the LTO object file does not indicate that the symbol `func_pos` will be defined by the inline assembly:
```
$ clang -target x86_64-windows-msvc -c lto-repro.c -flto
$ llvm-nm lto-repro.o
---------------- T func
U func_pos
---------------- d jumptable
```
This looks exactly the same when Clang targets Linux as well.
The reason why this fails on Windows, is that before starting the actual LTO compilation, lld-link checks whether there are unresolved symbols, to be able to print errors to the developer immediately if it looks like the link is going to fail, instead of having to wait for the full LTO compilation to complete, just to print errors: https://github.com/llvm/llvm-project/blob/llvmorg-17.0.6/lld/COFF/Driver.cpp#L2374-L2379 In the ELF version of LLD, there's nothing corresponding (probably because most linked ELF objects are allowed to have undefined symbols?).
These links do succeed if just the pre-LTO symbol availability check is skipped.
In order to facilitate symbol discovery from LTO objects, the LLVM LTO object file implementation does actually peek into the inline assembly statements, but only for module level inline assembly, not for function internal inline assembly:
```c
__asm__(
"static_func:\n"
".globl extern_func\n"
"extern_func:\n"
" call undefined_sym\n"
);
void func(void) {
__asm__(
"inline_static_func:\n"
".globl inline_extern_func\n"
"inline_extern_func:\n"
" call inline_undefined_sym\n"
);
}
```
```
$ clang -target x86_64-linux-gnu -c lto-symbols.c -flto
$ llvm-nm lto-symbols.o
---------------- T extern_func
---------------- T func
---------------- t static_func
U undefined_sym
```
Here, both the defined and undefined symbols referenced in the module level inline assembly are picked up, but not the ones from the function level inline assembly.
CC @MaskRay
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0WFGP4jgS_jXmpQQChwb6gYceerlbqVcjnWZvH5FjV4inHTuyHWj-_ansBGhg5nZOularJ7ErlXLVV199GRGC3lvENXv6wp5eR6KLtfPrJkTnw3c3Kp06rd--fYWy00YFcBVst02Le3AW_tJWuWOgy4_VAiqhDeMbKFGKLiC8vb1CiUbjAQPEWkSINYLR9h1qEaCzHoMzB1QQTk3pTKCHgwMdAb13PoDrIpRYOY_QeicRlbZ7iC45EjJ2wgAFJ13TaoPA-OpYo0eItQs4uIWj64wC0bYoPOPPE_hW65BiKBEteGydj6jIcX84EaGOsQ2seGF8y_g2eiEnVUWbE-f3tKLlO0bGt7Pp03xFPhGc13ttRcpC611psBFRS2g1SqTcSacQpLBQIhw0HlHdv2qvY92VE-kaxrc5nuuL0riS8a1dTGaMb40uxYG8Ssa3H6sF49vGtCq0O211nMgJm76y6Uv-SyHqELpzCB5b71QnUcFRxxoEHNCfoNFWN8KAx7wnRcBcQOPcewCj3-lep5iz_8U0_8p8jx8RvQVZCw9VZ-WudYEVX66DCTGlRjobIhycVsD4S7773jVtFKXBDEpgxSuw5RdgfDE4A7Z8vXGYfNA-4yu6ZvyZnsqbALudCM1uBwdnRNQGGV8NWwCM80uYL-xpYxnnwzatFC9k42mVry7x8efeiK7O4Sxfb7KSb19ixKaNPYRTQ4GwKneEjrkEb9--3me1v-VzkEbYPYyj8HuM1HW7xXx8zH04bsJBwliCiW6cSjuRMK5MdJfnjVHj9L6LjYOx6yIrXi5L-IEwRhv9iRUvlBgYh64MpxCxYUWqkjOYvQ4eKUWpbemisworbc-tTWvnBOdgit_yL3is0KMloJWn69hvDa9Cfpifv3SsiTGIHFwbtbPAFtOcgMWUepLipPSHThKZhLvuCKJBwI8WvW7QRhAmuLN1LtAmVeBYo4VcBXL4pm338ct1M_TUeG-726LdVU1NjFE3NYPbemXwP4rgbx7tH5sNZalyHkpHWKT4EkQHps_x3-fNOxd7atFXXK-t0RZBhIBNaU5QGiff6RX0Om2TDQU91CodIJcq4yeA6BE0bCcEZZNjrWWdfGwysbouBq0S0eqYcRUgujSTelzQtHDld5QRKpoYymEAS8FbpaWIeAn-4XvhqI0h6hzwXZ4enfT_28KHZmyb-3YY3_zAtytEwJ83DXhnra549zGIdOgHAH4IGU0-ecJVaofcGT1EBvAEOKIx94BBEZyFY31KgyRph3ClKahmA5J6BRCi8Jk8Hw1_QRhKPT4wnKxRvgcKLdbo6SmPIDz-QHgQJSPQ6emy9dqeZUgvOBQe0LgWPeimQaVFRHMCncD2aTD2IkcH2Lue7QdtpG2IKBRBtBaHfvModExdl_vB3J2LjOjWYETy8r0L8TZKotifCAlCTf_PuPWOOuAiJmjV-f14tpxMJ4u0oBjfbr5uyc-r1wf0E9m2jBdvvFjOx_T3GX7PHfzb25Z0Q6BAXUWyL-WT8s34MrVXTSeVznsMrbNJxTG-IokkEi_0irFxIabcoUpec6eGVDVhjDtmkVaLA96NmMCKLYm7G6SFXIwA6sx2VLKcwZp0JY4p2323i4PQRpTa6HjKCKIyhnfdtqg--f7dgvOKgEXVlfQE0UfvR-kgXRJTlXfNFe2EPjfw9vbvP-7oSFONiZ5z2RM7ZaibE7SI76Btj8ZbbiU9lR4NA985a04JVo1TnUEwhN87puKbxH9kd6ZibUm-iXvjM609VH29xLooK8Z5lnm7RET3yorzyd640kAWjNnskw3j_HrvkQsAKYy5AGIXTs0nq0_i7Be04q1EzNnY_fRI14fq7X94tk9ef3rK63P29j8-LvwtNfo_i5S-3X4-mAajH4-m6_P-9_F1txnhugznNH36-fMGE4_O_c_EUpsseDLLZ1Yh2XPHMdditdcvP2uuRFwtfSgq6NqhL6ndkkYlfZPo4ZMOeujpE_VsNsDm0z9EeP-XOI3UulDPxbMY4Xq2nBbT5dNqtRrV6ydRcVUKVWFZquV0ViyxmJfPs2dZVMWUz0Z6zae8mHE-nfFiNV1N5quZELwS81W5EKuVYPMpNkKbCVWWPntHSeKtl4vpfDEyokQT0n8ccE4Do3jJA4MzvmGct0bEynn6YDgOQ73foo8cztnT68ivE2rKbh_YfGp0iOHytqijwfV5oBNZnnVCz7PneqQpff7gz_Lythr98pDpMOq8Wf_yzEw5CIxvUxr-EwAA___FC4nS">