#!/usr/bin/perl # Copyright 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011, 2012, 2013 # 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; use integer; use Getopt::Long; sub cleanup(@); my $cpu; my $output_def; my $tls_offsets; GetOptions('cpu=s'=>\$cpu, 'output-def=s'=>\$output_def, 'tlsoffsets=s'=>\$tls_offsets); $main::first = 0; if (!defined($cpu) || !defined($output_def) || !defined($tls_offsets)) { die "$0: missing required option\n"; } require $tls_offsets; my $is64bit = $cpu eq 'x86_64'; my $sym_prefix = $is64bit ? '' : '_'; my @top = (); while (<>) { push(@top, cleanup $_); last if /^\s*exports$/oi; } my @in = cleanup <>; my %sigfe = (); my @data = (); my @nosigfuncs = (); my @text = (); for (@in) { chomp; s/\s+DATA$//o and do { push @data, $_; next; }; if (/=/o) { if (s/\s+NOSIGFE\s*$//) { # nothing } elsif (s/\s+SIGFE(_MAYBE)?$//) { my $func = (split(' '))[2]; my $maybe = (defined($1) ? 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+(\S+)\s*$/o; $_ = $alias . ' = ' . $sigfe{$func} if defined($func) && $sigfe{$func}; } open OUT, '>', $output_def or die "$0: couldn't open \"$output_def\" - $!\n"; push @top, (map {$_ . " DATA\n"} @data), (map {$_ . "\n"} @text); print OUT @top; close OUT; open SIGFE, '>', 'sigfe.h' or die "$0: couldn't open 'sigfe.h' file for writing - $!\n"; for my $k (sort keys %sigfe) { print SIGFE fefunc($k, $sigfe{$k}); } close SIGFE; sub fefunc { my $func = $sym_prefix . shift; my $fe = $sym_prefix . shift; my $sigfe_func; if ($is64bit) { $sigfe_func = ($fe =~ /^(.*)_${func}$/)[0]; } else { $sigfe_func = ($fe =~ /^(.*)${func}$/)[0]; } my $extra; my $res; if ($is64bit) { $res = < than tls jge 0f # yep. we don't have a tls. subq \$$tls::initialized,%r12 # where we will be looking movl $tls::initialized(%r12),%r11d cmpl \$0xc763173f,%r11d # initialized? je 1f 0: popq %r12 ret .seh_endproc .seh_proc _sigfe _sigfe: # stack is aligned on entry! pushq %r12 .seh_pushreg %r12 .seh_endprologue movq %gs:8,%r12 # location of bottom of stack 1: movl \$1,%r11d # potential lock value xchgl %r11d,$tls::stacklock(%r12) # see if we can grab it movl %r11d,$tls::spinning(%r12) # flag if we are waiting for lock testl %r11d,%r11d # it will be zero jz 2f # if so pause jmp 1b # loop 2: movq \$8,%rax # have the lock, now increment the xaddq %rax,$tls::stackptr(%r12) # stack pointer and get pointer leaq _sigbe(%rip),%r11 # new place to return to xchgq %r11,16(%rsp) # exchange with real return value movq %r11,(%rax) # store real return value on alt stack incl $tls::incyg(%r12) decl $tls::stacklock(%r12) # remove lock popq %r12 # restore saved value popq %rax # pop real function address from stack jmp *%rax # and jmp to it .seh_endproc .seh_proc _sigfe _sigbe: # return here after cygwin syscall # stack is aligned on entry! pushq %r12 .seh_pushreg %r12 .seh_endprologue movq %gs:8,%r12 # address of bottom of tls 1: movl \$1,%r11d # potential lock value xchgl %r11d,$tls::stacklock(%r12) # see if we can grab it movl %r11d,$tls::spinning(%r12) # flag if we are waiting for lock testl %r11d,%r11d # it will be zero jz 2f # if so pause jmp 1b # and loop 2: movq \$-8,%r11 # now decrement aux stack xaddq %r11,$tls::stackptr(%r12) # and get pointer movq -8(%r11),%r11 # get return address from signal stack decl $tls::incyg(%r12) decl $tls::stacklock(%r12) # release lock popq %r12 jmp *%r11 # "return" to caller .seh_endproc .global sigdelayed .seh_proc sigdelayed sigdelayed: pushq %r10 # used for return address injection .seh_pushreg %rbp pushq %rbp .seh_pushreg %rbp movq %rsp,%rbp # stack is aligned or unaligned on entry! # make sure it is aligned from here on # We could be called from an interrupted thread which doesn't know # about his fate, so save and restore everything and the kitchen sink. andq \$0xfffffffffffffff0,%rsp .seh_setframe %rbp,0 pushq %r15 .seh_pushreg %r15 pushq %r14 .seh_pushreg %r14 pushq %r13 .seh_pushreg %r13 pushq %r12 .seh_pushreg %r12 pushq %r11 .seh_pushreg %r11 pushq %r9 .seh_pushreg %r9 pushq %r8 .seh_pushreg %r8 pushq %rsi .seh_pushreg %rsi pushq %rdi .seh_pushreg %rdi pushq %rdx .seh_pushreg %rdx pushq %rcx .seh_pushreg %rcx pushq %rbx .seh_pushreg %rbx pushq %rax .seh_pushreg %rax pushf subq \$0x120,%rsp .seh_stackalloc 0x120 movdqa %xmm15,0x110(%rsp) movdqa %xmm14,0x100(%rsp) movdqa %xmm13,0xf0(%rsp) movdqa %xmm12,0xe0(%rsp) movdqa %xmm11,0xd0(%rsp) movdqa %xmm10,0xc0(%rsp) movdqa %xmm9,0xb0(%rsp) movdqa %xmm8,0xa0(%rsp) movdqa %xmm7,0x90(%rsp) movdqa %xmm6,0x80(%rsp) movdqa %xmm5,0x70(%rsp) movdqa %xmm4,0x60(%rsp) movdqa %xmm3,0x50(%rsp) movdqa %xmm2,0x40(%rsp) movdqa %xmm1,0x30(%rsp) movdqa %xmm0,0x20(%rsp) .seh_endprologue movq %gs:8,%r12 # get tls movl $tls::saved_errno(%r12),%r15d # temporarily save saved_errno movq \$$tls::start_offset,%rcx # point to beginning of tls block addq %r12,%rcx # and store as first arg to method call _ZN7_cygtls19call_signal_handlerEv # call handler 1: movl \$1,%r11d # potential lock value xchgl %r11d,$tls::stacklock(%r12) # see if we can grab it movl %r11d,$tls::spinning(%r12) # flag if we are waiting for lock testl %r11d,%r11d # it will be zero jz 2f # if so pause jmp 1b # and loop 2: testl %r15d,%r15d # was saved_errno < 0 jl 3f # yup. ignore it movq $tls::errno_addr(%r12),%r11 movl %r15d,(%r11) 3: movq \$-8,%r11 # now decrement aux stack xaddq %r11,$tls::stackptr(%r12) # and get pointer xorq %r10,%r10 xchgq %r10,-8(%r11) # get return address from signal stack xorl %r11d,%r11d movl %r11d,$tls::incyg(%r12) movl %r11d,$tls::stacklock(%r12) # unlock movdqa 0x20(%rsp),%xmm0 movdqa 0x30(%rsp),%xmm1 movdqa 0x40(%rsp),%xmm2 movdqa 0x50(%rsp),%xmm3 movdqa 0x60(%rsp),%xmm4 movdqa 0x70(%rsp),%xmm5 movdqa 0x80(%rsp),%xmm6 movdqa 0x90(%rsp),%xmm7 movdqa 0xa0(%rsp),%xmm8 movdqa 0xb0(%rsp),%xmm9 movdqa 0xc0(%rsp),%xmm10 movdqa 0xd0(%rsp),%xmm11 movdqa 0xe0(%rsp),%xmm12 movdqa 0xf0(%rsp),%xmm13 movdqa 0x100(%rsp),%xmm14 movdqa 0x110(%rsp),%xmm15 addq \$0x120,%rsp popf popq %rax popq %rbx popq %rcx popq %rdx popq %rdi popq %rsi popq %r8 popq %r9 popq %r11 popq %r12 popq %r13 popq %r14 popq %r15 movq %rbp,%rsp popq %rbp xchgq %r10,(%rsp) ret .seh_endproc # _cygtls::pop .global _ZN7_cygtls3popEv .seh_proc _ZN7_cygtls3popEv _ZN7_cygtls3popEv: .seh_endprologue movq \$-8,%r11 xaddq %r11,$tls::pstackptr(%rcx) movq -8(%r11),%rax ret .seh_endproc # _cygtls::lock .global _ZN7_cygtls4lockEv .seh_proc _ZN7_cygtls4lockEv _ZN7_cygtls4lockEv: pushq %r12 .seh_pushreg %r12 .seh_endprologue movq %rcx,%r12 1: movl \$1,%r11d xchgl %r11d,$tls::pstacklock(%r12) testl %r11d,%r11d jz 2f pause jmp 1b 2: popq %r12 ret .seh_endproc # _cygtls::unlock .global _ZN7_cygtls6unlockEv .seh_proc _ZN7_cygtls6unlockEv _ZN7_cygtls6unlockEv: .seh_endprologue decl $tls::pstacklock(%rcx) ret .seh_endproc # _cygtls::locked .global _ZN7_cygtls6lockedEv .seh_proc _ZN7_cygtls6lockedEv _ZN7_cygtls6lockedEv: .seh_endprologue movl $tls::pstacklock(%rcx),%eax ret .seh_endproc .seh_proc stabilize_sig_stack stabilize_sig_stack: pushq %r12 .seh_pushreg %r12 subq \$0x20,%rsp .seh_stackalloc 32 .seh_endprologue movq %gs:8,%r12 1: movl \$1,%r10d xchgl %r10d,$tls::stacklock(%r12) movl %r10d,$tls::spinning(%r12) # flag if we are waiting for lock testl %r10d,%r10d jz 2f pause jmp 1b 2: incl $tls::incyg(%r12) cmpl \$0,$tls::sig(%r12) jz 3f decl $tls::stacklock(%r12) # unlock movq \$$tls::start_offset,%rcx # point to beginning addq %r12,%rcx # of tls block call _ZN7_cygtls19call_signal_handlerEv jmp 1b 3: decl $tls::incyg(%r12) addq \$0x20,%rsp movq %r12,%r11 # return tls addr in r11 popq %r12 ret .seh_endproc EOF } else { $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\@4 # 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\@4 __ZN7_cygtls3popEv\@4: 1: pushl %ebx movl %eax,%ebx # this movl \$-4,%eax xadd %eax,$tls::pstackptr(%ebx) movl -4(%eax),%eax popl %ebx ret # _cygtls::lock .global __ZN7_cygtls4lockEv\@4 __ZN7_cygtls4lockEv\@4: 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 # _cygtls::unlock .global __ZN7_cygtls6unlockEv\@4 __ZN7_cygtls6unlockEv\@4: decl $tls::pstacklock(%eax) ret .global __ZN7_cygtls6lockedEv __ZN7_cygtls6lockedEv: movl $tls::pstacklock(%eax),%eax ret .extern __ZN7_cygtls19call_signal_handlerEv\@4 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\@4 jmp 1b 3: decl $tls::incyg(%ebx) ret EOF } } return $res; } sub longjmp { if ($is64bit) { return <