public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Why does -g force .cfi_* directives?
@ 2021-02-18  5:21 Fangrui Song
  2021-02-19 22:51 ` Jim Wilson
  0 siblings, 1 reply; 9+ messages in thread
From: Fangrui Song @ 2021-02-18  5:21 UTC (permalink / raw)
  To: gcc-help; +Cc: i

g++ -fno-exceptions -fno-asynchronous-unwind-tables -S a.cc => no
.cfi_* directive
g++ -fno-exceptions -fno-asynchronous-unwind-tables -g -S a.cc =>
there are .cfi_* directive

C++ exceptions passing through -fno-exceptions frames have undefined behaviors.
Without .eh_frame, the traditional behavior is std::terminate() as a
result of _Unwind_RaiseException returning _URC_END_OF_STACK.

So -fno-asynchronous-unwind-tables is a good way to detect C++
exceptions passing through -fno-exceptions frames.
-g (imagine a build which always turns on debug information) forcing
.cfi_* defeats such usage.
(I can understand that if .debug_frame is used (rare), -g always forces .cfi_*)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Why does -g force .cfi_* directives?
  2021-02-18  5:21 Why does -g force .cfi_* directives? Fangrui Song
@ 2021-02-19 22:51 ` Jim Wilson
  2021-02-20  0:36   ` Fangrui Song
  0 siblings, 1 reply; 9+ messages in thread
From: Jim Wilson @ 2021-02-19 22:51 UTC (permalink / raw)
  To: Fangrui Song; +Cc: gcc-help

On Wed, Feb 17, 2021 at 9:22 PM Fangrui Song <i@maskray.me> wrote:

> g++ -fno-exceptions -fno-asynchronous-unwind-tables -S a.cc => no
> .cfi_* directive
> g++ -fno-exceptions -fno-asynchronous-unwind-tables -g -S a.cc =>
> there are .cfi_* directive
>

The intent is that -g produces .debug_frame sections, because the compiler
is supposed to, and we can't know in advance whether the debugger will want
them.  EH produces .eh_frame sections.  If we need to produce an eh_frame
section, then we don't bother to produce a debug_frame section because they
are basically the same, except that eh_frame has extra alignment padding to
make it friendlier to non-dwarf2 systems, and gdb can use either section.
The .cfi_* directives are used for both the debug_frame and eh_frame
sections.

When using -g with exceptions off, you should see a
     .cfi_sections .debug_frame
directive which tells the assembler to produce a debug_frame section.  If
no .cfi_sections directive the assembler will produce a eh_frame section by
default.

If a toolchain produces debug info by default, you can turn it off with
-g0, preferably at the end of the command in case there is a -g option
somewhere earlier in the command.

Exact behavior will depend on gcc version and target, since cfi_sections
was added about 10 years ago, and some targets enable debug and/or
exceptions by default, and some targets don't use dwarf2 exceptions.

Jim

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Why does -g force .cfi_* directives?
  2021-02-19 22:51 ` Jim Wilson
@ 2021-02-20  0:36   ` Fangrui Song
  2021-02-20  0:38     ` Fangrui Song
  2021-02-20  3:53     ` Jim Wilson
  0 siblings, 2 replies; 9+ messages in thread
From: Fangrui Song @ 2021-02-20  0:36 UTC (permalink / raw)
  To: Jim Wilson; +Cc: gcc-help

On 2021-02-19, Jim Wilson wrote:
>On Wed, Feb 17, 2021 at 9:22 PM Fangrui Song <i@maskray.me> wrote:
>
>> g++ -fno-exceptions -fno-asynchronous-unwind-tables -S a.cc => no
>> .cfi_* directive
>> g++ -fno-exceptions -fno-asynchronous-unwind-tables -g -S a.cc =>
>> there are .cfi_* directive
>>
>
>The intent is that -g produces .debug_frame sections, because the compiler
>is supposed to, and we can't know in advance whether the debugger will want
>them.  EH produces .eh_frame sections.  If we need to produce an eh_frame
>section, then we don't bother to produce a debug_frame section because they
>are basically the same, except that eh_frame has extra alignment padding to
>make it friendlier to non-dwarf2 systems, and gdb can use either section.
>The .cfi_* directives are used for both the debug_frame and eh_frame
>sections.
>
>When using -g with exceptions off, you should see a
>     .cfi_sections .debug_frame
>directive which tells the assembler to produce a debug_frame section.  If
>no .cfi_sections directive the assembler will produce a eh_frame section by
>default.
>
>If a toolchain produces debug info by default, you can turn it off with
>-g0, preferably at the end of the command in case there is a -g option
>somewhere earlier in the command.
>
>Exact behavior will depend on gcc version and target, since cfi_sections
>was added about 10 years ago, and some targets enable debug and/or
>exceptions by default, and some targets don't use dwarf2 exceptions.

Thanks for the information. I have a follow-up question.

How should we make the following code work with both
-fno-asynchronous-unwind-tables and -fasynchronous-unwind-tables?

   int main() {
     asm(".cfi_undefined %rip");
   }

Currently gcc -fno-asynchronous-unwind-tables -c a.c reports an error:

a.c:2: Error: CFI instruction used without previous .cfi_startproc

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Why does -g force .cfi_* directives?
  2021-02-20  0:36   ` Fangrui Song
