public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Indu Bhagat <indu.bhagat@oracle.com>
To: Jan Beulich <jbeulich@suse.com>
Cc: binutils@sourceware.org
Subject: Re: [PATCH, V2 09/10] gas: testsuite: add a x86_64 testsuite for SCFI
Date: Thu, 2 Nov 2023 22:45:36 -0700	[thread overview]
Message-ID: <66f17782-5cf3-4aed-b1ec-1f8a7dea202c@oracle.com> (raw)
In-Reply-To: <13294625-0ab1-dfa6-08dd-d5c1ec541ec7@suse.com>

On 11/2/23 05:28, Jan Beulich wrote:
> On 01.11.2023 07:24, Indu Bhagat wrote:
>> On 10/31/23 09:13, Jan Beulich wrote:
>>> On 30.10.2023 17:51, Indu Bhagat wrote:
>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/scfi/x86_64/scfi-add-2.s
>>>> @@ -0,0 +1,48 @@
>>>> +        .section        .rodata
>>>> +	.type	simd_cmp_op, @object
>>>> +	.size	simd_cmp_op, 8
>>>> +simd_cmp_op:
>>>> +	.long	2
>>>> +	.zero	4
>>>> +
>>>> +# Testcase for add instruction.
>>>> +# add reg, reg instruction
>>>> +	.text
>>>> +	.globl	foo
>>>> +	.type	foo, @function
>>>> +foo:
>>>> +	.cfi_startproc
>>>> +	pushq	%rbp
>>>> +	.cfi_def_cfa_offset 16
>>>> +	.cfi_offset 6, -16
>>>> +	movq    %rsp, %rbp
>>>> +	.cfi_def_cfa_register 6
>>>> +	pushq	%r12
>>>> +	.cfi_offset 12, -24
>>>> +	mov	%rsp, %r12
>>>
>>> You copy %rsp to %r12 here, and ...
>>>
>>>> +# Stack manipulation is permitted if the base register for
>>>> +# tracking CFA has been changed to FP.
>>>> +	addq    %rdx, %rsp
>>>> +	addq	%rsp, %rax
>>>> +# Some add instructions may access the stack indirectly.  Such
>>>> +# accesses do not make REG_FP untraceable.
>>>> +	addl    %eax, -84(%rbp)
>>>> +# Other kind of add instructions should not error out in the
>>>> +# x86_64 -> ginsn translator
>>>> +	addq    $simd_cmp_op+8, %rdx
>>>> +	addl    %edx, -32(%rsp)
>>>> +	addl    $1, fb_low_counter(,%rbx,4)
>>>> +	mov	%r12, %rsp
>>>
>>> ... you restore it here, but both without any .cfi_* annotation.
>>> It is therefore unclear whether this is in any way related to ...
>>>
>>
>> There are no .cfi_* annotations for the %rsp updates here because the
>> CFA tracking has already been switched to REG_FP based tracking.  From
>> the perspective of DWARF CFI, this usages of the stack do not need to
>> tracked.  If unwinding happens from any instruction in the above
>> sequence, we already have the correct and complete unwind information.
>>
>>>> +# Popping a callee-saved register.
>>>> +# RSP must be traceable.
>>>> +	pop     %r12
>>>> +	.cfi_restore 12
>>>
>>> ... what the comment says about these.
>>>
>>
>> The comment here means that hand-written programs may use stack for
>> their local usage etc. but must ensure that before or in the epilogue,
>> rsp is restored to the desired value (before register restores via pop
>> instructions).
> 
> And how exactly do you tell that the "mov %r12, %rsp" is a restore, not
> the setting of an arbitrary new %rsp value?
> 

It checks that there must have been a "mov %rsp, %r12" seen earlier. 
The SCFI machinery caches such a save of stack pointer state.

>> This is not a special handling in the SCFI machinery but it is what is
>> needed to ensure correctness of the function.  For asm not adhering to
>> the ABI/calling conventions, SCFI cannot be used.
> 
> But the calling convention doesn't go as far as dictating local frame
> layout in a function, I don't think?
> 

No you are right on that one.

In this example, we only concern ourselves only with the callee-saved 
registers and their save/restores; the components that affect the CFI 
annotations.  The local stack usage is not of interest per se; the 
program is allowed to allocate and use as it pleases.

