Hi Marcus,
__errno_location and __h_errno_location are no longer weak symbols and so can not be overwritten any longer. The internal glibc systemcall wrappers no longer call the functions by reference, but directly.
the real problem is even worse. glibc has switched to using thread-local storage for errno (i.e. it is declared as 'extern __thread int errno') when the tool chain supports the __thread keyword.
This means that C source code compiled against the new headers will result in assembler code that *directly* accesses a thread-local variable as defined by the TLS ABI. In the case of errno, this will involve accessing the %gs segment using an offset from the GOT, without any function call being performed. (errno is defined to use the initial-exec TLS storage model.)
The __errno_location routine is provided only for backwards compatibility reasons, it is no longer guaranteed that every access to errno calls it. Thus, if you overwrite the implementation of __errno_location, you will only catch *some* errno accesses, not all of them ...
Bye, Ulrich (who has just implemented TLS for s390 ;-/)
On Fri, 24 Jan 2003, Ulrich Weigand wrote: [...]
This means that C source code compiled against the new headers will result in assembler code that *directly* accesses a thread-local variable as defined by the TLS ABI. In the case of errno, this will involve accessing the %gs segment using an offset from the GOT, without any function call being performed. (errno is defined to use the initial-exec TLS storage model.)
I probably only have a limited understanding of these threading problems. However I had an idea and this limited knowledge lead me to believe that it might work and so now I have to inflict it on the world<g>.
So basically the problem as I understand it is that both Linux libraries and some Windows applications believe that the %gs register points to a TLS structure, except that these two structures are not compatible.
Hmmm, wait a minute, could they be made compatible? E.g. by changing the struct definition in glibc? Anyway, assuming that's not possible...
So we basically need separate values for this register for the Windows code and the Linux code.
So why not save and restore that register whenever we enter and exit a builtin dll?
It seems that it should be pretty easy to modify each DLL entry point to do:
{ wine_restore_linux_gs(); ... wine_restore_windows_gs(); return ret; }
Of course, the DLL entry points are the easy part. The hard part is:
* modifying all code that invokes a callback function to first restore the windows %gs and the linux one when the call returns * modifying all builtin callback functions to do the same as entry points * modifying all COM functions
Well, now I will let people who know better explain why this cannot work :-)
On Sat, Jan 25, 2003 at 04:43:09AM -0800, Francois Gouget wrote:
On Fri, 24 Jan 2003, Ulrich Weigand wrote: [...]
This means that C source code compiled against the new headers will result in assembler code that *directly* accesses a thread-local variable as defined by the TLS ABI. In the case of errno, this will involve accessing the %gs segment using an offset from the GOT, without any function call being performed. (errno is defined to use the initial-exec TLS storage model.)
I probably only have a limited understanding of these threading problems. However I had an idea and this limited knowledge lead me to believe that it might work and so now I have to inflict it on the world<g>.
So basically the problem as I understand it is that both Linux libraries and some Windows applications believe that the %gs register points to a TLS structure, except that these two structures are not compatible.
No, this is just a side problem only for 16bit applications.
The problem is different.
Lets have a small example: wine does: #include <errno.h> ... ret = mkdir("/blub/"); if (ret == -1) { fprintf(stderr,"mkdir failed with errno %d\n",errno); exit(1); }
In 1980 this was rather nice and worked all the time with the nice global 'errno' integer variable. However, someone had to invent multi threading.
After this, errno could not stay a global integer variable, since you could get into race conditions writing/accessing it. Sinc millions of lines of code could not be changed, the <errno.h> header was changed to defined it as:
extern int *__errno_location(); #define errno *(__errno_location())
With __errno_location (or similar) a function that returns a pointer to an integer variable within the thread local storage area.
(The same goes for __h_errno_location and other internal functions.)
The glibc implementation basically does: ... convert registers ... int 0x80 jae error lret... error: ... lcall __errno_location mov errorcode , ($eax) ... lret
glibc follows the pthread style of threading, at the time WINE needed threading implemented by SIGALRM timers within a single process (clone(2) was not invented yet).
As WINE started Win32 threading the clone(2) handler was available for us and we implemented our own kind of threading, Windows style. glibc however does not know a single thing about that and still assumes there is no threading and had __errno_location return a single pointer.
So we had to overwrite __errno_location(), which was easy possible, since libpthread also did so and it was exported as weak symbol meant to be overwritten.
However with glibc 2.3 the internal thread representation changed, most pthread libraries now use clone(2) too, and use a new way of Thread Local Storage, using a segment register. Since WINE was using %fs, they chose to use %gs.
Now a system call looks like: ... convert registers ... int 0x80 jae error lret... error: ... mov errorcode , %gs:(offset) ... lret
So we no longer can overwrite __errno_location to have our own errno storage, so we need to cooperate with the libc threading.
Ciao, Marcus