@ 2021-02-20  0:38     ` Fangrui Song
  2021-02-20  3:53     ` Jim Wilson
  1 sibling, 0 replies; 9+ messages in thread
From: Fangrui Song @ 2021-02-20  0:38 UTC (permalink / raw)
  To: Jim Wilson; +Cc: gcc-help

On 2021-02-19, Fangrui Song wrote:
>On 2021-02-19, Jim Wilson wrote:
>>On Wed, Feb 17, 2021 at 9:22 PM Fangrui Song <i@maskray.me> wrote:
>>
>>>g++ -fno-exceptions -fno-asynchronous-unwind-tables -S a.cc => no
>>>.cfi_* directive
>>>g++ -fno-exceptions -fno-asynchronous-unwind-tables -g -S a.cc =>
>>>there are .cfi_* directive
>>>
>>
>>The intent is that -g produces .debug_frame sections, because the compiler
>>is supposed to, and we can't know in advance whether the debugger will want
>>them.  EH produces .eh_frame sections.  If we need to produce an eh_frame
>>section, then we don't bother to produce a debug_frame section because they
>>are basically the same, except that eh_frame has extra alignment padding to
>>make it friendlier to non-dwarf2 systems, and gdb can use either section.
>>The .cfi_* directives are used for both the debug_frame and eh_frame
>>sections.
>>
>>When using -g with exceptions off, you should see a
>>    .cfi_sections .debug_frame
>>directive which tells the assembler to produce a debug_frame section.  If
>>no .cfi_sections directive the assembler will produce a eh_frame section by
>>default.
>>
>>If a toolchain produces debug info by default, you can turn it off with
>>-g0, preferably at the end of the command in case there is a -g option
>>somewhere earlier in the command.
>>
>>Exact behavior will depend on gcc version and target, since cfi_sections
>>was added about 10 years ago, and some targets enable debug and/or
>>exceptions by default, and some targets don't use dwarf2 exceptions.
>
>Thanks for the information. I have a follow-up question.
>
>How should we make the following code work with both
>-fno-asynchronous-unwind-tables and -fasynchronous-unwind-tables?
>
>  int main() {
>    asm(".cfi_undefined %rip");
>  }

The example is minimalistic. The idea is that if inline asm does stack
push/pop and wants to manually add .cfi_* directives, the current
error behavior is undesired.

>Currently gcc -fno-asynchronous-unwind-tables -c a.c reports an error:
>
>a.c:2: Error: CFI instruction used without previous .cfi_startproc


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Why does -g force .cfi_* directives?
  2021-02-20  0:36   ` Fangrui Song
  2021-02-20  0:38     ` Fangrui Song
