Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 26 May 2017 04:00:32 -0700
From:      Mark Millard <markmi@dsl-only.net>
To:        FreeBSD Toolchain <freebsd-toolchain@freebsd.org>, FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>
Subject:   Re: PowerPC64 C++ exceptions with clang/llvm
Message-ID:  <E4A0E8D1-92A4-495B-88E1-C9244DFD272D@dsl-only.net>
In-Reply-To: <74D091B2-71CD-42DE-8C1E-8E0BDED1EAFD@dsl-only.net>
References:  <20170524113441.GA58092@vlakno.cz> <74D091B2-71CD-42DE-8C1E-8E0BDED1EAFD@dsl-only.net>

next in thread | previous in thread | raw e-mail | index | archive | help
[Turns out Roman's working case was based on gcc 4.2.1
based system libraries, not ones built by clang.]

On 2017-May-24, at 9:03 PM, Mark Millard <markmi at dsl-only.net> wrote:

> [So far I've been unable to replicate dwarfump reporting
> anything near "0x94 00 00 00 01 00 01 02 ed 14 1b". The
> compiled code still gets SIGSEGV: it is only the low
> level detail that I'm noting as different. Roman has
> more information from me than I show here.]
>=20
> On 2017-May-24, at 4:34 AM, Roman Divacky <rdivacky@freebsd.org> =
wrote:
>=20
>> Hi,
>>=20
>> Currently C++ exceptions don't work on PowerPC64 when compiled with =
clang. I
>> looked at why and discovered the following.
>>=20
>> With the default gcc unwinder and libstdc++ this simple test program:
>>=20
>> #include <iostream>
>>=20
>> 	int main()
>> 	{
>> 	  try {
>> 	    std::cout << "Before\n";
>> 	    throw std::exception();
>> 	    std::cout << "After\n";
>> 	  } catch (...) {
>> 	    std::cout << "Exception\n";
>> 	  }
>> 	}
>>=20
>> segfaults right after printing "Before\n". This is because the =
.eh_frame is corrupted and
>> the personality relocation is wrong:
>>=20
>> <    1>	version				1
>> 	cie section offset		56 0x00000038
>> 	augmentation			zPLR
>> 	code_alignment_factor		4
>> 	data_alignment_factor		-8
>> 	return_address_register		65
>> 	eh aug data len 0xb bytes 0x94 00 00 00 01 00 01 02 ed 14 1b=20
>=20
> So far I'm unable to replicate producing anything like
> the "large one" as I'll call it.
>=20
> I get things like:
>=20
> # clang++ -std=3Dc++11 exception_test_dots.cpp
> # dwarfdump -v -v -F a.out | more
>=20
> .eh_frame
> . . .
> cie:
> <    0> version                         1
> . . .
>        eh aug data len 0xb bytes 0x94 00 00 00 00 00 01 03 45 14 1b=20
> . . .
>=20
> (No cia<1> at all.)
>=20
> and like:
>=20
> # clang++ -B /usr/local/bin/ -std=3Dc++11 exception_test_dots.cpp
> # dwarfdump -v -v -F a.out | more
>=20
> .eh_frame
> . . .
> cie:
> <    0> version                         1
> . . .
> <    1> version                         1
> . . .
>        eh aug data len 0xb bytes 0x94 00 00 00 00 00 01 f1 1d 14 1b=20
> . . .
>=20
> My context is head -r317820 on a system built with
> the system clang without building gcc 4.2.1 materials.
>=20
> # uname -paKU
> FreeBSD FBSDG5L 12.0-CURRENT FreeBSD 12.0-CURRENT  r317820M  powerpc =
powerpc64 1200030 1200030
>=20
> # ld --version
> GNU ld 2.17.50 [FreeBSD] 2007-07-03
> Copyright 2007 Free Software Foundation, Inc.
> This program is free software; you may redistribute it under the terms =
of
> the GNU General Public License.  This program has absolutely no =
warranty.
>=20
> # /usr/local/bin/ld --version
> GNU ld (GNU Binutils) 2.27
> Copyright (C) 2016 Free Software Foundation, Inc.
> This program is free software; you may redistribute it under the terms =
of
> the GNU General Public License version 3 or (at your option) a later =
version.
> This program has absolutely no warranty.
>=20
> (I have avoided 2.28 so far because of the
> "return code" consequences on the likes of
> aarch64.)
>=20
> I've tried variations like omitting -std=3Dc++11.
> So far I've not found a way to get near:
>=20
> "0x94 00 00 00 01 00 01 02 ed 14 1b"
>=20
> but all the experiments get SIGSEGV when
> I run the produced program.
>=20
> (I do not have a gcc 4.2.1 build around and so
> do not have libstdc++ on powerpc64.)

