News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

TinyCC better than Masm32 in most cases

Started by frankvl, September 02, 2007, 07:10:41 AM

Previous topic - Next topic

frankvl

Hello there,

I have been a big fan of Masm32 and used it a lot, because the exe/overhead was small and I had a sense of control.

Today however, I feel urged to inform you about TinyCC, an ANSI-C compiler which emerged out of a programming contest where the challenge was to make a C compiler with 2 kB of source code (excluding { and }). Once I sold my soul to C, I saved A LOT of time writing code and fixing mistakes, I can create larger projects more easily and other programmers will be able to actually understand and expand my work.

The things we've grown to hate about C compilers simply don't apply to TinyCC. It evolved into a very decent all-in-one compiler/linker/assembler/interpreter(!), targeting 386/ARM on Linux and, since recently, Windows and supporting GCC inline asm. It's 10 times as fast as GCC. The resulting exe is only about 1 kb bigger than it would be under Masm32, because the commandline is wrapped in a string array on startup to support the ANSI-C standard. Like Masm32, all the stuff that isn't used doesn't end up in the binary and function/loop entry/exit codes are clean. There's a tool included that generates a .def file from a .dll, so you don't need any kind of source code/lib files before you can dynamically link dll functions, and this method doesn't force you to place typecasts all over the place.

You should also know that it's not necessary in C to define prototypes and header files or use a makefile and all that crap, plus it can be compiled without any hitch by other compilers, because of the ANSI standard. Using (redistributable) cross-platform libraries is advisable too, mostly because they are designed better and with more features than the ~30 year old closed source windows API.

Lastly, TinyCC can be used as a dll (~100 kb) that compiles or interprets C code in runtime via a very simple interface, and it's LGPL licenced (unlike Masm32), so you can basically distribute the source or compiled version for free and for any purpose.

Link: http://fabrice.bellard.free.fr/tcc/

In case you work on operating system stuff, you might want to know about the 138 kb TCCBOOT loader, which can compile and run a linux kernel directly from its source code in 15 seconds (2.4GHz)...

hutch--

Hi Frank,

This has been possible using the Microsoft VC compiler for years if you put aside the crappy C runtime libraries and write all of your own code. The problem is that once you put aside the C runtime library you don't code anywhere near as fast as with it so you throw away the only gain you have over an assembler.

Attached is a 1.5k exe using standard Microsoft C with the VC compiler and MSVCRT.

[attachment deleted by admin]
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Vortex

Hi Frank,

How do you configure TinyCC to use in the Win32 environment? I receive this error message :

include file 'windows.h' not found

arek

Frank,
That is probably good news for all, who feel more comfortable with C than assembler  :thumbu

Regards,
Arek

drhowarddrfine

Hm.  Two posts by two 'different' people with only one post to their credit.

Vortex

OK, initializing the Tcc compiler is easy, I found it :

tcc -ID:\tcc\include\winapi -ID:\tcc\include -LD:\tcc\lib hello_win.c

Here are the results of my testings. As source code, I used the hello_win.c file supplied with the Tcc package.

Tcc : the compiler produces an exe with a size of 3584 bytes.

MS Visual C++ Express 2005 : 3072 bytes with my own tiny C startup module. I used Polink to link the object file. If I merge the sections, the final size is reduced to 2560 bytes.

Vista SDK compiler : Same results as VC++  Express 2005

The TinyCC compiler can output ELF object files. To study them, you can use Agner Fog's object file converter objconv.exe :

objconv -fasm hello_win.o hello_win.asm

You get a disassembly listing of the Tcc object module.

[attachment deleted by admin]

japheth


Vortex,

your comparison is a bit unfair because the MSVCRT.DLL is used .... by the TCC generated module.  :green

Vortex

japheth,

When using the Tcc compiler, is there a way to get rid of the msvcrt.dll dependency?

hutch--

While I have not heard anything bad about TinyCC it does not appear as if the compiler is any improvement on the VC series of C compilers available. It may have a smaller default runtime library but thats no problem either with VC, just use a custom runtime library written in MASM.

If I have the general drift of Frank's posting, he has made the shift to Linux and wanted to have a parting free kick at a Windows based assembler. Its common knowledge that assembler support in Linux is reasonably crude as the vast majority of Linux programmers want to program in C and instead of doing the work to get an assembler up and going in Linux as a viable production tool, most are too lazy and prefer to paddle along with a C compiler.

I don't personally have any beef against a decent C compiler but comparing a Unix C compiler to a Windows assembler is something like comparing chalk and cheese. A C compiler has the advantage of portability between the host of badly supported versions of Linux but they are off the pace in a well known and extensive OS like 32 bit Windows and there are enough people floating around this forum who can prove it.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

frankvl

TinyCC is no better than VC indeed, just didn't know VC could do that; long time since I used it. It can be convenient to have the compiler/linker's source code though and be allowed to change it.

