[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Tinycc-devel] Odd problem when using variables defined in header files

From: William Hales
Subject: [Tinycc-devel] Odd problem when using variables defined in header files for a .dll
Date: Wed, 8 Mar 2017 09:41:22 +1100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0 SeaMonkey/2.46


I have been having a problem with tcc when linking my project against a dll. The dll and my project share variables through a header file. This works fine with gcc, but when compiled with tcc my program and the dll end up with completely unique copies of the variables in the .h file, rather than sharing them.

I've made a simple example to demonstrate this:

    http://halestrom.net/misc/tcc/bad_tcc_light.zip   (2.8M)
    http://halestrom.net/misc/tcc/bad_tcc.zip    (111M)

Both of these archives demonstrate the problem, but the second once contains a full copy of mingw gcc so you can verify how the .dll is compiled.

Below is the full contents of the readme.txt included in my example.

Can anyone help me? Is this a compiler bug, a non-standard part of C, or me just being silly?

Regards, Hales

== The problem ==

This archive demonstrates I problem I have with tcc on Windows.

Abbreviated compile command:

   tcc -L. -lpdcurses -I windows_toolchain\PDcurses-modified\
   main.c -o bad.exe

The code in main.c and the code in pdcurses.dll both need access to
pointers (such as WINDOW *stdscr) that are defined in curses.h.

During runtime the code in main.c sees a completely different copy of
these pointers to the code in the dll.  This does not make much sense to
me, and does not occur if I use gcc to compile the .exe

I have no clue why this going on :|

== What's in this archive ==

 * a library called PDcurses, that we compile into pdcurses.dll
 * a small program (main.c) to demonstrate the problem
 * a batch file that compiles this program
 * the latest release copy of tcc (926)
 * a semi-recent compile of tcc from git (a few weeks old IIRC)
 * a gcc toolchain from mingw64 (32 bit version)
 * compiled versions of main.c (for the lazy) named bad_*.exe

== How to use this archive ==

Run "build.bat" by double-clicking it (on Windows) or through
wineconsole (on Linux).  It will delete all existing .exe, .o and .dll
files before recompiling everything (including the dll).

Three executables result (each compiled by a different compiler):

 * bad_tcc926.exe  (shows the problem)
 * bad_tccgit.exe  (shows the problem)
 * bad_gcc.exe     (no problem, works as expected)

I have modified the PDcurses library by adding a function called
hales_test_hack_get_stdscr().  All it does is return the value of
WINDOW *stdscr as seen by the code in the DLL.

main.c prints out what *stdscr looks like from both main.c's point of
view and from the dll's point of view (using my added function).  It
does this before and after running a function in the dll that should
modify the value of *stdscr.

The output of my example program should look like this:

    WINDOW *stdscr is defined in curses.h

    Before we initialised curses, it pointed to:
            00000000 (from our point of view)
            00000000 (from pdcurses.dll's point of view)

    After we initialised curses, it pointed to:
            0024EEA8 (from our point of view)
            0024EEA8 (from pdcurses.dll's point of view

Instead it looks like this:

    WINDOW *stdscr is defined in curses.h

    Before we initialised curses, it pointed to:
            6705ED88 (from our point of view)
            00000000 (from pdcurses.dll's point of view)

    After we initialised curses, it pointed to:
            6705ED88 (from our point of view)
            0041F250 (from pdcurses.dll's point of view)

== Mostly irrelevant backstory: how I came across this issue ==

I have been writing a small, toy project on Linux.  It uses the common
ncurses library to draw text in a console and I've been using GCC to
compile it.

I wanted to get this project working on Windows.  Ncurses did not have
a win32 variant, but I found another curses implementation called
PDcurses (public domain curses) which did.  I built this as a dll, used
gcc, spent some time porting some OS specific functions (mainly to do
with timing and file IO) and my program worked.

I then wanted to get it to build using tcc.  The GCC toolchain on
Windows is quite large, and I wanted to distribute my program in a form
that other people could be instantly able to modify and recompile
without having to run any toolchain setup gauntlets.   TCC would be
perfect for this.

A few system header files differed, and access() didn't exist, but apart
from that things were not too hard to port.

Except that my program would segfault immediately upon opening.

Through lots of fiddling I eventually found that using the *stdscr
pointer anywhere in my code would cause my program to crash.  I
confirmed this through gdb.

For the most part I can avoid this in curses, as the curses spec
provides two variants of most functions:

     addch(char c);
    waddch(WINDOW *win, char c);

The former assumes you want to add a character to stdscr.  The latter
requires you to tell it which window to draw to.

addch() is implemented as a proper function, not a macro wrapper around
waddch().  This way the .dll handles tracking of WINDOW *stdscr rather
than me, avoiding the problem.

== Misc Notes on PDcurses ==

I'm using PDcurses in this example because it's the .dll I have at hand.
I presume my problem is a compiler behaviour, and does not have to do
with the pdcurses code specifically.

PDcurses gets recompiled from scratch when you run my build.bat, so
you can look at the source of build.bat to see what's going on.

I have added flags to PDcurses' makefile so GCC makes a static dll
(otherwise I need to copy over several mingw-gcc libs such as

reply via email to

[Prev in Thread] Current Thread [Next in Thread]