From owner-freebsd-toolchain@freebsd.org Thu Jan 12 19:24:54 2017 Return-Path: Delivered-To: freebsd-toolchain@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 1BA8CCACE0E for ; Thu, 12 Jan 2017 19:24:54 +0000 (UTC) (envelope-from rdivacky@vlakno.cz) Received: from vlakno.cz (mail.vlakno.cz [91.217.96.224]) by mx1.freebsd.org (Postfix) with ESMTP id BB742143B; Thu, 12 Jan 2017 19:24:53 +0000 (UTC) (envelope-from rdivacky@vlakno.cz) Received: by vlakno.cz (Postfix, from userid 1002) id 4550012CACB; Thu, 12 Jan 2017 20:22:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=vlakno.cz; s=mail; t=1484248943; bh=aa0i8114AsABvu10G5jY1mgsisTe4gMEvJvOTgRreSw=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=kr8ESIkj3eQsRtvfrlgx2d/RLldvvkW8ZeQPiH1pkYSuFm3oF/SYJhvJNCNkNacot 2DS6k7rWqo0AoBfp63Wm0uZxIzRE9GT/UyfO+0bIgQhjdJkTxLNlbt9vDDMbUiDHcl xG/Fz6L9Xd6IKu/AcKEVcx/gePHVAAGj3LFRg5UY= Date: Thu, 12 Jan 2017 20:22:23 +0100 From: Roman Divacky To: Mark Millard Cc: Ed Maste , FreeBSD Toolchain Subject: Re: /usr/bin/ld.lld on powerpc64: produces a.out for which: ld-elf.so.1: assert failed: /usr/src/libexec/rtld-elf/powerpc64/reloc.c:374 Message-ID: <20170112192223.GA49469@vlakno.cz> References: <7139F615-8F18-4EDC-9051-5FFEC0C4057F@dsl-only.net> <20170111194844.GA16135@vlakno.cz> <8242A7B9-7ED3-4861-8209-F3728113D188@dsl-only.net> <20170111210658.GA20265@vlakno.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.7.2 (2016-11-26) X-BeenThere: freebsd-toolchain@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Maintenance of FreeBSD's integrated toolchain List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 12 Jan 2017 19:24:54 -0000 Can you check if the TOC is correct? LLD assumes this: static uint64_t PPC64TocOffset = 0x8000; uint64_t getPPC64TocBase() { // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The // TOC starts where the first of these sections starts. We always create a // .got when we see a relocation that uses it, so for us the start is always // the .got. uint64_t TocVA = In::Got->getVA(); // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. Note that the glibc startup // code (crt1.o) assumes that you can get from the TOC base to the // start of the .toc section with only a single (signed) 16-bit relocation. return TocVA + PPC64TocOffset; } Perhaps thats not true on FreeBSD? Especially the hardcoded constant seems suspicious. When it comes to the actual PLT entry, there's this comment in the code: // FIXME: What we should do, in theory, is get the offset of the function // descriptor in the .opd section, and use that as the offset from %r2 (the // TOC-base pointer). Instead, we have the GOT-entry offset, and that will // be a pointer to the function descriptor in the .opd section. Using // this scheme is simpler, but requires an extra indirection per PLT dispatch. So I think that while it's different it might not be wrong. What might be wrong is the TOC entry (either it's content or it's position). I suspect there might be some Linux vs FreeBSD difference that prevents this from working. Roman On Thu, Jan 12, 2017 at 12:37:53AM -0800, Mark Millard wrote: > On 2017-Jan-11, at 1:23 PM, Ed Maste wrote: > > > On 11 January 2017 at 21:06, Roman Divacky wrote: > >> Looks like a progress :) Three questions... > >> > >> Is the readelf -a reasonable now? > > > > FYI, I just committed an ELF Tool Chain fix (r311941) so readelf > > should display the relocation types properly now. > > Thanks. I updated to -r311950 to pick this up. > > >> If you compile with -g, does the > >> backtrace make a bit more sense? And finally, can you try to "nexti/stepi" in gdb from > >> _start to see where things go wrong? Possibly doing it both for ld linked a.out > >> and lld linked a.out and compare where things differ. > > I had compiled with -g. It never gets to main. . . > > # /usr/local/bin/gdb a.out > . . . > Reading symbols from a.out...done. > (gdb) start > Temporary breakpoint 1 at 0x1001045c: file main.c, line 3. > Starting program: /root/c_tests/a.out > > Program received signal SIGSEGV, Segmentation fault. > 0x000000001001056c in ?? () > > Note that the temporary breakpoint is never hit. > > (gdb) bt > #0 0x000000001001056c in ?? () > #1 0x00000000100100d8 in ?? () > #2 0x00000000500279b0 in ._rtld_start () at /usr/src/libexec/rtld-elf/powerpc64/rtld_start.S:104 > Backtrace stopped: frame did not save the PC > > (gdb) up 2 > #2 0x00000000500279b0 in ._rtld_start () at /usr/src/libexec/rtld-elf/powerpc64/rtld_start.S:104 > 104 blrl /* _start(argc, argv, envp, obj, cleanup, ps_strings) */ > (gdb) disass > Dump of assembler code for function ._rtld_start: > 0x0000000050027930 <+0>: stdu r1,-144(r1) > 0x0000000050027934 <+4>: std r3,96(r1) > 0x0000000050027938 <+8>: std r4,104(r1) > 0x000000005002793c <+12>: std r5,112(r1) > 0x0000000050027940 <+16>: std r8,136(r1) > 0x0000000050027944 <+20>: bl 0x50027950 <._rtld_start+32> > 0x0000000050027948 <+24>: .long 0x0 > 0x000000005002794c <+28>: .long 0x30e40 > 0x0000000050027950 <+32>: mflr r3 > 0x0000000050027954 <+36>: ld r4,0(r3) > 0x0000000050027958 <+40>: add r3,r4,r3 > 0x000000005002795c <+44>: ld r4,-32768(r2) > 0x0000000050027960 <+48>: subf r4,r4,r2 > 0x0000000050027964 <+52>: bl 0x50027c64 > 0x0000000050027968 <+56>: nop > 0x000000005002796c <+60>: ld r4,104(r1) > 0x0000000050027970 <+64>: addi r3,r4,-8 > 0x0000000050027974 <+68>: addi r4,r1,128 > 0x0000000050027978 <+72>: addi r5,r1,120 > 0x000000005002797c <+76>: bl 0x50028608 <_rtld> > 0x0000000050027980 <+80>: nop > 0x0000000050027984 <+84>: ld r2,8(r3) > 0x0000000050027988 <+88>: ld r11,16(r3) > 0x000000005002798c <+92>: ld r3,0(r3) > 0x0000000050027990 <+96>: mtlr r3 > 0x0000000050027994 <+100>: ld r3,96(r1) > 0x0000000050027998 <+104>: ld r4,104(r1) > 0x000000005002799c <+108>: ld r5,112(r1) > 0x00000000500279a0 <+112>: ld r6,120(r1) > 0x00000000500279a4 <+116>: ld r7,128(r1) > 0x00000000500279a8 <+120>: ld r8,136(r1) > 0x00000000500279ac <+124>: blrl > => 0x00000000500279b0 <+128>: li r0,1 > 0x00000000500279b4 <+132>: sc > 0x00000000500279b8 <+136>: nop > 0x00000000500279bc <+140>: nop > End of assembler dump. > > So setting a breakpoint at 0x00000000500279ac and > trying again: > > (gdb) run > Starting program: /root/c_tests/a.out > > Breakpoint 3, ._rtld_start () at /usr/src/libexec/rtld-elf/powerpc64/rtld_start.S:104 > 104 blrl /* _start(argc, argv, envp, obj, cleanup, ps_strings) */ > (gdb) info registers > r0 0x50027980 1342339456 > r1 0xffffffffffffdaf0 18446744073709542128 > r2 0x10028138 268599608 > r3 0x1 1 > r4 0xffffffffffffdbb8 18446744073709542328 > r5 0xffffffffffffdbc8 18446744073709542344 > r6 0x5004c000 1342488576 > r7 0x50058b30 1342540592 > r8 0x0 0 > r9 0x0 0 > r10 0x0 0 > r11 0x0 0 > r12 0x20000000 536870912 > r13 0x50057010 1342533648 > r14 0x0 0 > r15 0x0 0 > r16 0x0 0 > r17 0x0 0 > r18 0x0 0 > r19 0x0 0 > r20 0x0 0 > r21 0x0 0 > r22 0x0 0 > r23 0x0 0 > r24 0x0 0 > r25 0x0 0 > r26 0x0 0 > r27 0x0 0 > r28 0x0 0 > r29 0x0 0 > r30 0x0 0 > r31 0x0 0 > pc 0x500279ac 0x500279ac <._rtld_start+124> > msr > cr 0x22000c00 570428416 > lr 0x10010000 0x10010000 > ctr 0x50043a80 1342454400 > xer 0x20000000 536870912 > (gdb) stepi > 0x0000000010010000 in ?? () > > and that is effectively at ._start . > > NOTE: There is no ._start name in the disassembly > listed by objdump. > > By contrast for -fuse-ld=bfd building a.out objdump shows: > > 0000000010000438 <._start> mflr r0 > 000000001000043c <._start+0x4> mfcr r12 > 0000000010000440 <._start+0x8> std r31,-8(r1) > 0000000010000444 <._start+0xc> std r0,16(r1) > 0000000010000448 <._start+0x10> stw r12,8(r1) > 000000001000044c <._start+0x14> stdu r1,-176(r1) > . . . > > > In gdb for ld.lld used: > > Reading symbols from a.out...done. > (gdb) br *0x00000000500279ac > Breakpoint 1 at 0x500279ac > (gdb) run > Starting program: /root/c_tests/a.out > > Breakpoint 1, ._rtld_start () at /usr/src/libexec/rtld-elf/powerpc64/rtld_start.S:104 > 104 blrl /* _start(argc, argv, envp, obj, cleanup, ps_strings) */ > (gdb) stepi > 0x0000000010010000 in ?? () > (gdb) > 0x0000000010010004 in ?? () > (gdb) display/i $pc > 1: x/i $pc > => 0x10010004: mfcr r12 > (gdb) stepi > 0x0000000010010008 in ?? () > 1: x/i $pc > => 0x10010008: std r31,-8(r1) > (gdb) > 0x000000001001000c in ?? () > 1: x/i $pc > => 0x1001000c: std r0,16(r1) > > . . . > > (gdb) > 0x00000000100100a0 in ?? () > 1: x/i $pc > => 0x100100a0: beq 0x100100ac > (gdb) > 0x00000000100100ac in ?? () > 1: x/i $pc > => 0x100100ac: cmpldi r8,0 > (gdb) > 0x00000000100100b0 in ?? () > 1: x/i $pc > => 0x100100b0: beq 0x100100c0 > (gdb) > 0x00000000100100c0 in ?? () > 1: x/i $pc > => 0x100100c0: addis r3,r2,0 > (gdb) > 0x00000000100100c4 in ?? () > 1: x/i $pc > => 0x100100c4: ld r3,32552(r3) > (gdb) > 0x00000000100100c8 in ?? () > 1: x/i $pc > => 0x100100c8: cmpldi r3,0 > (gdb) > 0x00000000100100cc in ?? () > 1: x/i $pc > => 0x100100cc: beq 0x100100e0 > (gdb) > 0x00000000100100d0 in ?? () > 1: x/i $pc > => 0x100100d0: mr r3,r7 > (gdb) > 0x00000000100100d4 in ?? () > 1: x/i $pc > => 0x100100d4: bl 0x10010560 > > Note: Below is from plt : > > Disassembly of section .plt: > 0000000010010560 <.plt> std r2,40(r1) > 0000000010010564 <.plt+0x4> addis r11,r2,0 > 0000000010010568 <.plt+0x8> ld r12,32512(r11) > 000000001001056c <.plt+0xc> ld r11,0(r12) <<<<<===== Fails here. > 0000000010010570 <.plt+0x10> mtctr r11 > 0000000010010574 <.plt+0x14> ld r2,8(r12) > 0000000010010578 <.plt+0x18> ld r11,16(r12) > 000000001001057c <.plt+0x1c> bctr > > (By setting breakpoints in the 3 such .plt code blocks: > this is the first .plt code block executed and it fails.) > > The .plt is different from what ld.bfd generates: > no __glink_PLTresolve or its use and the code does > not appear strictly equivalent to me. > > Back to gdb based information: > > (gdb) info registers > r0 0x500279b0 1342339504 > r1 0xffffffffffffda40 18446744073709541952 > r2 0x10028138 268599608 > r3 0x50058b30 1342540592 > r4 0x0 0 > r5 0xffffffffffffdbc8 18446744073709542344 > r6 0x5004c000 1342488576 > r7 0x50058b30 1342540592 > r8 0x0 0 > r9 0x0 0 > r10 0x0 0 > r11 0x0 0 > r12 0x22000c00 570428416 > r13 0x50057010 1342533648 > r14 0x0 0 > r15 0x0 0 > r16 0x0 0 > r17 0x0 0 > r18 0x0 0 > r19 0x0 0 > r20 0x0 0 > r21 0x0 0 > r22 0x0 0 > r23 0x0 0 > r24 0x0 0 > r25 0x10028138 268599608 > r26 0x0 0 > r27 0x0 0 > r28 0x1 1 > r29 0xffffffffffffdbb8 18446744073709542328 > r30 0xffffffffffffdbc8 18446744073709542344 > r31 0xffffffffffffda40 18446744073709541952 > pc 0x10010560 0x10010560 > msr > cr 0x42000c00 1107299328 > lr 0x100100d8 0x100100d8 > ctr 0x50043a80 1342454400 > xer 0x20000000 536870912 > > (gdb) > 0x0000000010010560 in ?? () > 1: x/i $pc > => 0x10010560: std r2,40(r1) > (gdb) > 0x0000000010010564 in ?? () > 1: x/i $pc > => 0x10010564: addis r11,r2,0 > (gdb) > 0x0000000010010568 in ?? () > 1: x/i $pc > => 0x10010568: ld r12,32512(r11) > (gdb) > 0x000000001001056c in ?? () > 1: x/i $pc > => 0x1001056c: ld r11,0(r12) > (gdb) > > Program received signal SIGSEGV, Segmentation fault. > 0x000000001001056c in ?? () > 1: x/i $pc > => 0x1001056c: ld r11,0(r12) > > The source code (from lib/csu/powerpc64/crt1.c ) is: > > void > _start(int argc, char **argv, char **env, > const struct Struct_Obj_Entry *obj __unused, void (*cleanup)(void), > struct ps_strings *ps_strings) > { > > handle_argv(argc, argv, env); > > if (ps_strings != (struct ps_strings *)0) > __ps_strings = ps_strings; > > if (&_DYNAMIC != NULL) > atexit(cleanup); > else > _init_tls(); > > #ifdef GCRT > atexit(_mcleanup); > monstartup(&eprol, &etext); > #endif > > handle_static_init(argc, argv, env); > exit(main(argc, argv, env)); > } > > The 3 plt code blocks are for: > > atexit > _init_tls > exit > > from what I can tell, possibly not in that order. > > Overall: The plt handling seems to be broken. > > > > You can also build rtld with additional debugging by adding -DDEBUG to > > CFLAGS. In libexec/rtld-elf/Makefile there's an example command line > > for building it locally, but I've just added CFLAGS+=-DDEBUG to the > > Makefile in my test tree and built it along with the rest of my full > > cross build. > > # svnlite diff /usr/src/libexec/rtld-elf/Makefile > Index: /usr/src/libexec/rtld-elf/Makefile > =================================================================== > --- /usr/src/libexec/rtld-elf/Makefile (revision 311950) > +++ /usr/src/libexec/rtld-elf/Makefile (working copy) > @@ -17,6 +17,7 @@ > malloc.c xmalloc.c debug.c libmap.c > MAN= rtld.1 > CSTD?= gnu99 > +CFLAGS+=-DDEBUG > CFLAGS+= -Wall -DFREEBSD_ELF -DIN_RTLD -ffreestanding > CFLAGS+= -I${SRCTOP}/lib/csu/common > .if exists(${.CURDIR}/${MACHINE_ARCH}) > > The above did not seem to make much of a difference for the > code involved, likely because crt1.c is from > lib/csu/powerpc64/ instead of from libexec/rtld-elf/ . > > > === > Mark Millard > markmi at dsl-only.net