TinyCC gets the same results as Masm32 for normal Windows applications, that's why I compared them. Whether you use stdlib functions or not, C is a lot easier to use when you'll be dealing with stuff like inter-related structures, because you don't have to manage the register loading yourself. This was the tipping point for me at least, saved my a loooot of debugging ;) I also want to get rid of Windows dependency since Windows versions don't exactly get better.

You can omit MSVCRT dependency by providing an implementation for the original PE startup procedure, called _start, like this:

hello.c:


#include <windows.h>

void _start()
{
MessageBox(NULL, "Hello world!", "Look mom, no MessyShitVCRT!", MB_OK);
}


compile & link:
tcc -L "<installpath>/tcc-0.9.23/lib" -I "<installpath>/tcc-0.9.23/include" -I "<installpath>/tcc-0.9.23/include/winapi" -luser32 hello.c -o hello.exe


The resulting file is minimal, like Masm32. When you write code in _start to call a main(argc,argv) function (or use a custom library for that), you can still have platform independence.

Unfortunately, looking at the source code there seems to be no option to force tcc to call anything else then a msvcrt-type WinMain when you want a non-console app, but tccpe.c can be edited to link _winstart instead.

You can also still use printf etc if you want, the startup code won't be added, but most msvcrt functions are in kernel32 as well, so just define aliases (strlen = lstrlen, printf = wsprintf, etc) so your program can still be used by people who prefer other platforms.

japheth

thanks frank for the info!

tcc is pretty cool, IMO a very good tool for ASM coders, better than the MS bloatware.

there is also the "-static" option, which is supposed to link "statically", but I was unable to do that.

Do you know how to do that for Win32? There seems to be a problem with the underscore ("printf" instead of "_printf").

Vortex

libtcc1.a, the C runtime startup library supplied with TinyCC has two entry points _start and _winstart for console and GUI applications respectively. The compiler emits ELF object files so I decided to translate my own tiny C runtime startup modules to C modules with inline assembly. TinyCC accepts only the AT&T syntax to write inline assembly. Unfortunately, the compiler ignores the __declspec(naked) statement disabling the standard prologue\epilogue code. The solution was to patch the object modules to remove the overhead. Without removing the prologue\epilogue code, I could not terminate the modules with the ExitProcess function. Finally, I was able to eliminate the msvcrt.dll dependency and the size of the demo executable hello_win.exe decreased from 3584 bytes to 3072 bytes :

\tcc\tcc\tcc -ID:\tcc\include\winapi -ID:\tcc\include -L..\lib -lkernel32 -luser32 -lgdi32 hello_win.c ..\crt0ELF\crt0ELF.a -o hello_win.exe

I could not find a way to use my static library crt0ELF.a with TinyCC. The compiler emits the following error message :

\tcc\tcc\tcc -ID:\tcc\include\winapi -ID:\tcc\include -L..\lib -lkernel32 -luser32 -lgdi32 hello_win.c ..\crt0ELF\crt0ELF.a -o hello_win.exe

tcc: undefined symbol '_winstart'


crt0ELF.a is a static library including the two startup modules for console and GUI applications. I used the librarian ar.exe supplied with the MinGW package to build the static library :

\MinGW\bin\ar rc crt0ELF.a crt0cons.o crt0gui.o

Is there a way to use static libraries with TinyCC?

[attachment deleted by admin]

frankvl

I think _start and _winstart are compiler-specific names (i.e. not im-/exported in the exe), and that _winstart is not the name used by Masm32. If that is correct, it might help to change the name of the wingui entry point in your library (I think it's WinCRTStartup or something). It doesn't seem to be a problem with the -static option per se, but I've never used it, it could be that it hasn't been implemented properly yet for the PE format. You could check tcc.c and tccpe.c to see what it does.

Alternatively, you could write the asm in gnu assembler notation and compile everything with tcc. Or use C entirely; you don't need asm to get rid of the startup code/msvcrt dependency :)

You could further reduce the size (marginally) by using a PE tool to change the segments' alignment.

Vortex

Hi Frank,

You are right, the labels _start and _winstart are specific to the compiler TinyCC. Masm and the Visual C++ compilers are using the following the equivalents :

mainCRTStartup for console applications.
WinMainCRTStartup for GUI applications.

The -static switch does not seem to work for me. Specifying this switch, the compiler has troubles with finding the libraries :

\tcc\tcc\tcc -ID:\tcc\include\winapi -ID:\tcc\include -L..\lib -lkernel32 -luser32 -lgdi32 -static -lcrt0ELF.a hello_win.c -o hello_win.exe

tcc: cannot find -lkernel32


I prefer to use asm to code the tiny C startup module because it produces an output with the minimal size eliminating all the unnecessary overhead.

I know the PE tools, they can reduce the size of the final executable but I prefer to stay away from those tools to avoid potential compatibility problems across different versions of Windows.

Many thanks for your help, I will try the GNU assembler as.exe.

Timbo

The entry point of the executable belongs to the linker and not the compiler actually.  You also are not bound by the subsystem as to the choice of entry point i.e. you can specify /ENTRY:main or /ENTRY:mainCRTStartup for subsystem:windows applications.  This is in reference to ms link.