#!/usr/bin/perl # Copyright 2003, 2004, 2005, 2006, 2008 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 (<IN>) { push(@top, cleanup $_); last if /^\s*exports\s*$/i; } my $libline = cleanup scalar(<IN>); my @in = cleanup <IN>; 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 = <<EOF; .extern $func .global $fe $fe: pushl \$$func jmp $sigfe_func EOF if (!$main::first++) { $res = <<EOF . longjmp () . $res; .text __sigfe_maybe: pushl %ebx pushl %edx movl %fs:4,%ebx # location of bottom of stack addl \$$tls::initialized,%ebx # where we will be looking cmpl %ebx,%esp # stack loc > 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 lock 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 xorl %eax,%eax # nope. It was not zero call _low_priority_sleep # 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 %edx pushl %ebx pushl %eax # don't clobber 1: movl %fs:4,%ebx # address of bottom of tls movl \$1,%eax # potential lock value lock 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 xorl %eax,%eax # nope. not zero call _low_priority_sleep # sleep jmp 1b # and loop 2: movl \$-4,%eax # now decrement aux stack xadd %eax,$tls::stackptr(%ebx) # and get pointer xorl %edx,%edx xchgl %edx,-4(%eax) # get return address from signal stack xchgl %edx,8(%esp) # restore edx/real return address decl $tls::incyg(%ebx) decl $tls::stacklock(%ebx) # release lock popl %eax popl %ebx ret .global _sigreturn _sigreturn: movl %fs:4,%ebx incl $tls::incyg(%ebx) addl \$12,%esp # remove arguments call _set_process_mask\@4 1: movl \$1,%eax # potential lock value lock 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 xorl %eax,%eax # nope. not zero call _low_priority_sleep # 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 decl $tls::incyg(%ebx) decl $tls::stacklock(%ebx) # unlock popl %eax popl %ebx popl %ecx popl %edx popl %edi popl %esi popf 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 incl $tls::incyg(%ebx) pushl $tls::saved_errno(%ebx) # saved errno call _set_process_mask_delta pushl %eax # fill out handler arguments xorl %eax,%eax # ucontext_t (currently not set) pushl %eax leal $tls::infodata(%ebx),%eax pushl %eax # siginfo pushl $tls::sig(%ebx) # signal number call _reset_signal_arrived\@0 pushl \$_sigreturn # where to return pushl $tls::func(%ebx) # signal func cmpl \$0,$tls::threadkill(%ebx)#pthread_kill signal? jnz 4f # yes. callee clears signal number movl \$0,$tls::sig(%ebx) # zero the signal number as a # flag to the signal handler thread # that it is ok to set up sigsave 4: decl $tls::incyg(%ebx) ret .global __ZN7_cygtls3popEv __ZN7_cygtls3popEv: 1: pushl %ebx pushl %edx # FIXME: needed? movl %eax,%ebx movl \$-4,%edx xadd %edx,$tls::pstackptr(%ebx) xorl %eax,%eax xchgl %eax,-4(%edx) popl %edx # FIXME: needed? popl %ebx ret .global __ZN7_cygtls4lockEv __ZN7_cygtls4lockEv: pushl %ebx movl %eax,%ebx 1: movl \$1,%eax lock xchgl %eax,$tls::pstacklock(%ebx) testl %eax,%eax jz 2f xorl %eax,%eax call _low_priority_sleep 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 incl $tls::incyg(%ebx) 1: movl \$1,%eax lock xchgl %eax,$tls::stacklock(%ebx) movl %eax,$tls::spinning(%ebx) # flag if we are waiting for lock testl %eax,%eax jz 2f xorl %eax,%eax call _low_priority_sleep jmp 1b 2: cmpl \$0,$tls::sig(%ebx) jz 3f decl $tls::stacklock(%ebx) # unlock movl \$-$tls::sizeof__cygtls,%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 <<EOF; .globl _setjmp _setjmp: pushl %ebp movl %esp,%ebp pushl %edi movl 8(%ebp),%edi movl %eax,0(%edi) movl %ebx,4(%edi) movl %ecx,8(%edi) movl %edx,12(%edi) movl %esi,16(%edi) movl -4(%ebp),%eax movl %eax,20(%edi) movl 0(%ebp),%eax movl %eax,24(%edi) movl %esp,%eax addl \$12,%eax movl %eax,28(%edi) movl 4(%ebp),%eax movl %eax,32(%edi) movw %es,%ax movw %ax,36(%edi) movw %fs,%ax movw %ax,38(%edi) movw %gs,%ax movw %ax,40(%edi) movw %ss,%ax movw %ax,42(%edi) movl %fs:0,%eax movl %eax,44(%edi) pushl %ebx call stabilize_sig_stack movl $tls::stackptr(%ebx),%eax # save stack pointer contents decl $tls::stacklock(%ebx) popl %ebx movl %eax,48(%edi) popl %edi movl \$0,%eax leave ret .globl ___sjfault ___sjfault: pushl %ebp movl %esp,%ebp pushl %edi movl 8(%ebp),%edi movl %eax,0(%edi) movl %ebx,4(%edi) movl %ecx,8(%edi) movl %edx,12(%edi) movl %esi,16(%edi) movl -4(%ebp),%eax movl %eax,20(%edi) movl 0(%ebp),%eax movl %eax,24(%edi) movl %esp,%eax addl \$12,%eax movl %eax,28(%edi) movl 4(%ebp),%eax movl %eax,32(%edi) movw %es,%ax movw %ax,36(%edi) movw %fs,%ax movw %ax,38(%edi) movw %gs,%ax movw %ax,40(%edi) movw %ss,%ax movw %ax,42(%edi) movl %fs:0,%eax movl %eax,44(%edi) popl %edi movl \$0,%eax leave ret .global ___ljfault ___ljfault: pushl %ebp movl %esp,%ebp movl 8(%ebp),%edi movl 12(%ebp),%eax testl %eax,%eax jne 0f incl %eax 0: movl %eax,0(%edi) movl 24(%edi),%ebp pushfl popl %ebx movl 44(%edi),%eax movl %eax,%fs:0 movw 42(%edi),%ax movw %ax,%ss movl 28(%edi),%esp pushl 32(%edi) pushl %ebx movw 36(%edi),%ax movw %ax,%es movw 40(%edi),%ax movw %ax,%gs movl 0(%edi),%eax movl 4(%edi),%ebx movl 8(%edi),%ecx movl 16(%edi),%esi movl 12(%edi),%edx movl 20(%edi),%edi popfl ret .globl _longjmp _longjmp: pushl %ebp movl %esp,%ebp movl 8(%ebp),%edi # address of buffer call stabilize_sig_stack movl 48(%edi),%eax # get old signal stack movl %eax,$tls::stackptr(%ebx) # restore decl $tls::stacklock(%ebx) # relinquish lock xorl %eax,%eax movl %eax,$tls::incyg(%ebx) # we're definitely not in cygwin anymore movl 12(%ebp),%eax testl %eax,%eax jne 3f incl %eax 3: movl %eax,0(%edi) movl 24(%edi),%ebp pushfl popl %ebx movl 44(%edi),%eax movl %eax,%fs:0 movw 42(%edi),%ax movw %ax,%ss movl 28(%edi),%esp pushl 32(%edi) pushl %ebx movw 36(%edi),%ax movw %ax,%es movw 40(%edi),%ax movw %ax,%gs movl 0(%edi),%eax movl 4(%edi),%ebx movl 8(%edi),%ecx movl 16(%edi),%esi movl 12(%edi),%edx movl 20(%edi),%edi popfl ret EOF } sub cleanup(@) { map {s/\r//g; $_} @_; map {s/#.*//g; $_} @_; map {s/[ \t]+$//g; $_} @_; }