>>>> +	leave
>>>> +	.cfi_def_cfa_register 7
>>>> +	.cfi_restore 6
>>>
>>> Using numbers here isn't very helpful, I'm afraid.
>>>
>>
>> I am not sure I understand.  The DWARF register numbers and the offset
>> values are required by the semantics of those CFI directives.
> 
> Offsets are (largely) unavoidable to be numerics, yes. But .cfi_*
> directives support register names, and using them is (imo) far better
> than Dwarf register numbers - you may have memorized them by now, but
> others likely won't.
> 

Ah ok. Yeah I can use register numbers.

>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/scfi/x86_64/scfi-asm-marker-3.l
>>>> @@ -0,0 +1,2 @@
>>>> +.*Assembler messages:
>>>> +.*9: Warning: --scfi=all ignores some user-specified CFI directives
>>>
>>> Is repeating this for (about?) every test really necessary / useful?
>>> If multiple passes for every test were to make sense to me, I'd expect
>>> one pass with SCFI and one pass without, where the directives then
>>> take effect. And then the same set of expectations should match.
>>>
>>
>> re: is repeating this useful? Strictly speaking no. _But_, I think as
>> the code evolves, we may add more diagnostics to the SCFI machinery.
>> Explicitly checking for the set of warnings helps us ensure no new
>> warnings show up where they are not expected. In a way, it is a stricter
>> check and ensures no unintented slippage.
> 
> Well, okay, that's fair. You didn't respond to the other part of my
> comment, though.
> 

Sorry I missed that.  Yes, we could do two runs for the meaningful 
tests, one with --scfi and another without. That should be useful.  I 
recall there was only one case (dont recollect which one) where the 
generated FDEs were reversed in order with --scfi, but it was not a 
functional difference.  Other than that test, rest all should match.

>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/scfi/x86_64/scfi-bp-sp-2.s
>>>> @@ -0,0 +1,49 @@
>>>> +# Testcase for switching between sp/fp based CFA.
>>>> +	.text
>>>> +	.globl	foo
>>>> +	.type	foo, @function
>>>> +foo:
>>>> +        .cfi_startproc
>>>> +        pushq   %r14
>>>> +        .cfi_def_cfa_offset 16
>>>> +        .cfi_offset 14, -16
>>>> +        pushq   %r13
>>>> +        .cfi_def_cfa_offset 24
>>>> +        .cfi_offset 13, -24
>>>> +        pushq   %r12
>>>> +        .cfi_def_cfa_offset 32
>>>> +        .cfi_offset 12, -32
>>>> +        pushq   %rbp
>>>> +        .cfi_def_cfa_offset 40
>>>> +        .cfi_offset 6, -40
>>>> +        pushq   %rbx
>>>> +        .cfi_def_cfa_offset 48
>>>> +        .cfi_offset 3, -48
>>>> +        movq    %rdi, %rbx
>>>> +        subq    $32, %rsp
>>>> +        .cfi_def_cfa_offset 80
>>>> +# This mov does not switch CFA tracking to REG_FP, because there has already
>>>> +# been stack usage between here and the push %rbp
>>>> +        movq    %rsp, %rbp
>>>
>>> Yet another constraint?
>>>
>>
>> Not sure I understand. This is not a constraint for SCFI.  A pattern
>> where the user does:
>>       push %rbp
>>       .. more stack usage..
>>       movq %rsp, %rbp
>> is not using frame pointer for stack tracing, but simply as a scratch
>> register.
> 
> Why might it not be? We're talking about hand-written assembly, and
> assembly writers are free to e.g. first push all (necessary) callee-
> saved register and then copy %rsp into %rbp. For a function with many
> stack locals this has the benefit of allowing more of them to be
> accessed via <disp8>(%rbp).
> 

You are right on this one. It should be allowed. The mov %rsp, %rbp 
should switch to REG_FP based CFA in this example. I will fix it.

