mstackalign vs rbp order in gcc optimization level epilogue/prologue - O2/O3

2020-09-29 Thread AJ D via Gcc
Hi,



I was looking at the implementation of mstackalign in gcc (O2/O3) and it
looks like we generate code for mstackalign (i.e. generate instructions for
stack alignment) before pushing $rbp to stack/setting $rbp. In the
epilogue, we do the same in reverse order.



some_routine:

   0x00400860 <+0>:lea0x8(%rsp),%r10

   0x00400865 <+5>:and$0xfff0,%rsp

   0x00400869 <+9>:pushq  -0x8(%r10)

   0x0040086d <+13>: push   %rbp

   0x0040086e <+14>:  mov%rsp,%rbp

  :

   0x00400983 <+291>:  pop%rbp

>>   0x00400984 <+292>:  lea-0x8(%r10),%rsp

   0x00400988 <+296>:  retq



In gdb, when I single-step to IP (Instruction Pointer) 0x00400984
(shown above) and try to get my stack trace using ‘gdb - where’, I do not
get my full stack trace, this is what I get:



(gdb) where

#0  0x004009e3 in backtrace() ()

#1  0x00400b18 in fac(int) ()

Backtrace stopped: previous frame inner to this frame (corrupt stack?)

(gdb)



And of course, if I just do one more ‘single stepi’ and stop at the next
instruction retq / IP: 0x00400988, then everything works fine.



(gdb) si

0x004009e7 in backtrace() ()

(gdb) where

#0  0x004009e7 in backtrace() ()

#1  0x00400b18 in fac(int) ()

#2  0x00400b49 in func1(int) ()

#3  0x00400b69 in func2(int) ()

#4  0x0040078a in main ()

(gdb)



It looks like this issue is showing up due to the order in which ‘%rbp’ is
saved/restored w.r.t the ‘stack alignment code’ execution.



In CLANG, %rbp is pushed/set first, then the stack is aligned, here is the
CLANG generated code:



Some_func:

   0x00400850 <+0>:push   %rbp

   0x00400851 <+1>:mov%rsp,%rbp

   :

   0x0040085d <+13>: and$0xfff0,%rsp

   0x00400861 <+17>:  sub$0x8d0,%rsp

   0x00400868 <+24>:  lea0x520(%rsp),%r14

   0x00400870 <+32>:  mov%r14,%rdi

   :

   0x0040093a <+234>:  lea-0x28(%rbp),%rsp

   :

   0x00400947 <+247>:  pop%rbp

   0x00400948 <+248>:  retq



And with the CLANG generated code, ‘gdb – where’ works fine at every
instruction pointer.


Whereas, in GCC, the stack is aligned first, then the %rbp is pushed/set
and that seems to be opening up a few instruction holes where 'gdb - where'
wouldn't work.



Would you folks consider this as a GCC bug? Do you folks see any issue in
the CLANG approach? Is there a way (any switch) in gcc which would reverse
the order of ‘setting %rbp’ vs ‘stack alignment code’ (like CLANG)?


I used -mstackrealign with -O3 and -fomit-frame-pointer for generating my
code.


GCC DWARF Issue - Frame Pointer Dependency

2020-10-12 Thread AJ D via Gcc
Hi,



I have a function for which GCC is generating the following code (just
showing the relevant snippet here).



5a70 :

5a70:   4c 8d 54 24 08  lea0x8(%rsp),%r10

5a75:   48 83 e4 f0 and$0xfff0,%rsp

5a79:   41 ff 72 f8 pushq  -0x8(%r10)

5a7d:   55  push   %rbp

5a7e:   48 89 e5mov%rsp,%rbp

5a81:   41 57   push   %r15

5a83:   41 56   push   %r14

5a85:   41 55   push   %r13

5a87:   41 54   push   %r12

:

5b08:   5b  pop%rbx

5b09:   41 5a   pop%r10

5b0b:   41 5c   pop%r12

5b0d:   41 5d   pop%r13

5b0f:   41 5e   pop%r14

5b11:   41 5f   pop%r15

5b13:   5d  pop%rbp

*=>5b14:   49 8d 62 f8  lea-0x8(%r10),%rsp*

5b18:   c3  retq



