#!/usr/bin/perl # # 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; GetOptions('cpu=s'=>\$cpu, 'output-def=s'=>\$output_def); $main::first = 0; if (!defined($cpu) || !defined($output_def)) { die "$0: missing required option\n"; } my $is_x86_64 = $cpu eq 'x86_64'; # FIXME? Do other (non-32 bit) arches on Windows still use symbol prefixes? my $sym_prefix = ''; 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.s' or die "$0: couldn't open 'sigfe.s' 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 ($is_x86_64) { $sigfe_func = ($fe =~ /^(.*)_${func}$/)[0]; } my $extra; my $res; if ($is_x86_64) { $res = < than tls jge 0f # yep. we don't have a tls. movl _cygtls.initialized(%r10),%r11d cmpl \$0xc763173f,%r11d # initialized? je 1f 0: ret .seh_endproc .seh_proc _sigfe _sigfe: # stack is aligned on entry! .seh_endprologue movq %gs:8,%r10 # location of bottom of stack 1: movl \$1,%r11d # potential lock value xchgl %r11d,_cygtls.stacklock(%r10) # see if we can grab it movl %r11d,_cygtls.spinning(%r10) # 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,_cygtls.stackptr(%r10) # stack pointer and get pointer leaq _sigbe(%rip),%r11 # new place to return to xchgq %r11,8(%rsp) # exchange with real return value movq %r11,(%rax) # store real return value on alt stack incl _cygtls.incyg(%r10) decl _cygtls.stacklock(%r10) # remove lock popq %rax # pop real function address from stack jmp *%rax # and jmp to it .seh_endproc .global _sigbe .seh_proc _sigbe _sigbe: # return here after cygwin syscall # stack is aligned on entry! .seh_endprologue movq %gs:8,%r10 # address of bottom of tls 1: movl \$1,%r11d # potential lock value xchgl %r11d,_cygtls.stacklock(%r10) # see if we can grab it movl %r11d,_cygtls.spinning(%r10) # 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,_cygtls.stackptr(%r10) # and get pointer movq -8(%r11),%r11 # get return address from signal stack decl _cygtls.incyg(%r10) decl _cygtls.stacklock(%r10) # release lock jmp *%r11 # "return" to caller .seh_endproc .global sigdelayed .seh_proc sigdelayed sigdelayed: pushq %r10 # used for return address injection .seh_pushreg %r10 pushq %rbp .seh_pushreg %rbp movq %rsp,%rbp pushf .seh_pushreg %rax # fake, there's no .seh_pushreg for the flags # 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 subq \$0x128,%rsp .seh_stackalloc 0x128 stmxcsr 0x124(%rsp) fnstcw 0x120(%rsp) 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 _cygtls.saved_errno(%r12),%r15d # temporarily save saved_errno movq \$_cygtls.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,_cygtls.stacklock(%r12) # see if we can grab it movl %r11d,_cygtls.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 _cygtls.errno_addr(%r12),%r11 movl %r15d,(%r11) 3: movq \$-8,%r11 # now decrement aux stack xaddq %r11,_cygtls.stackptr(%r12) # and get pointer xorq %r10,%r10 xchgq %r10,-8(%r11) # get return address from signal stack xorl %r11d,%r11d movl %r11d,_cygtls.incyg(%r12) movl %r11d,_cygtls.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 fninit fldcw 0x120(%rsp) ldmxcsr 0x124(%rsp) addq \$0x128,%rsp 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 subq \$8, %rsp popf popq %rbp xchgq %r10,(%rsp) ret .seh_endproc _sigdelayed_end: .global _sigdelayed_end # _cygtls::pop .global _ZN7_cygtls3popEv .seh_proc _ZN7_cygtls3popEv _ZN7_cygtls3popEv: .seh_endprologue movq \$-8,%r11 xaddq %r11,_cygtls.stackptr_p(%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,_cygtls.stacklock_p(%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 _cygtls.stacklock_p(%rcx) ret .seh_endproc # _cygtls::locked .global _ZN7_cygtls6lockedEv .seh_proc _ZN7_cygtls6lockedEv _ZN7_cygtls6lockedEv: .seh_endprologue movl _cygtls.stacklock_p(%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,_cygtls.stacklock(%r12) movl %r10d,_cygtls.spinning(%r12) # flag if we are waiting for lock testl %r10d,%r10d jz 2f pause jmp 1b 2: incl _cygtls.incyg(%r12) cmpl \$0,_cygtls.sig(%r12) jz 3f decl _cygtls.stacklock(%r12) # unlock movq \$_cygtls.start_offset,%rcx # point to beginning addq %r12,%rcx # of tls block call _ZN7_cygtls19call_signal_handlerEv jmp 1b 3: decl _cygtls.incyg(%r12) addq \$0x20,%rsp movq %r12,%r11 # return tls addr in r11 popq %r12 ret .seh_endproc EOF } } return $res; } sub longjmp { if ($is_x86_64) { return <