>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/scfi/x86_64/scfi-cfg-1.d
>>>> @@ -0,0 +1,36 @@
>>>> +#as: --scfi -W
>>>> +#objdump: -Wf
>>>> +#name: Synthesize CFI in presence of control flow 1
>>>> +#...
>>>> +Contents of the .eh_frame section:
>>>> +
>>>> +00000000 0+0014 0+0000 CIE
>>>> +  Version:               1
>>>> +  Augmentation:          "zR"
>>>> +  Code alignment factor: 1
>>>> +  Data alignment factor: -8
>>>> +  Return address column: 16
>>>> +  Augmentation data:     [01][abc]
>>>> +  DW_CFA_def_cfa: r7 \(rsp\) ofs 8
>>>> +  DW_CFA_offset: r16 \(rip\) at cfa-8
>>>> +  DW_CFA_nop
>>>> +  DW_CFA_nop
>>>> +
>>>> +0+0018 0+0024 0000001c FDE cie=00000000 pc=0+0000..0+003a
>>>> +  DW_CFA_advance_loc: 1 to 0+0001
>>>> +  DW_CFA_def_cfa_offset: 16
>>>> +  DW_CFA_offset: r3 \(rbx\) at cfa-16
>>>> +  DW_CFA_advance_loc: 37 to 0+0026
>>>> +  DW_CFA_remember_state
>>>> +  DW_CFA_advance_loc: 1 to 0+0027
>>>> +  DW_CFA_restore: r3 \(rbx\)
>>>> +  DW_CFA_def_cfa_offset: 8
>>>> +  DW_CFA_advance_loc: 1 to 0+0028
>>>> +  DW_CFA_restore_state
>>>> +  DW_CFA_advance_loc: 9 to 0+0031
>>>> +  DW_CFA_restore: r3 \(rbx\)
>>>> +  DW_CFA_def_cfa_offset: 8
>>>> +  DW_CFA_nop
>>>> +#...
>>>> +
>>>> +#pass
>>>
>>> Seeing this recurring pattern (the last three lines): Why not just #pass?
>>>
>>
>> I thought adding #... is clearer as it indicates that the test knowingly
>> skips lines thereafter.
> 
> Well, #pass alone already says exactly this. If you didn't expect further
> output lines, you'd _omit_ #pass.
> 

OK.

>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/scfi/x86_64/scfi-cfg-1.s
>>>> @@ -0,0 +1,47 @@
>>>> +# Testcase with one dominator bb and two exit bbs
>>>> +# Something like for: return ferror (f) || fclose (f) != 0;
>>>> +	.text
>>>> +	.section	.rodata.str1.1,"aMS",@progbits,1
>>>> +.LC0:
>>>> +	.string	"w"
>>>> +.LC1:
>>>> +	.string	"conftest.out"
>>>> +	.section	.text.startup,"ax",@progbits
>>>> +	.p2align 4
>>>> +	.globl	main
>>>> +	.type	main, @function
>>>> +main:
>>>> +.LFB11:
>>>
>>> Coming back to "hand-written assembly": The above looks very much like it
>>> was compiler output (earlier tests did, too, but it's perhaps more
>>> prominent here). That's not necessarily what a human might write, and
>>> hence I wonder about the overall coverage that can be gained that way.
>>>
>>
>> Yes, its inspired by compiler generated output. I ran into this when
>> running some tests. Its still a good basic cfg test for SCFI - a
>> function with two return paths.
> 
> You understand though that I used this only as (sutiable) example. My point
> being that hand-written assembly frequently doesn't resemble compiler-
> genertaed code. Otherwise, i.e. if the resulting code wasn't to be different,
> why would one write assembly code in nthe first place?
> 

True.
Open to suggestions on improving the testsuite.

>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/scfi/x86_64/scfi-diag-1.s
>>>> @@ -0,0 +1,23 @@
>>>> +# Testcase for REG_FP based CFA
>>>> +# and using REG_FP as scratch.
>>>> +	.text
>>>> +	.globl	foo
>>>> +	.type	foo, @function
>>>> +foo:
>>>> +	.cfi_startproc
>>>> +	pushq	%rbp
>>>> +	.cfi_def_cfa_offset 16
>>>> +	.cfi_offset 6, -16
>>>> +	movq    %rsp, %rbp
>>>> +	.cfi_def_cfa_register 6
>>>> +# The following add causes REG_FP to become untraceable
>>>> +	addq	%rax, %rbp
>>>
>>> But this isn't a problem as long as FP isn't further used. Indeed ...
>>>
>>>> +	.cfi_def_cfa_register 7
>>>> +	pop	%rbp
>>>
>>> ... its original value is restored right afterwards. Yet another constraint?
>>>
>>
>> Hmm. I need some clarification on the statement "Yet another constraint".
> 
> By "constraint" I mean assumptions you make on the way assembly code is
> written, for your machinery to be usable. The more such assumptions, the
> smaller the set of code "eligible" to (future) use of your work. Hence
> also why I think all such "constraints" need to be spelled out in a
> single place, such that one can
> - verify that everything meeting these constraints actually also works,
> - check up front whether one's assembly code is actually suitable for
>    enabling --scfi.
> 