It is still true that I've not replicated the
"large one" problems (as I called it). But
my environment is not a mix of gcc 4.2.1
and clang based: just clang based, including
libc++ and the like.

So things are very different from Roman's
context.

>> 	bytes of initial instructions	3
>> 	cie length			28
>> 	initial instructions
>> 	 0 DW_CFA_def_cfa r1 0
>>=20
>> the personality relocation is "00 00 00 01 00 01 02 ed" encoded as pc =
relative. The program segfaults
>> because this address is wrong. The 33rd bit is incorrect, the real =
address should be "00 00 00 00 00 01 02 ed".
>> The same problem applies for LDSA encoding. Both personality and LDSA =
relocations are produced by CFI instructions
>> in the assembler source code.
>>=20
>> I verified this theory by hacking the gcc unwinder and libsupc++ &=3D =
the address with 0xffffffff; and that made
>> the application work. (the full patch can be found at =
http://www.vlakno.cz/~rdivacky/ppc64.exceptions.hack.patch).

Roman did not test a libstdc++ built with clang
here. He was using a library to support handling
thrown C++ exceptions that was built by gcc
4.2.1 . Instead the only clang code tested was
in his a.out (or whatever he named the program
generated).

My past testing indicates that whatever library is
supposed to support thrown C++ exceptions is broken
when built by clang. (I've a couple of llvm
submittals about messed up dwarf information and
the like.)

In essence the consequences of the builtin's that
are involved in creating the supporting code in
the library is wrong/incomplete in clang's code
and/or dwarf generation as I understand. For
example:

__builtin_unwind_init()
__builtin_eh_return_data_regno (0)
__builtin_eh_return
__builtin_dwarf_cfa()

were involved back when I did the clang 3.8
investigation (that mostly seems to still
apply in the C++ exception handling area).

I'm not surprised that clang generated
code can use the library code that gcc
4.2.1 generated, at least for the small
examples involved (and probably far more).

>> I checked why this relocation is wrong and it turns out it's our old =
in-tree ld that (wrongly) produces this.
>> Our old gcc does not use CFI to produce these and hardcodes the CIE =
manually and produces correct address. And for
>> some reason ld is fine with that.
>>=20
>> When I compile and assemble the above source code using clang++ and =
only use newer ld linker from ports the resulting
>> binary is correct and works as expected.
>>=20
>> So this is a bug in our in-tree ld linker. I don't know why ld has =
this bug but given Mark Millard's report of ld
>> being broken for other stuff (kernel iirc) I am not going to bother =
trying to fix it. I suspect it might be related
>> to comdats but I didn't really investigate.

As my libc++ and the like was built with clang
for my tests, the system ld does not work for
buildworld for such a context, nor does lld.
So I used

devel/powerpc64-binutils

for buildworld and buildkernel.

Given that clang built it all instead
of gcc 4.2.1, what the system ld does
for the little test program in my
context would be expected to be likely
to not match Roman's results.

But my context gives more information
about the status of things for attempting
to avoid gcc 4.2.1, since that is what
I was doing (gcc 4.2.1 and related
material not built or present) .


>> I didn't try the situation with the LLVM unwinder and libcxxrt, but I =
hope it might be the same.

Last I tried the llvm unwinder could not be be built
by clang. I submitted llvm bugzilla material for it
at the time.

lld did not work last I tried either. (In fact Roman
supplied one patch that let me get far enough to
report some on what else is a problem for lld.)

=3D=3D=3D
Mark Millard
markmi at dsl-only.net




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E4A0E8D1-92A4-495B-88E1-C9244DFD272D>