I am using a SIGPROF based CPU profiler (Google CPU Profiler) to profile my
code. The SIGPROF handler (of the Google CPU Profiler) tries to unwind the
stack (using libunwind) every time it gets a SIGPROF. And libunwind (used
for unwinding the stack) uses DWARF unwind table (dumped by gcc -O3
-mstackrealign -fomit-frame-pointer).


And I noticed that I get a crash every time my code gets interrupted by
SIGPROF while my program is in the middle of setting / resetting frame
pointer and the frame pointer %rbp happens to point to the parent/previous
frame at that point, for example, in instruction *5b14* (shown above with
=> and red).



*=>5b14:   49 8d 62 f8  lea-0x8(%r10),%rsp*


DWARF dumped by GCC for the snippet shown above is the following:



02f4 0044 02f8 FDE cie=
pc=5a70..5d7c

  DW_CFA_advance_loc: 5 to 5a75

  DW_CFA_def_cfa: r10 (r10) ofs 0

  DW_CFA_advance_loc: 9 to 5a7e

  DW_CFA_expression: r6 (rbp) (DW_OP_breg6 (rbp): 0)

  DW_CFA_advance_loc: 11 to 5a89

  DW_CFA_expression: r15 (r15) (DW_OP_breg6 (rbp): -8)

  DW_CFA_expression: r14 (r14) (DW_OP_breg6 (rbp): -16)

  DW_CFA_expression: r13 (r13) (DW_OP_breg6 (rbp): -24)

  DW_CFA_expression: r12 (r12) (DW_OP_breg6 (rbp): -32)

  DW_CFA_advance_loc: 5 to 5a8e

  DW_CFA_def_cfa_expression (DW_OP_breg6 (rbp): -40; DW_OP_deref)

  DW_CFA_advance_loc: 4 to 5a92

*>>  DW_CFA_expression: r3 (rbx) (DW_OP_breg6 (rbp): -48)*

  DW_CFA_advance_loc1: 121 to 5b0b

  DW_CFA_remember_state

*>>  DW_CFA_def_cfa: r10 (r10) ofs 0*

  DW_CFA_advance_loc: 13 to 5b18

  DW_CFA_def_cfa: r7 (rsp) ofs 8

  DW_CFA_advance_loc: 8 to 5b20

  DW_CFA_restore_state



02f4 0044 02f8 FDE cie=
pc=5a70..5d7c

   LOC   CFA  rbx   rbp   r12   r13   r14   r15   ra

5a70 rsp+8u u u u u u c-8

5a75 r10+0u u u u u u c-8

5a7e r10+0u exp   u u u u c-8

5a89 r10+0u exp   exp   exp   exp   exp   c-8

5a8e exp  u exp   exp   exp   exp   exp   c-8

5a92 exp  exp   exp   exp   exp   exp   exp   c-8

*5b0b r10+0**exp   **exp   exp   exp   exp   exp   c-8*

5b18 rsp+8exp   exp   exp   exp   exp   exp   c-8

5b20 exp  exp   exp   exp   exp   exp   exp   c-8



And if you see here, the DWARF expression for fetching the CFA is correct,
but what about the DWARF expression for fetching the value of %rbx?



*>>  DW_CFA_expression: r3 (rbx) (DW_OP_breg6 (rbp): -48)*



Value of %rbx is (in DWARF) is “%rbp relative” and since %rbp is pointing
to the wrong (parent/previous) frame, we will obviously get garbage for the
value of %rbx.



If you look at the generated DWARF carefully, pretty much everything is
‘%rbp relative’, so values for each of these registers cannot be restored
in this scenario.



  DW_CFA_expression: r15 (r15) (DW_OP_breg6 (rbp): -8)

  DW_CFA_expression: r14 (r14) (DW_OP_breg6 (rbp): -16)

  DW_CFA_expression: r13 (r13) (DW_OP_breg6 (rbp): -24)

  DW_CFA_expression: r12 (r12) (DW_OP_breg6 (rbp): -32)



I was just wondering, instead of making these %rbp-relative, could we have
made this CFA-relative? That would have taken care of this particular
issue, since CFA is correctly maintained/restored in this example.



Another question, is there a known work around for this issue?



Regards

AJ


