[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Tinycc-devel] Why does TinyCC fail to link standard C runtime funct
From: |
Fereydoun Memarzanjany |
Subject: |
Re: [Tinycc-devel] Why does TinyCC fail to link standard C runtime functions in 32-bit mode but works in 64-bit mode? |
Date: |
Tue, 26 Nov 2024 20:15:02 -0700 |
Sorry for the delay in getting back to you.
I shouldn't have put `-subsystem=console` because it'd lead to
confusion in my example. The point is that, when you compile with
`-subsystem=windows` (which all GUI applications do), you _have_ to
allocate a console; GUI apps have a graphical window but no
command-line interface upon starting. It is a very common and
sensible usage case to want to have a console alongside your main
window.
In a console-based program, allocation and freopen is done
automatically; in a GUI app, you also need to freopen() or freopen_s()
the stdin/stderr/stdout streams, otherwise your printf outputs will
not show up on the newly allocated console.
In <stdio.h>, stdin/stderr/stdout are dependent on the definition of
either `_iob` or `_imp___iob`.
As mentioned in my earlier threads, both _iob and _imp___iob are
mis-configured in TCC's version of <stdio.h>; even the compiler itself
complains that they must've been declared with __declspec or
__atribute__ ((dllimport). Also, that is the exact same way it's done
in new MinGW's headers, using the _CRTIMP macro.
I guess using TCC (at least for building full-fledged windows apps) is
rather niche in comparison to "mainstream" compilers (and its `-m32`
compiler even more so), explaining why no one has encountered/reported
this basic bug before.
the _MSVCRT_ macro is really not all that important here; it's just
telling <stdio.h> to use the latest MSVCRT.dll as opposed to "old"
versions of it. Newer MSVCRT.dll only comes with _iob, because
_imp___iob has been deprecated.
I didn't compile my program with MinGW GCC, but this code is pretty
much the "hello world" equivalent of Win32 consoles and should work
anywhere; it's just a matter of header misconfiguration in TCC's
headers.
To be concise, both _iob and _imp___iob are external symbols that
ought to be provided at runtime via msvcrt.dll (or, in case of
_imp___iob, older versions thereof); the MinGW headers that you linked
correctly label them as __declspec((dllimport)), whereas TCC's headers
don't. The reason this bug only shows up in the `-m32` version and
not `-m64` is because of line 94 in <stdio.h>
#ifdef _WIN64
_CRTIMP FILE *__cdecl __iob_func(void);
#else
It "skips" those _iob and _imp__iob stuff on Win64.
On Sun, Nov 24, 2024 at 8:05 PM avih <avihpit@yahoo.com> wrote:
>
> Can we maybe start from the begining again?
>
> If you compile with subsusyem=console, why do you need to allocate a console
> in the first place and then reopen stdout? console apps already do that
> automatically, like so:
>
> // test.c
> #include <stdio.h>
> int main() {
> printf("press enter to exit\n");
> fgetc(stdin);
> return 0;
> }
>
> And you compile it simply as:
> tcc test.c
>
> Or as in your example (omitting -m32 because I use a native tcc 32, to reduce
> the number of variables):
> tcc -std=c11 -Wall -Werror -Wl,-subsystem=console test.c
>
> Then if you run it in a console then it prints the message and waits for
> "enter", and if you double click it in explorer then it opens a console and
> prints the message in that console and waits for "enter".
>
> Isn't this what you're trying to achieve?
>
> Why is _MSVCRT_ defined in your example? Why is windows.h included in your
> example?
>
> Maybe you have some other problem, and the example program which you attached
> is your attempted solution, which didn't work, and now you try to make it
> work?
>
> If that's the case, maybe you can go back and describe your original problem,
> and the standard minimal program which you wrote to solve it (without
> defining _MSVCRT_), and which compiles in mingw gcc or msvc.
>
> Please describe exactly how you compile it with mingw gcc, and then how you
> tried to compile it with tcc, and what went wrong.
>
> - 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
Re: [Tinycc-devel] Why does TinyCC fail to link standard C runtime functions in 32-bit mode but works in 64-bit mode?, avih, 2024/11/24
- Re: [Tinycc-devel] Why does TinyCC fail to link standard C runtime functions in 32-bit mode but works in 64-bit mode?,
Fereydoun Memarzanjany <=