@ 2021-02-20  3:53     ` Jim Wilson
  2021-02-20  4:30       ` -fno-asynchronous-unwind-tables && .cfi_* in inline asm Fangrui Song
  2021-02-20 19:43       ` Why does -g force .cfi_* directives? Segher Boessenkool
  1 sibling, 2 replies; 9+ messages in thread
From: Jim Wilson @ 2021-02-20  3:53 UTC (permalink / raw)
  To: Fangrui Song; +Cc: gcc-help

On Fri, Feb 19, 2021 at 4:36 PM Fangrui Song <i@maskray.me> wrote:

> How should we make the following code work with both
> -fno-asynchronous-unwind-tables and -fasynchronous-unwind-tables?
>
>    int main() {
>      asm(".cfi_undefined %rip");
>    }
>

I don't think that there is a way currently to make this work.

In general, I'd say that if you are doing something non-trivial you should
not be using an extended asm.  You should either use a built-in function or
just write it in assembly language directly.  Extended asms really only
work well for simple stuff.  If you use a built-in function, then the
compiler should emit any CFI directives for that built-in if necessary. If
writing in assembly language then you can hand write CFI directives for the
entire function, or rely on assembler support if the assembler can figure
it out from the code.

But if you really want to do this in an extended asm, then we would need to
extend the asm syntax so that one can put CFI info in the middle of an
asm.  One way to do that might be a special operator for formatting asm
strings that only prints the string if we are emitting unwind info.  We
would have to find a free punctuation character that isn't already used by
any existing port, and then assuming backquote is free we could do
int main() {
     asm("`.cfi_undefined %rip`");
   }
and the backquotes then only print the string if we are emitting unwind
info.  Or alternatively make this a % operator like %`.  Either way, I
think this would look funny, so might not be the best approach.  It would
likely be difficult for people to use.  I seriously doubt many users can
write CFI code and get it right.

Jim

^ permalink raw reply	[flat|nested] 9+ messages in thread

* -fno-asynchronous-unwind-tables && .cfi_* in inline asm
  2021-02-20  3:53     ` Jim Wilson
@ 2021-02-20  4:30       ` Fangrui Song
  2021-02-22 19:08         ` Jim Wilson
  2021-02-20 19:43       ` Why does -g force .cfi_* directives? Segher Boessenkool
  1 sibling, 1 reply; 9+ messages in thread
From: Fangrui Song @ 2021-02-20  4:30 UTC (permalink / raw)
  To: Jim Wilson; +Cc: gcc-help, binutils

On 2021-02-19, Jim Wilson wrote:
>On Fri, Feb 19, 2021 at 4:36 PM Fangrui Song <i@maskray.me> wrote:
>
>> How should we make the following code work with both
>> -fno-asynchronous-unwind-tables and -fasynchronous-unwind-tables?
>>
>>    int main() {
>>      asm(".cfi_undefined %rip");
>>    }
>>
>> The example is minimalistic. The idea is that if inline asm does stack
>> push/pop and wants to manually add .cfi_* directives, the current
>> error behavior is undesired.
>>
>
>I don't think that there is a way currently to make this work.

>In general, I'd say that if you are doing something non-trivial you should
>not be using an extended asm.  You should either use a built-in function or
>just write it in assembly language directly.  Extended asms really only
>work well for simple stuff.  If you use a built-in function, then the
>compiler should emit any CFI directives for that built-in if necessary. If
>writing in assembly language then you can hand write CFI directives for the
>entire function, or rely on assembler support if the assembler can figure
>it out from the code.