Comma Operator - Left to Right Associativity

2021-02-04 Thread AJ D via Gcc
Isn't comma operator suppose to honor left-to-right associativity?

When I try it on this test case, it exhibits right-to-left associativity.

#include 



struct CBI;

struct EC;

struct CET;



struct CBI {

CBI& operator,(const CBI& rhs)

{ return *const_cast(&rhs); }

};



struct EC : CBI {

explicit EC(CET* cet) : cet_(cet)

{}



CET* cet_;

};



struct CET {

CBI& operator,(const CBI& rhs) const

{ return *const_cast(&rhs); }



operator EC&() const

{ return *new EC(const_cast(this)); }

};



static const CET&

hello() {

std::cout << "Hello " << std::endl;

return *new CET();

}



static const CET&

world() {

std::cout << "World " << std::endl;

return *new CET();

}



static void

test_comma_operator(CBI&) {



}



int main()

{

test_comma_operator ((

hello(),

world()

));

}



CLANG appears to do it right.


us01odcvde08782> clang++ -g test.cpp

us01odcvde08782> ./a.out

*Hello*

World

us01odcvde08782> g++ -g test.cpp

us01odcvde08782> ./a.out

World

*Hello*

us01odcvde08782>


I was using CentOS6.8 with gcc 6.2. However, trying other versions of GCC
didn't make any difference.


Is this a bug in GCC?


Re: Comma Operator - Left to Right Associativity

2021-02-04 Thread AJ D via Gcc
Nope, -std=c++17 didn’t help either.

On Thu, Feb 4, 2021 at 1:33 PM David Brown  wrote:

>
>
> On 04/02/2021 22:21, Andreas Schwab wrote:
> > On Feb 04 2021, David Brown wrote:
> >
> >> For the built-in comma operator, you get guaranteed order of evaluation
> >> (or more precisely, guaranteed order of visible side-effects).  But for
> >> a user-defined comma operator, you do not - until C++17, which has
> >> guaranteed evaluation ordering in some circumstances.
> >
> > But not the evaluation order of function arguments.  See
> >  Sequenced-before
> > rules, rule 15.
>
> Correct.
>
> >
> >> Try your test again with "-std=c++17" or "-std=g++17" - if the order is
> >> still reversed, it's a gcc bug (AFAICS).
> >
> > I don't think so.
> >
>
> Unless I am missing something, in the OP's program it is a user-defined
> comma operator that is called.  There is only one argument to the
> "test_comma_operator" function, the result of that user-defined comma
> operator.  So rule 15 above does not apply - rule 16 applies.
>
> At least that is /my/ reading of the cppreference page and the OP's
> program.
>
> David
>
>


Re: Comma Operator - Left to Right Associativity

2021-02-04 Thread AJ D via Gcc
Yes, there is only function argument which is the result of the comma
operator.

On Thu, Feb 4, 2021 at 2:46 PM AJ D  wrote:

> Nope, -std=c++17 didn’t help either.
>
> On Thu, Feb 4, 2021 at 1:33 PM David Brown 
> wrote:
>
>>
>>
>> On 04/02/2021 22:21, Andreas Schwab wrote:
>> > On Feb 04 2021, David Brown wrote:
>> >
>> >> For the built-in comma operator, you get guaranteed order of evaluation
>> >> (or more precisely, guaranteed order of visible side-effects).  But for
>> >> a user-defined comma operator, you do not - until C++17, which has
>> >> guaranteed evaluation ordering in some circumstances.
>> >
>> > But not the evaluation order of function arguments.  See
>> > 
>> Sequenced-before
>> > rules, rule 15.
>>
>> Correct.
>>
>> >
>> >> Try your test again with "-std=c++17" or "-std=g++17" - if the order is
>> >> still reversed, it's a gcc bug (AFAICS).
>> >
>> > I don't think so.
>> >
>>
>> Unless I am missing something, in the OP's program it is a user-defined
>> comma operator that is called.  There is only one argument to the
>> "test_comma_operator" function, the result of that user-defined comma
>> operator.  So rule 15 above does not apply - rule 16 applies.
>>
>> At least that is /my/ reading of the cppreference page and the OP's
>> program.
>>
>> David
>>
>>