OK, Thanks. We are on the same page wrt "Constraints" then. In the above 
example, though, the "constraint" is due to the desire to be able 
unwind/stack trace asynchronously. Which is why it confused me in the 
first place, I think I wouldn't call this a "constraint" here. But this 
is a subjective line.

In the above example, the 'addq    %rax, %rbp' does cause a problem for 
unwinding because the CFA is REG_FP based. And the SCFI machinery needs 
to be able to tell what offset from REG_FP is the CFA. I think its 
correct for the SCFI machinery to complain with a ".*14: Error: SCFI: 
usage of REG_FP as scratch not supported" right away, because the unwind 
information at the next instruction is already affected.

That said, I do agree that the constraints need to be spelled out in a 
single place. I already have done some of it in scfi.c, but there is 
room for improvement, I see.

>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/scfi/x86_64/scfi-fp-diag-2.s
>>>> @@ -0,0 +1,55 @@
>>>> +# Testcase for a diagnostic around assymetrical restore
>>>> +# Testcase inspired by byte_insert_op1 in libiberty
>>>> +# False positive for the diagnostic
>>>> +.type	foo, @function
>>>> +foo:
>>>> +.LFB10:
>>>> +	.cfi_startproc
>>>> +	endbr64
>>>> +	pushq	%rbp
>>>> +	.cfi_def_cfa_offset 16
>>>> +	.cfi_offset 6, -16
>>>> +	movq	%rsp, %rbp
>>>> +	.cfi_def_cfa_register 6
>>>> +	pushq	%r12
>>>> +	pushq	%rbx
>>>> +	subq	$24, %rsp
>>>> +	.cfi_offset 12, -24
>>>> +	.cfi_offset 3, -32
>>>> +	movl	%edi, -20(%rbp)
>>>> +	movq	%rsi, -32(%rbp)
>>>> +	movl	%edx, -24(%rbp)
>>>> +	movq	%rcx, -40(%rbp)
>>>> +# The assembler cannot differentiate that the following
>>>> +# mov to %rbx is not a true restore operation, but simply
>>>> +# %rbx register usage as a scratch reg of some sort.
>>>> +# The assembler merely warns of a possible assymetric restore operation
>>>> +# In this case, its noise for the user unfortunately.
>>>> +	movq	-40(%rbp), %rbx
>>>> +	movq	-40(%rbp), %rax
>>>> +	leaq	3(%rax), %r12
>>>> +	jmp	.L563
>>>> +.L564:
>>>> +	subq	$1, %rbx
>>>> +	subq	$1, %r12
>>>> +	movzbl	(%rbx), %eax
>>>> +	movb	%al, (%r12)
>>>> +.L563:
>>>> +	cmpq	-32(%rbp), %rbx
>>>> +	jne	.L564
>>>
>>> But this is pretty common usage. Imo this (the false positive warning)
>>> cannot remain like this.
>>>
>>
>> The warning of "Warning: SCFI: asymetrical register restore" was added
>> to alert user if they do something like
>>       pushq %rbx
>>       pushq %r12
>>       ...
>>       popq  %rbx
>>       popq  %r12
>> i.e., asymmetric save and restore.  Now the user may do a restore to any
>> register and use what was saved on stack as scratch regiser; the only
>> way to differentiate between a "true reg restore in epilogue" vs "reg
>> restored for scratch purposes" is to know whether its the epilogue.  GAS
>> will not be able to determine that easily.
>>
>> We could remove the warning altogether.  I just thought it provides
>> users with some protection / validation of hand-written asm.
> 
> I'm in favor of such assisting warnings, but they're useful only if there
> are few false positives and few false negatives. Too many warnings makes
> people ignore them all (or shut them off), while too few makes people
> mistrust them being helpful.
> 

Noted. And I do agree. I just so happens that I dont have a solution to 
this problem of false positive warnings yet.

>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/scfi/x86_64/scfi-x86-64.exp
>>>> @@ -0,0 +1,103 @@
>>>> +# Copyright (C) 2022-2023 Free Software Foundation, Inc.
>>>> +
>>>> +# This program is free software; you can redistribute it and/or modify
>>>> +# it under the terms of the GNU General Public License as published by
>>>> +# the Free Software Foundation; either version 3 of the License, or
>>>> +# (at your option) any later version.
>>>> +#
>>>> +# This program is distributed in the hope that it will be useful,
>>>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> +# GNU General Public License for more details.
>>>> +#
>>>> +# You should have received a copy of the GNU General Public License
>>>> +# along with this program; if not, write to the Free Software
>>>> +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
>>>> +
>>>> +if { ![is_elf_format] } then {
>>>> +    return
>>>> +}
>>>> +
>>>> +# common tests
>>>> +if  { ([istarget "x86_64-*-*"]) } then {
>>>> +
>>>> +    global ASFLAGS
>>>> +    set old_ASFLAGS "$ASFLAGS"
>>>> +
>>>> +    run_dump_test "scfi-cfi-label-1"
>>>> +    run_list_test "scfi-cfi-label-1" "--scfi --warn"
>>>> +
>>>> +    run_list_test "scfi-diag-1" "--scfi"
>>>> +    run_list_test "scfi-fp-diag-2" "--scfi"
>>>> +    run_list_test "scfi-diag-2" "--scfi"
>>>> +
>>>> +    run_list_test "scfi-unsupported-1" "--32 --scfi"
>>>
>>> Perhaps a 2nd run with --x32, unless (see above) you choose to support
>>> that ABI as well?
>>>
>>
>> At the moment, the plan was to next work on --scfi=inline and add
>> support for aarch64/aapcs64 ABIs.  No plans to add support for x32
>> unless a need arises.
> 
> But that's precisely my point: As long as you don't support --x32, you
> want to check that its use is properly diagnosed (just like use of
> --32 is).
> 

Ah, apologies I construed this comment differently earlier. Yes, I agree 
we can add another run with --x32.


  reply	other threads:[~2023-11-03  5:45 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-30 16:51 [PATCH, V2 00/10] Synthesize CFI for hand-written asm Indu Bhagat
2023-10-30 16:51 ` [PATCH, V2 01/10] gas: dw2gencfi: minor rejig for cfi_sections_set and all_cfi_sections Indu Bhagat
2023-10-30 16:51 ` [PATCH, V2 02/10] gas: dw2gencfi: use all_cfi_sections instead of cfi_sections Indu Bhagat
2023-10-30 16:51 ` [PATCH, V2 03/10] gas: dw2gencfi: expose a new cfi_set_last_fde API Indu Bhagat
2023-10-30 16:51 ` [PATCH, V2 04/10] gas: dw2gencfi: move some tc_* defines to the header file Indu Bhagat
2023-10-30 16:51 ` [PATCH, V2 05/10] gas: add new command line option --scfi[=all,none] Indu Bhagat
2023-10-30 16:51 ` [PATCH, V2 06/10] gas: scfidw2gen: new functionality to prepapre for SCFI Indu Bhagat
2023-10-31 11:28   ` Jan Beulich
2023-10-31 22:06     ` Indu Bhagat
2023-11-02 10:35       ` Jan Beulich
2023-11-02 16:32         ` Indu Bhagat
2023-10-30 16:51 ` [PATCH, V2 07/10] gas: synthesize CFI for hand-written asm Indu Bhagat
2023-10-31 14:10   ` Jan Beulich
2023-11-02  8:15     ` Indu Bhagat
2023-11-02 11:39       ` Jan Beulich
2023-12-10 10:22         ` Indu Bhagat
2023-12-11  7:59           ` Jan Beulich
2023-12-19  7:07             ` Indu Bhagat
2023-11-02 15:53   ` Jan Beulich
2023-11-04  7:29     ` Indu Bhagat
2023-11-06 11:03       ` Jan Beulich
2023-12-10 10:23         ` Indu Bhagat
2023-12-11  8:02           ` Jan Beulich
2023-10-30 16:51 ` [PATCH, V2 08/10] gas: doc: update documentation for the new listing option Indu Bhagat
2023-10-30 16:51 ` [PATCH, V2 09/10] gas: testsuite: add a x86_64 testsuite for SCFI Indu Bhagat
2023-10-31 16:13   ` Jan Beulich
2023-11-01  6:24     ` Indu Bhagat
2023-11-02 12:28       ` Jan Beulich
2023-11-03  5:45         ` Indu Bhagat [this message]
2023-10-30 16:51 ` [PATCH, V2 10/10] gas/NEWS: announce the new command line option Indu Bhagat

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=66f17782-5cf3-4aed-b1ec-1f8a7dea202c@oracle.com \
    --to=indu.bhagat@oracle.com \
    --cc=binutils@sourceware.org \
    --cc=jbeulich@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).