Hi,
When linking against a .def file whose LIBRARY directive is a quoted
string with no file extension (a form MS's own LINK.exe/lib.exe accept,
and which real-world .def files - e.g. those shipped in OpenSSL's
official Win64 installer - actually use), pe_load_def() in tccpe.c
embeds the directive's value literally, quote characters included and
with no .dll suffix appended, as the DLL name the resulting executable
must load at startup. Since '"' is not a legal Windows filename
character, no file can ever satisfy that embedded name, and the
program fails to even start, with the Windows loader reporting
STATUS_DLL_NOT_FOUND (0xC0000135) - regardless of whether the correctly
named DLL is present and on PATH.
Repro:
// mylib.c -> compiled to mylib-1-x64.dll, exporting myfunc
__declspec(dllexport) int myfunc(void) { return 42; }
// mylib-1-x64.def
LIBRARY "mylib-1-x64"
EXPORTS
myfunc @1
tcc -shared mylib.c -o mylib-1-x64.dll
tcc prog.c mylib-1-x64.def -o prog.exe
prog.exe fails to launch (STATUS_DLL_NOT_FOUND), even though
mylib-1-x64.dll exists exactly where it should. Inspecting prog.exe's
import table shows the imported module name as the literal string
"mylib-1-x64" (15 chars, quotes included, no .dll suffix), which cannot
match any real file. MSVC's link.exe handles the identical .def file
correctly, embedding the correct mylib-1-x64.dll reference.
Root cause: in pe_load_def(), the LIBRARY value is extracted via a
plain whitespace-delimited tokenizer (trimfront/pstrcpy) that neither
strips a surrounding quote pair nor defaults a missing extension,
unlike MSVC's own DEF-file handling, which does both.
Confirmed present on the current mob branch, and reproduced identically
on commit 9eef33993ade2d3b964d19b1081978ceae5d359d (2020-06-05) - this
is not a regression, it's a long-standing, still-open gap.
Found via V (vlang/v), whose Windows CI links crypto/ecdsa,
crypto/rsa_pss, and net/quic against OpenSSL. OpenSSL's official
Windows installer (Win64OpenSSL, e.g. version 4.0.1) ships
lib\VC\x64\MD\libcrypto.def / libssl.def with exactly this quoted,
unsuffixed format (LIBRARY "libcrypto-4-x64"), so every tcc-linked
executable built against -lcrypto on Windows with this (very common,
officially distributed) OpenSSL package fails to launch.
Patch attached: strip a matched pair of surrounding quote characters
from the LIBRARY name, then default a missing extension to .dll,
mirroring MSVC's own DEF LIBRARY statement semantics. Verified against
the repro above (prog.exe now runs and returns 42), and re-tested the
previously-working unquoted and quoted-with-extension forms to confirm
no regression.
Thanks,
Richard Wheeler
From df132956f0bf6fcd56f0e63811c51066ae9793a9 Mon Sep 17 00:00:00 2001
From: Richard Wheeler <[email protected]>
Date: Wed, 22 Jul 2026 16:21:13 -0400
Subject: [PATCH] tccpe: strip quotes and default .dll extension in DEF LIBRARY
statements
pe_load_def() copied the LIBRARY directive's value verbatim into
dllname, with no handling for a quoted string and no fallback to
append .dll when the name has no extension.
Real-world .def files commonly quote the LIBRARY name and omit the
extension (this is exactly what MSVC's own DEF-file parser accepts,
and what OpenSSL's official Windows installer ships, e.g.
LIBRARY "libcrypto-4-x64"). Since '"' is not a legal filename
character, the resulting import table entry can never match any
real DLL, and the linked executable fails to start with
STATUS_DLL_NOT_FOUND.
Strip a matched pair of surrounding quotes, then default a missing
extension to .dll, mirroring MSVC's DEF LIBRARY statement semantics.
---
tccpe.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/tccpe.c b/tccpe.c
index a16411c7..0a434d05 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -1701,7 +1701,7 @@ static char *trimback(char *a, char *e)
/* ------------------------------------------------------------- */
static int pe_load_def(TCCState *s1, int fd)
{
- int state = 0, ret = -1, dllindex = 0, ord;
+ int state = 0, ret = -1, dllindex = 0, ord, len;
char line[400], dllname[80], *p, *x;
FILE *fp;
@@ -1716,7 +1716,17 @@ static int pe_load_def(TCCState *s1, int fd)
case 0:
if (0 != strnicmp(p, "LIBRARY", 7))
goto quit;
- pstrcpy(dllname, sizeof dllname, trimfront(p+7));
+ x = trimfront(p+7);
+ len = strlen(x);
+ if (len >= 2 && '"' == x[0] && '"' == x[len - 1]) {
+ x[len - 1] = 0;
+ ++x;
+ }
+ pstrcpy(dllname, sizeof dllname, x);
+ /* DEF LIBRARY statements may give a bare module name with no
+ extension; MSVC's own DEF parser assumes .dll in that case. */
+ if (0 == *tcc_fileextension(dllname))
+ pstrcat(dllname, sizeof dllname, ".dll");
++state;
continue;
-- 2.53.0.windows.2_______________________________________________
Tinycc-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel