| #!/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 nocr(@); |
| 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, nocr $_); |
| last if /^\s*exports\s*$/i; |
| } |
| my $libline = nocr scalar(<IN>); |
| my @in = nocr <IN>; |
| close(IN); |
| |
| my %sigfe = (); |
| my @data = (); |
| my @nosigfuncs = (); |
| my @out = (); |
| for (@in) { |
| /\sDATA$/o and do { |
| push(@data, $_); |
| next; |
| }; |
| chomp; |
| 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(@out, $_ . "\n"); |
| } |
| |
| for (@out) { |
| my ($alias, $func) = /^(\S+) = (\S+)\s*$/o; |
| $_ = $alias . ' = ' . $sigfe{$func} . "\n" |
| if defined($func) && $sigfe{$func}; |
| } |
| open(OUT, '>', $out) or die "$0: couldn't open \"$out\" - $!\n"; |
| print OUT @top, @data, @out; |
| 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 |
| |
| .stabs "_sigfe:F(0,1)",36,0,0,__sigfe |
| __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 |
| .stabs "_sigbe:F(0,1)",36,0,0,__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 |
| .stabs "sigreturn:F(0,1)",36,0,0,_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 |
| .stabs "sigdelayed:F(0,1)",36,0,0,_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 nocr(@) { |
| map {s/\r//g; $_} @_; |
| } |