>But if you really want to do this in an extended asm, then we would need to
>extend the asm syntax so that one can put CFI info in the middle of an
>asm.  One way to do that might be a special operator for formatting asm
>strings that only prints the string if we are emitting unwind info.  We
>would have to find a free punctuation character that isn't already used by
>any existing port, and then assuming backquote is free we could do
>int main() {
>     asm("`.cfi_undefined %rip`");
>   }
>and the backquotes then only print the string if we are emitting unwind
>info.  Or alternatively make this a % operator like %`.  Either way, I
>think this would look funny, so might not be the best approach.  It would
>likely be difficult for people to use.  I seriously doubt many users can
>write CFI code and get it right.

In GNU as, can we have a .cfi_sections value to ignore subsequent .cfi_* directives?
If such a directive exists, gcc -fno-asynchronous-unwind-tables can emit
that directive, and pass through all the .cfi_* directives, then let GNU as ignore them.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Why does -g force .cfi_* directives?
  2021-02-20  3:53     ` Jim Wilson
  2021-02-20  4:30       ` -fno-asynchronous-unwind-tables && .cfi_* in inline asm Fangrui Song
@ 2021-02-20 19:43       ` Segher Boessenkool
  2021-02-26  7:09         ` Fangrui Song
  1 sibling, 1 reply; 9+ messages in thread
From: Segher Boessenkool @ 2021-02-20 19:43 UTC (permalink / raw)
  To: Jim Wilson; +Cc: Fangrui Song, gcc-help

Hi!

On Fri, Feb 19, 2021 at 07:53:13PM -0800, Jim Wilson wrote:
> On Fri, Feb 19, 2021 at 4:36 PM Fangrui Song <i@maskray.me> wrote:
> > How should we make the following code work with both
> > -fno-asynchronous-unwind-tables and -fasynchronous-unwind-tables?
> >
> >    int main() {
> >      asm(".cfi_undefined %rip");
> >    }
> >
> 
> I don't think that there is a way currently to make this work.
> 
> In general, I'd say that if you are doing something non-trivial you should
> not be using an extended asm.  You should either use a built-in function or
> just write it in assembly language directly.  Extended asms really only
> work well for simple stuff.  If you use a built-in function, then the
> compiler should emit any CFI directives for that built-in if necessary. If
> writing in assembly language then you can hand write CFI directives for the
> entire function, or rely on assembler support if the assembler can figure
> it out from the code.

[ Well, I wouldn't say "non-trivial"...  But "more than a few machine
instructions", or "something that uses assembler pseudo-ops that aren't
set up for this (with push/pop for example), I certainly agree with it
if put that way. ]

An inline asm inserts a piece of text in the middle of the compiler
output.  You aren't even guaranteed it will be in *this* function, it
could be inlined, and could be cloned, etc.  Or deleted.

That can be dealt with by using a noipa attribute.  But then you get the
next problem:

You then know this asm will appear somewhere in the compiler output for
this function.  But where?  In this example there is likely no other
code generated for this function (if you have optimisation enabled!),
but for any useful function, you do not know.

(Btw, this is not an extended asm, this is a basic asm.  If you use at
least one colon it is en extended asm, and then you need to write
"%%rip", i.e., two percent signs).

> But if you really want to do this in an extended asm, then we would need to
> extend the asm syntax so that one can put CFI info in the middle of an
> asm.

But what would the semantics of that be?  You cannot control where in
the compiler output the asm will appear, or even if that is only once!
For example, in this code:

int a, b;
void f(int x)
{
	if (x)
		a++;
	else
		b++;
	asm("beacon");
}

the asm is output twice, since in effect the compiler makes this

int a, b;
void f(int x)
{
	if (x) {
		a++;
		asm("beacon");
		return;
	} else {
		b++;
		asm("beacon");
		return;
	}
}

> One way to do that might be a special operator for formatting asm
> strings that only prints the string if we are emitting unwind info.  We
> would have to find a free punctuation character that isn't already used by
> any existing port, and then assuming backquote is free we could do

There are no free characters this way: some code out there might output
backticks in its inline asm.  Everything not % (or {|} on some targets)
is emitted as-is (well, almost).

> int main() {
>      asm("`.cfi_undefined %rip`");
>    }
> and the backquotes then only print the string if we are emitting unwind
> info.  Or alternatively make this a % operator like %`.

Yes, that can work.  But you still have all the other problems with
abusing asm like this :-/

> Either way, I
> think this would look funny, so might not be the best approach.  It would
> likely be difficult for people to use.  I seriously doubt many users can
> write CFI code and get it right.

It often will depend on choices the compiler made, too, in which case 0
users can get it right!  They can get lucky, and sometimes it will do
what the user wanted.


Segher

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: -fno-asynchronous-unwind-tables && .cfi_* in inline asm
  2021-02-20  4:30       ` -fno-asynchronous-unwind-tables && .cfi_* in inline asm Fangrui Song
@ 2021-02-22 19:08         ` Jim Wilson
  0 siblings, 0 replies; 9+ messages in thread
From: Jim Wilson @ 2021-02-22 19:08 UTC (permalink / raw)
  To: Fangrui Song; +Cc: gcc-help, Binutils

On Fri, Feb 19, 2021 at 8:30 PM Fangrui Song <i@maskray.me> wrote:

> In GNU as, can we have a .cfi_sections value to ignore subsequent .cfi_*
> directives?
> If such a directive exists, gcc -fno-asynchronous-unwind-tables can emit
> that directive, and pass through all the .cfi_* directives, then let GNU
> as ignore them.
>

I think that is a better suggestion than mine.

Jim

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Why does -g force .cfi_* directives?
  2021-02-20 19:43       ` Why does -g force .cfi_* directives? Segher Boessenkool
@ 2021-02-26  7:09         ` Fangrui Song
  0 siblings, 0 replies; 9+ messages in thread
From: Fangrui Song @ 2021-02-26  7:09 UTC (permalink / raw)
  To: Jim Wilson; +Cc: Segher Boessenkool, gcc-help

