Before I'll respond to your last email, you said in your original email that even printf doesn't work:
> `_iob` is not the only "unresolved" symbol, either; `printf`, > `freopen`, `freopen_s`, and basically everything from the CRT will > fail to link. But in my minimal example there's only _MSVCRT_ and #include <stdio.h> and printf and it does compile and link (and runs, and prints), and there's no #include <windows.h> which you think cancels _MSVCRT_. Is my example incorrect somehow? or maybe it didn't work in 0.9.27 but does work with recent mob? Now, to your suggested fix. Looking at a recent mingw installation (specifically w64devkit 2.0 - https://github.com/skeeto/w64devkit), it looks to me pretty much the same as this code in tcc stdio.h (w64devkit/i686-w64-mingw32/include/stdio.h lines 101-129) with minor difference that _imp___iob is a macro expansion and not explicit. Your original test case (with freopen and _MSVCRT_ after #include <windows.h>) does compile with w64devkit x86, so at the very least your suggestion is not how it's handled in new mingw. Can you maybe dig into that and figure out what makes it tick in w64devkit, and see if a similar thing can be applied to the tcc headers? On Sunday, November 24, 2024 at 11:05:38 PM GMT+2, Fereydoun Memarzanjany <thraeta...@ieee.org> wrote: After nearly 16 hours of debugging, I've found the culprit: `_iob` and `_imp___iob` should have been declared with either `__attribute__((dllimport))` or `__declspec(dllimport)` To be more specific, lines 93 to 106 of <stdio.h> in TCC's ./include directory are currently written as follows: ```c #ifndef _STDIO_DEFINED #ifdef _WIN64 _CRTIMP FILE *__cdecl __iob_func(void); #else #ifdef _MSVCRT_ extern FILE _iob[]; /* A pointer to an array of FILE */ #define __iob_func() (_iob) #else extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ #define __iob_func() (*_imp___iob) #define _iob __iob_func() #endif #endif #endif ``` To fix them so that it compiles under `-m32` just as fine as it does under `-m64`, you need to change them to the following: ```c #ifndef _STDIO_DEFINED #ifdef _WIN64 _CRTIMP FILE *__cdecl __iob_func(void); #else #ifdef _MSVCRT_ __attribute__((dllimport)) extern FILE _iob[]; /* A pointer to an array of FILE */ #define __iob_func() (_iob) #else __attribute__((dllimport)) extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ #define __iob_func() (*_imp___iob) #define _iob __iob_func() #endif #endif #endif ``` (NOTE: As I said earlier, both `__attribute__((dllimport))` and `__declspec(dllimport)` work here. Either of them fix it for both _MSVCRT_ and non-_MSVCRT_ headers.) A few additional details on why this fix is even useful in the first place: - freopen() is optional in -subsystem=console (i.e., CLI) but absolutely required if you compile in -subsystem=windows (i.e., GUI) mode; if freopen() isn't called in the latter, printf and other std outputs don't show up on the allocated console; - freopen() depends on the value of `stdout`, and `stdout` is defined based on either _iob or _imp___iob in stdio.h; - _imp___iob is too old and no longer exists in newer msvcrt.dll or ucrtbase.dll, making _iob (and therefore defining _MSVCRT_) the go-to choice; and - #define'ing _MSVCRT_ before <windows.h> is akin to not defining it at all; I think <windows.h> undefines it somewhere, internally. I still find it strange that such a "fix" was required, because TCC works just fine under `-m64` anyway. For `-m32` builds, do you think we should patch the stdio.h in the mob branch ourselves? I'm not sure if this is a TCC-specific patch or if it actually affects any compiler that uses stdio.h from MinGW. (Also, I did compile the latest mob branch using "build-tcc.bat -x -c cl" but this stdio.h bug affected it the same way it affected 0.9.27.) On Sun, Nov 24, 2024 at 12:09 PM avih <avih...@yahoo.com> wrote: > > tcc 0.9.27 is few years old now, and hopefully 0.9.28 would be released > sooner rather than later, so you should try the latest version, which is the > mob (default) branch here: > https://repo.or.cz/tinycc.git > > You'll need to build it yourself. If you can't build it or can't find a > recent pre-build binary, then I can upload a version to some pastebin (do > ask, but do try to build it first if you can). > > You should also keep in mind that tcc is a not mingw gcc clone. It does use > (old) mingw headers, but you should not expect 100% compatibility, and the > headers set is intentionally stripped down to keep it minimal (although many > programs compile out of the box with the existing headers) > > Specifically about your issue. With latest tcc, if I comment out the line > with "freopen" in your sample program, or with a minimal program like this: > > #define _MSVCRT_ > #include <stdio.h> > > int main() { > printf("Hello, world\n"); > return 0; > } > > Then it compiles and works fine. > > But with your original program with freopen, tcc indeed complains about > undefined symbol '_iob'. > > However, if I move the _MSVCRT_ definition above #include <windows.h>, then > it does compile (I didn't try to run it, but I presume it would work). > > So I'd think largely it's OK. However, I was not aware of this _MSVCRT_ > thingy, so I don't know what differences to expect and I didn't try to > understand it further. > > I don't know whether this should be considered an issue that it works in tcc > only if _MSVCRT_ is defined before windows.h is included (to me that feels > reasonable, so do double check), but if it should be considered an issue, > then maybe you could help by trying to pinpoint the cause at the headers, and > report back. > > Cheers, > avih > > > On Sunday, November 24, 2024 at 07:43:30 PM GMT+2, Fereydoun Memarzanjany >via Tinycc-devel <tinycc-devel@nongnu.org> wrote: > > > If you use TinyCC in its 32-bit mode (`-m32`) to compile a sample > program that uses any CRT function/symbol from `msvcrt.dll` (such as > the snippet provided later in this message), you'll be met with > compilation failures: > > `tcc.exe -std=c11 -Wall -Werror -Wl,-subsystem=console -m32 .\main.c` > "tcc: error: undefined symbol '_iob', missing __declspec(dllimport)?" > > (This only happens under `-m32`, whereas `-m64` works perfectly fine.) > > `_iob` is not the only "unresolved" symbol, either; `printf`, > `freopen`, `freopen_s`, and basically everything from the CRT will > fail to link. > > Regardless of whether or not you use `-lmsvcrt`, `#pragma comment(lib, > "msvcrt")`, `_declspec(dllimport)`, `attribute ((dllimport))`, > `-static` or `-shared`, or even `-impdef` on > "C:\Windows\SysWow64\msvcrt.dll" (or earlier versions thereof: > "msvcrt40.dll"), TCC still complains. > > I've verified with `DUMPBIN.exe` that both 32- and 64-bit "msvcrt.dll" > do, in fact, define `_iob` and other symbols. > > By some arcane logic, the following works perfectly fine: `tcc.exe > -std=c11 -Wall -Werror -Wl,-subsystem=console -m64 .\main.c` > > `main.c` > ```c > //#pragma comment(lib, "msvcrt") > //__attribute__((dllimport)) extern __declspec(dllimport) FILE _iob[]; > > #include <windows.h> > > // _MSVCRT_ being defined will cause MinGW's stdio.h to use _iob as > // opposed to _imp___iob; only the former is defined in msvcrt.dll. > // However, even though _iob is exported by both the 32- and 64-bit > // versions of said dll, TinyCC still fails to find _iob in the former. > #define _MSVCRT_ > #include <stdio.h> > > void main() { > // AllocConsole() and basically everything from kernel32.dll or > // user32.dll work perfectly fine, both in -m32 and -m64; it's > // only msvcrt.dll that causes issues with TinyCC. > AllocConsole(); > > // Any CRT function (e.g., freopen, freopen_s, printf, etc.) > // fail to get linked properly ONLY in -m32; -m64 is fine. > // Even if I change the -I and -L paths to C:/Windows/SysWow64 > // and/or use tcc.exe -impdef to create .def files from them, > // TCC still fails in finding _iob and other symbols. > // Also, using #pragma comment(lib, "msvcrt") or -lmsvcrt > // doesn't help at all. Even if you do get TCC to somehow > // stop complaining about missing symbols, it'd just include > // a blank IAT.printf or IAT.freopen, causing segfaults. > freopen("CONOUT$", "w", stdout); > printf("This only compiles (and prints) under TCC in 64-bit mode."); > } > ``` > > As mentioned earlier, this error in `-m32` happens regardless of other > switches like `-std`, `-shared`, `-static`, `-lmsvcrt`, `-subsyetem`, > etc. So, at this point, I'm starting to think this might really be a > bug with TinyCC 0.9.27 (Win32 & Win64 builds) itself. > > _______________________________________________ > Tinycc-devel mailing list > Tinycc-devel@nongnu.org > https://lists.nongnu.org/mailman/listinfo/tinycc-devel _______________________________________________ Tinycc-devel mailing list Tinycc-devel@nongnu.org https://lists.nongnu.org/mailman/listinfo/tinycc-devel