#!/usr/bin/perl # Copyright 2003, 2004, 2005, 2006, 2008, 2009, 2010 Red Hat, Inc. # # This file is part of Cygwin. # # This software is a copyrighted work licensed under the terms of the # Cygwin license. Please consult the file "CYGWIN_LICENSE" for # details. # use strict; sub cleanup(@); my $in = shift; my $tls_offsets = shift; my $out = shift; my $sigfe = shift; $main::first = 0; if (!defined($in) || !defined($out) || !defined($sigfe)) { die "usage: $0 deffile.in cygtls.h deffile.def sigfe.s\n"; } require $tls_offsets; open(IN, $in) or die "$0: couldn't open \"$in\" - $!\n"; my @top = (); while () { push(@top, cleanup $_); last if /^\s*exports\s*$/i; } my $libline = cleanup scalar(); my @in = cleanup ; close(IN); my %sigfe = (); my @data = (); my @nosigfuncs = (); my @text = (); for (@in) { chomp; s/\sDATA$//o and do { push @data, $_; next; }; if (/=/o) { if (s/\s+NOSIGFE\s*$//) { # nothing } elsif (s/ SIGFE(_MAYBE)?$//) { my $func = (split(' '))[2]; my $maybe = lc $1 . '_'; $sigfe{$func} = '_sigfe' . $maybe . $func; } } else { my ($func, $sigfe) = m%^\s*(\S+)(?:\s+((?:NO)?SIGFE(?:_MAYBE)?))?$%o; if (defined($sigfe) && $sigfe =~ /^NO/o) { $_ = $func; } else { $sigfe ||= 'sigfe'; $_ = '_' . lc($sigfe) . '_' . $func; $sigfe{$func} = $_; $_ = $func . ' = ' . $_; } } s/(\S)\s+(\S)/$1 $2/go; s/(\S)\s+$/$1/o; s/^\s+(\S)/$1/o; push @text, $_; } for (@text) { my ($alias, $func) = /^(\S+) = (\S+)\s*$/o; $_ = $alias . ' = ' . $sigfe{$func} if defined($func) && $sigfe{$func}; } open(OUT, '>', $out) or die "$0: couldn't open \"$out\" - $!\n"; push @top, (map {$_ . " DATA\n"} @data), (map {$_ . "\n"} @text); print OUT @top; close OUT; open(SIGFE, '>', $sigfe) or die "$0: couldn't open sigfe file \"$sigfe\" - $!\n"; for my $k (sort keys %sigfe) { print SIGFE fefunc($k, $sigfe{$k}); } close SIGFE; sub fefunc { my $func = '_' . shift; my $fe = '_' . shift; my $sigfe_func = ($fe =~ /^(.*)$func/)[0]; my $extra; my $res = < than tls jge 0f # yep. we don't have a tls. subl \$$tls::initialized,%ebx # where we will be looking movl $tls::initialized(%ebx),%eax cmpl \$0xc763173f,%eax # initialized? je 1f 0: popl %edx popl %ebx ret __sigfe: pushl %ebx pushl %edx movl %fs:4,%ebx # location of bottom of stack 1: movl \$1,%eax # potential lock value xchgl %eax,$tls::stacklock(%ebx) # see if we can grab it movl %eax,$tls::spinning(%ebx) # flag if we are waiting for lock testl %eax,%eax # it will be zero jz 2f # if so call _yield # should be a short-time thing, so jmp 1b # sleep and loop 2: movl \$4,%eax # have the lock, now increment the xadd %eax,$tls::stackptr(%ebx) # stack pointer and get pointer leal __sigbe,%edx # new place to return to xchgl %edx,12(%esp) # exchange with real return value movl %edx,(%eax) # store real return value on alt stack incl $tls::incyg(%ebx) decl $tls::stacklock(%ebx) # remove lock popl %edx # restore saved value popl %ebx ret .global __sigbe __sigbe: # return here after cygwin syscall pushl %eax # don't clobber pushl %ebx # tls pointer 1: movl %fs:4,%ebx # address of bottom of tls movl \$1,%eax # potential lock value xchgl %eax,$tls::stacklock(%ebx) # see if we can grab it movl %eax,$tls::spinning(%ebx) # flag if we are waiting for lock testl %eax,%eax # it will be zero jz 2f # if so call _yield # sleep jmp 1b # and loop 2: movl \$-4,%eax # now decrement aux stack xadd %eax,$tls::stackptr(%ebx) # and get pointer movl -4(%eax),%eax # get return address from signal stack xchgl %eax,4(%esp) # swap return address with saved eax decl $tls::incyg(%ebx) decl $tls::stacklock(%ebx) # release lock popl %ebx ret .global _sigdelayed _sigdelayed: pushl %ebp movl %esp,%ebp pushf pushl %esi pushl %edi pushl %edx pushl %ecx pushl %ebx pushl %eax movl %fs:4,%ebx # get tls pushl $tls::saved_errno(%ebx) # saved errno movl \$$tls::start_offset,%eax # point to beginning addl %ebx,%eax # of tls block call __ZN7_cygtls19call_signal_handlerEv # call handler movl %fs:4,%ebx # reget tls 1: movl \$1,%eax # potential lock value xchgl %eax,$tls::stacklock(%ebx) # see if we can grab it movl %eax,$tls::spinning(%ebx) # flag if we are waiting for lock testl %eax,%eax # it will be zero jz 2f # if so call _yield # sleep jmp 1b # and loop 2: popl %edx # saved errno testl %edx,%edx # Is it < 0 jl 3f # yup. ignore it movl $tls::errno_addr(%ebx),%eax movl %edx,(%eax) 3: movl \$-4,%eax # now decrement aux stack xadd %eax,$tls::stackptr(%ebx) # and get pointer xorl %ebp,%ebp xchgl %ebp,-4(%eax) # get return address from signal stack xchgl %ebp,28(%esp) # store real return address leave: xorl %eax,%eax movl %eax,$tls::incyg(%ebx) movl %eax,$tls::stacklock(%ebx) # unlock popl %eax popl %ebx popl %ecx popl %edx popl %edi popl %esi popf ret .global __ZN7_cygtls3popEv __ZN7_cygtls3popEv: 1: pushl %ebx movl %eax,%ebx # this movl \$-4,%eax xadd %eax,$tls::pstackptr(%ebx) movl -4(%eax),%eax popl %ebx ret .global __ZN7_cygtls4lockEv __ZN7_cygtls4lockEv: pushl %ebx movl %eax,%ebx 1: movl \$1,%eax xchgl %eax,$tls::pstacklock(%ebx) testl %eax,%eax jz 2f call _yield jmp 1b 2: popl %ebx ret .global __ZN7_cygtls6unlockEv __ZN7_cygtls6unlockEv: decl $tls::pstacklock(%eax) ret .global __ZN7_cygtls6lockedEv __ZN7_cygtls6lockedEv: movl $tls::pstacklock(%eax),%eax ret .extern __ZN7_cygtls19call_signal_handlerEv stabilize_sig_stack: movl %fs:4,%ebx 1: movl \$1,%eax xchgl %eax,$tls::stacklock(%ebx) movl %eax,$tls::spinning(%ebx) # flag if we are waiting for lock testl %eax,%eax jz 2f call _yield jmp 1b 2: incl $tls::incyg(%ebx) cmpl \$0,$tls::sig(%ebx) jz 3f decl $tls::stacklock(%ebx) # unlock movl \$$tls::start_offset,%eax # point to beginning addl %ebx,%eax # of tls block call __ZN7_cygtls19call_signal_handlerEv jmp 1b 3: decl $tls::incyg(%ebx) ret EOF } return $res; } sub longjmp { return <