On 2021-02-20, Segher Boessenkool wrote:
>Hi!
>
>On Fri, Feb 19, 2021 at 07:53:13PM -0800, Jim Wilson wrote:
>> On Fri, Feb 19, 2021 at 4:36 PM Fangrui Song <i@maskray.me> wrote:
>> > How should we make the following code work with both
>> > -fno-asynchronous-unwind-tables and -fasynchronous-unwind-tables?
>> >
>> >    int main() {
>> >      asm(".cfi_undefined %rip");
>> >    }
>> >
>>
>> I don't think that there is a way currently to make this work.
>>
>> In general, I'd say that if you are doing something non-trivial you should
>> not be using an extended asm.  You should either use a built-in function or
>> just write it in assembly language directly.  Extended asms really only
>> work well for simple stuff.  If you use a built-in function, then the
>> compiler should emit any CFI directives for that built-in if necessary. If
>> writing in assembly language then you can hand write CFI directives for the
>> entire function, or rely on assembler support if the assembler can figure
>> it out from the code.
>
>[ Well, I wouldn't say "non-trivial"...  But "more than a few machine
>instructions", or "something that uses assembler pseudo-ops that aren't
>set up for this (with push/pop for example), I certainly agree with it
>if put that way. ]
>
>An inline asm inserts a piece of text in the middle of the compiler
>output.  You aren't even guaranteed it will be in *this* function, it
>could be inlined, and could be cloned, etc.  Or deleted.
>
>That can be dealt with by using a noipa attribute.  But then you get the
>next problem:
>
>You then know this asm will appear somewhere in the compiler output for
>this function.  But where?  In this example there is likely no other
>code generated for this function (if you have optimisation enabled!),
>but for any useful function, you do not know.
>
>(Btw, this is not an extended asm, this is a basic asm.  If you use at
>least one colon it is en extended asm, and then you need to write
>"%%rip", i.e., two percent signs).
>
>> But if you really want to do this in an extended asm, then we would need to
>> extend the asm syntax so that one can put CFI info in the middle of an
>> asm.
>
>But what would the semantics of that be?  You cannot control where in
>the compiler output the asm will appear, or even if that is only once!
>For example, in this code:
>
>int a, b;
>void f(int x)
>{
>	if (x)
>		a++;
>	else
>		b++;
>	asm("beacon");
>}
>
>the asm is output twice, since in effect the compiler makes this
>
>int a, b;
>void f(int x)
>{
>	if (x) {
>		a++;
>		asm("beacon");
>		return;
>	} else {
>		b++;
>		asm("beacon");
>		return;
>	}
>}
>
>> One way to do that might be a special operator for formatting asm
>> strings that only prints the string if we are emitting unwind info.  We
>> would have to find a free punctuation character that isn't already used by
>> any existing port, and then assuming backquote is free we could do
>
>There are no free characters this way: some code out there might output
>backticks in its inline asm.  Everything not % (or {|} on some targets)
>is emitted as-is (well, almost).
>
>> int main() {
>>      asm("`.cfi_undefined %rip`");
>>    }
>> and the backquotes then only print the string if we are emitting unwind
>> info.  Or alternatively make this a % operator like %`.
>
>Yes, that can work.  But you still have all the other problems with
>abusing asm like this :-/
>
>> Either way, I
>> think this would look funny, so might not be the best approach.  It would
>> likely be difficult for people to use.  I seriously doubt many users can
>> write CFI code and get it right.
>
>It often will depend on choices the compiler made, too, in which case 0
>users can get it right!  They can get lucky, and sometimes it will do
>what the user wanted.

For my .cfi_* in inline asm problem, I have filed

https://sourceware.org/bugzilla/show_bug.cgi?id=27472
   gas: Suppress "CFI instruction used without previous .cfi_startproc" if .cfi_sections is empty

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99282
   Emit .cfi_sections without arguments for -fno-asynchronous-unwind-tables


(I noticed that LLVM integrated assembler did not support
.cfi_sections with an empty section list. I just implemented it.
)

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-02-26  7:09 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-18  5:21 Why does -g force .cfi_* directives? Fangrui Song
2021-02-19 22:51 ` Jim Wilson
2021-02-20  0:36   ` Fangrui Song
2021-02-20  0:38     ` Fangrui Song
2021-02-20  3:53     ` Jim Wilson
2021-02-20  4:30       ` -fno-asynchronous-unwind-tables && .cfi_* in inline asm Fangrui Song
2021-02-22 19:08         ` Jim Wilson
2021-02-20 19:43       ` Why does -g force .cfi_* directives? Segher Boessenkool
2021-02-26  7:09         ` Fangrui Song

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).