Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 May 2017 13:34:41 +0200
From:      Roman Divacky <rdivacky@freebsd.org>
To:        freebsd-toolchain@freebsd.org
Cc:        freebsd-ppc@freebsd.org, markmi@dsl-only.net
Subject:   PowerPC64 C++ exceptions with clang/llvm
Message-ID:  <20170524113441.GA58092@vlakno.cz>

next in thread | raw e-mail | index | archive | help
Hi,

Currently C++ exceptions don't work on PowerPC64 when compiled with clang. I
looked at why and discovered the following.

With the default gcc unwinder and libstdc++ this simple test program:

#include <iostream>

	int main()
	{
	  try {
	    std::cout << "Before\n";
	    throw std::exception();
	    std::cout << "After\n";
	  } catch (...) {
	    std::cout << "Exception\n";
	  }
	}

segfaults right after printing "Before\n". This is because the .eh_frame is corrupted and
the personality relocation is wrong:

<    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 
	bytes of initial instructions	3
	cie length			28
	initial instructions
	 0 DW_CFA_def_cfa r1 0

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.

I verified this theory by hacking the gcc unwinder and libsupc++ &= 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).

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.

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.

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.

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


Thank you, Roman



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20170524113441.GA58092>