bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC PATCH] test-c-stack2.sh: skip if the platform sent SIGILL on an


From: Ivan Zakharyaschev
Subject: Re: [RFC PATCH] test-c-stack2.sh: skip if the platform sent SIGILL on an invalid address.
Date: Sat, 29 Dec 2018 23:13:00 +0300 (MSK)
User-agent: Alpine 2.20 (LFD 67 2015-01-07)

Here is a follow-up to the story, for those curious what happens in a 
similar IA64 architecture. And this should be it.

As for the problem on E2K itself, we should discuss it with MCST and/or 
investigate whether the missing information about the faults can be 
recovered to better satisfy POSIX.

On Sat, 29 Dec 2018, Ivan Zakharyaschev wrote:

> > > As for the SIGILL peculiarity, it has a reason in the Elbrus 
> > > architecture. 

> I've studied the assembler code and found the other true 
> reason in this specific case: these are faults "hidden" in an explicitly 
> "speculative" computation which utltimately result in SIGILL. (The E2K ISA 
> is reminiscent of IA64; this can help get the idea.) The specific kind of 
> the fault is "forgotten", unfortunately.

> Besides, in many aspects including the newly mentioned by me explicitly 
> speculative instructions, E2K reminds IA64.
> 
> And it'd be interesting to have a look how they treat faults coming from 
> speculative computations in Linux/ia64 to get an idea whether it can be 
> done in a manner with better conformance to POSIX.

> * * *
> 
> BTW, saving and forgetting the type of the original fault doesn't seem

I meant "not forgetting".

> to be something expensive to implement (after some thought): when a
> register is marked as invalid, it shouldn't matter anymore what value
> it holds. So, the same register can be used to save the information
> about the type of the fault.

As Dmitry Levin pointed out, probably not, because there can be too much 
information (the fault, and the associated addres) for a single register.

> * * *
> 
> I wanted to see how Linux/ia64 handles these complications arising
> from speculative computations possibly causing a fault; and powered on
> such a machine, and had a look at the above examples with SIGILL on
> E2K: the third one, and the fifth one (speculative division by zero).
> 
> The third example from above:
> 
> address@hidden:~/test-speculative-SIGSEGV$ cc -Wall -O3 -xc - -S -o c.s && 
> cat c.s
> int main(int argc, char ** argv) {
>   if (0 < argc)
>     ++*(char*)0xbad;
>   return 0xbeef;
> }
>       .file   ""
>       .pred.safe_across_calls p1-p5,p16-p63
>       .section        .text.startup,"ax",@progbits
>       .align 16
>       .align 64
>       .global main#
>       .type   main#, @function
>       .proc main#
> main:
>       .prologue
>       .body
>       .mmi
>       cmp4.ge p6, p7 = 0, r32
>       addl r14 = 2989, r0
>       addl r8 = 48879, r0
>       ;;
>       .mmi
>       (p7) ld1 r15 = [r14]
>       ;;
>       (p7) adds r15 = 1, r15
>       nop 0
>       ;;
>       .mib
>       (p7) st1 [r14] = r15
>       nop 0
>       br.ret.sptk.many b0
>       .endp main#
>       .ident  "GCC: (Debian 4.6.3-14) 4.6.3"
>       .section        .note.GNU-stack,"",@progbits
> address@hidden:~/test-speculative-SIGSEGV$ cc -Wall -O3 c.s && ./a.out; echo 
> $?
> Segmentation fault
> 139

> Notes on the assembler: the possible groupings into VLIWs are
> separated by double semicolons (";;"). Predicative execution of
> instructions is marked by a prefix with the corresponding predicate
> register in parentheses, like "(p7)" in the code above:
> 
>       .mmi
>       (p7) ld1 r15 = [r14]
>       ;;
>       (p7) adds r15 = 1, r15
>       nop 0
>       ;;
>       .mib
>       (p7) st1 [r14] = r15
> 
> These are the "load", "add", and "store" instructions corresponding to: 
> ++*(char*)0xbad
> 
> All this shows that gcc-4.6 on IA-64 doesn't generate speculative
> computations for the same examples that had speculative computations
> on E2K. Unfortunately, this means that we couldn't compare the
> interesting bits of the behavior between Linux/e2k and Linux/ia64
> quickly. Perhaps, editing the IA64 assembler code can give a desired
> example.

Cool! Linux/ia64 also produces SIGILL in the same situation; it seems
to have no magic. (But there is a second part of the story!)

address@hidden:~/test-speculative-SIGSEGV$ diff c.s c_s.s
18c18
<       (p7) ld1 r15 = [r14]
---
>       (p7) ld1.s r15 = [r14]
address@hidden:~/test-speculative-SIGSEGV$ cc c_s.s && ./a.out; echo $?
Illegal instruction
132

"ld1.s" is the "load 1 byte" instruction with the "speculative" flag.

If we do not use the "invalid" register in a "store" instruction, then
there is no fault:

address@hidden:~/test-speculative-SIGSEGV$ diff c_s.s c_nost.s
24,25d23
<       (p7) st1 [r14] = r15
<       nop 0
address@hidden:~/test-speculative-SIGSEGV$ cc c_nost.s && ./a.out; echo $?
239


And the second part:

The problem has a solution on IA64. The compiler would know how to
replay the faulty speculative computation, so it would be able
generate code to do this non-speculatively and trigger the real fault.
And there is an instruction that checks whether a register is
"valid"[1] and helps to jump to the recovery code[2]: "chk.s".

I've implemented this approach manually in c_chk.s like this (but I
have not seen what a compiler would do actually; IA64 has other
flavors of speculative instructions, like "ld.a" etc., so there are
rich possiblities):

        .file   ""
        .pred.safe_across_calls p1-p5,p16-p63
        .section        .text.startup,"ax",@progbits
        .align 16
        .align 64
        .global main#
        .type   main#, @function
        .proc main#
main:
        .prologue
        .body
        .mmi
        addl r14 = 2989, r0
        addl r8 = 48879, r0
        ;;
        .mmi
        ld1.s r15 = [r14]
        ;;
        .mmi
        cmp4.ge p6, p7 = 0, r32
        ;;
        (p7) adds r15 = 1, r15
        nop 0
        ;;
        (p7) chk.s r15, .recovery
        ;;
.back:
        .mib
        (p7) st1 [r14] = r15
        nop 0
        br.ret.sptk.many b0
.recovery:
        ld1 r15 = [r14]
        //adds r15 = 1, r15
        br.cond.sptk .back
        .endp main#
        .ident  "GCC: (Debian 4.6.3-14) 4.6.3"
        .section        .note.GNU-stack,"",@progbits

address@hidden:~/test-speculative-SIGSEGV$ cc c_chk.s && ./a.out; echo $?
Segmentation fault
139

It produced a normal behavior, better satisfying POSIX.

[1]: https://blogs.msdn.microsoft.com/oldnewthing/20040119-00/?p=41003
[2]: 
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/ia64/strchr.S;h=3a29e80b52c350a76e880cbb8daa66c91fa98964;hb=HEAD#l87

[1] seems to be outdated because it shows a wrong variant of "chk.s",
but has a story about the registers being 65-bit having an additional
bit for their "validity".

[2] is a manually written example of this approach which I googled up
quickly searching for "chk.s" "ia64".

-- 
Best regards,
Ivan




reply via email to

[Prev in Thread] Current Thread [Next in Thread]