PATCH: glibc 2.3.x and errno

Marcus Meissner marcus at jet.franken.de
Sat Jan 25 08:22:21 CST 2003


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



More information about the wine-devel mailing list