Port-vax archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

ld assertion failures building NetBSD-VAX with GCC 4.5

Hi all,

I recently booted up my VS4000/90 to play with NetBSD. The CPU seems a
bit faster than my Amiga 3000 with WarpEngine 40MHz 68040) and it has
the benefit that it can do a complete build without failing, while my
Amiga has some intermittent RAM or bus corruption that causes random
GCC build failures every few days (especially frustrating when it
takes 4-5 hours for an incremental build to proceed to the point where
the previous build crashed). The SCSI controller is slower than the
Amiga (it appears to be limited to 6.25MB/s transfers) and the
Ethernet seems a bit slower as well, but the VS4000 is quite solid.

I'd like to upgrade my build to use GCC 4.5.x, since the VAX is the
only platform remaining on GCC 4.1.3. The first step would be to get a
cross-build working, and then I believe gmp, mpfr, and/or mpc still
need to be ported for a native build to work. The generated code seems
to be almost identical, at least when the same CFLAGS are used, but I
had to patch share/mk/bsd.sys.mk to add "-Wno-uninitialized" for VAX
to fix some build failures for uninitialized variable warnings (this
flag was already added for SH3 and m68k):

diff -d -u -r1.223 bsd.sys.mk
--- bsd.sys.mk 27 Jan 2013 02:31:44 -0000 1.223
+++ bsd.sys.mk 6 Mar 2013 19:15:50 -0000
@@ -75,7 +75,8 @@
      && (${MACHINE_ARCH} == "sh3eb" || \
  ${MACHINE_ARCH} == "sh3el" || \
  ${MACHINE_ARCH} == "m68k" || \
- ${MACHINE_ARCH} == "m68000"))
+ ${MACHINE_ARCH} == "m68000" || \
+ ${MACHINE_ARCH} == "vax"))
 # XXX GCC 4.5 for sh3 and m68k (which we compile with -Os) is extra noisy for
 # cases it should be better with
 CFLAGS+= -Wno-uninitialized

My kernel built with GCC 4.5 works fine, but I experienced some
strange failures trying to start in multiuser after installing the
system (the first being that /etc/rc seems to get bad output from
rcorder and fails to run "d/swap2", with other scripts failing). I
created a chroot to try to find the source of the problems and
discovered a highly reproducible SIGILL crash starting /usr/bin/vi.
Tracking down that crash revealed the following bug:

In early startup of nvi, the function cl_keyval() is called via a
pointer which is initialized in cl_func_std() in cl/cl_main.c. I
discovered via gdb that cl_keyval was pointing to data rather than
code, and the GDB disassembly showed this:

415             gp->scr_insertln = cl_insertln;
   0x000161a8 <+194>:   movl 0xfffffff8(fp),r0
   0x000161ac <+198>:   movab *0x860f4 <_GLOBAL_OFFSET_TABLE_+820>,0xacc(r0)

416             gp->scr_keyval = cl_keyval;
   0x000161b5 <+207>:   movl 0xfffffff8(fp),r0
   0x000161b9 <+211>:   movab *0x86170 <__progname>,0xac8(r0)

417             gp->scr_move = cl_move;
   0x000161c2 <+220>:   movl 0xfffffff8(fp),r0
   0x000161c6 <+224>:   movab *0x860f0 <_GLOBAL_OFFSET_TABLE_+816>,0xad4(r0)

instead of:

415             gp->scr_insertln = cl_insertln;
   0x00016402 <+194>:   movl 0xfffffff8(fp),r0
   0x00016406 <+198>:   movab *0x8a8b4 <_GLOBAL_OFFSET_TABLE_+832>,0xacc(r0)

416             gp->scr_keyval = cl_keyval;
   0x0001640f <+207>:   movl 0xfffffff8(fp),r0
   0x00016413 <+211>:   movab *0x8a930 <_GLOBAL_OFFSET_TABLE_+956>,0xac8(r0)

417             gp->scr_move = cl_move;
   0x0001641c <+220>:   movl 0xfffffff8(fp),r0
   0x00016420 <+224>:   movab *0x8a8b0 <_GLOBAL_OFFSET_TABLE_+828>,0xad4(r0)

Then I discovered that the link command had failed for vi and a few
other binaries, with:

BFD (NetBSD Binutils nb1) 2.21.1 assertion fail

Adding some debug lines showed that the linker was trying to reference
cl_keyval in the global offset table at 1 index past the end of the

cl_main.o: h->got.offset=212 sgot->size=212 for `cl_keyval' from .text

The other failures all showed the same pattern. It seems like the size
of the GOT is 1 entry too small, and the failure occurs only when I
link with the GCC 4.5 version of /usr/lib/libgcc.a. So either there's
a bug in binutils for VAX that's only triggered by the new GCC, or
there's something wrong with GCC 4.5's libgcc.

I compared recent NetBSD patches for GCC 4.1 for VAX to see which
hadn't been copied to GCC 4.5. The only one I found was the patch to
ffssi2, which can be applied to GCC 4.5 like this (but doesn't fix the
linker bug):

cvs diff: Diffing .
Index: builtins.md
RCS file: /cvsroot/src/external/gpl3/gcc/dist/gcc/config/vax/builtins.md,v
retrieving revision 1.2
diff -d -u -r1.2 builtins.md
--- builtins.md 10 Nov 2011 17:16:30 -0000 1.2
+++ builtins.md 6 Mar 2013 19:30:34 -0000
@@ -37,7 +37,7 @@
   rtx label = gen_label_rtx ();
-  emit_insn (gen_ffssi2_internal (operands[0], operands[1]));
+  emit_insn (gen_unspec_ffssi2 (operands[0], operands[1]));
   emit_jump_insn (gen_condjump (gen_rtx_NE(VOIDmode, cc0_rtx,
const0_rtx), label));
   emit_insn (gen_negsi2 (operands[0], const1_rtx));
   emit_label (label);
@@ -45,10 +45,16 @@

-(define_insn "ffssi2_internal"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=rQ")
- (ffs:SI (match_operand:SI 1 "general_operand" "nrmT")))
-   (set (cc0) (match_dup 0))]
+;; Set cc0 to match argument 1 since if it is 0, Z will be set just as
+;; if a tst:SI was performed.  If we did a match_dup 0, that wouldn't be
+;; right since 0 will be set to (0+32) [the position (relative to the base)
+;; of a bit one position to the left of the specified field].
+(define_insn "unspec_ffssi2"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
+        (unspec:SI [(match_operand:SI 1 "general_operand" "nrQ")] VUNSPEC_FFS))
+   (set (cc0) (match_dup 1))]
   "ffs $0,$32,%1,%0")

Index: vax.md
RCS file: /cvsroot/src/external/gpl3/gcc/dist/gcc/config/vax/vax.md,v
retrieving revision 1.3
diff -d -u -r1.3 vax.md
--- vax.md 5 Feb 2012 17:38:21 -0000 1.3
+++ vax.md 6 Mar 2013 19:30:34 -0000
@@ -33,6 +33,7 @@
   [(VUNSPEC_BLOCKAGE 0)    ; `blockage' insn to prevent scheduling across an
     ; insn in the code.
    (VUNSPEC_SYNC_ISTREAM 1) ; sequence of insns to sync the I-stream
+   (VUNSPEC_FFS 2)          ; internal FFS for the expand
    (VAX_AP_REGNUM 12)    ; Register 12 contains the argument pointer
    (VAX_FP_REGNUM 13)    ; Register 13 contains the frame pointer
    (VAX_SP_REGNUM 14)    ; Register 14 contains the stack pointer

I tried to investigate how the GOT is created and sized, but can't
figure out what's happening. I did notice in
binutils/dist/bfd/elf32-vax.c that there are some comments about the
first two entries of the GOT being reserved, but another section of
code fills in the first three entries in the global offset table. So
that could be the cause of the off-by-one index, but I don't see the
code where the initial GOT is being allocated...

          /* Get the offset into the .got table of the entry that
             corresponds to this function.  Each .got entry is 4 bytes.
             The first two are reserved.  */
          got_offset = (plt_index + 3) * 4;


  /* Fill in the first three entries in the global offset table.  */
  if (sgot->size > 0)
      if (sdyn == NULL)
        bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
        bfd_put_32 (output_bfd,
                    sdyn->output_section->vma + sdyn->output_offset,
      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);

  elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;

I'll try to track this down further, but I'm hoping this info will be
enough for someone else on the list with more experience in these
areas to see what's going wrong. I'll be happy to test any patches
anyone has (I'm doing cross-builds from a much faster box).

The other question I have, since people have been discussing slow VAX
performance recently on the list, is why these function pointers are
being accessed via the global offset table anyway? The affected
binaries are linking against shared libs but aren't themselves shared,
but I've also seen it mentioned that the VAX ABI defines all code as
PIC, but maybe that was referring to SVR4 or VMS? It seems like the
linker should be able to create a direct reference to these function
pointers. I also discovered that the linker is inserting a whole bunch
of extra calls to reload r0 when I compile with "-g" (as in the above
GDB output), so the non-debug version of the assembly code looks like:

        movl 16(%r7),%r0
        movab cl_addstr,2704(%r0)
        movab cl_waddstr,2708(%r0)
        movab cl_attr,2712(%r0)

which turns into:

   0x0001501a <+294>:   movl 0x10(r7),r0
   0x0001501e <+298>:   movab *0x63184 <_GLOBAL_OFFSET_TABLE_+912>,0xa90(r0)
   0x00015027 <+307>:   movab *0x630f8 <_GLOBAL_OFFSET_TABLE_+772>,0xa94(r0)
   0x00015030 <+316>:   movab *0x630f4 <_GLOBAL_OFFSET_TABLE_+768>,0xa98(r0)

but the "-g" version of vi (compiled with "-O1 -fgcse
-fstrength-reduce -fgcse-after-reload"), which doesn't inline
cl_func_std(), turns into the following instructions:

   0x000160ef <+9>:     movl 0x10(r0),0xfffffff8(fp)
   0x000160f4 <+14>:    movl 0xfffffff8(fp),r0
   0x000160f8 <+18>:    movab *0x86158 <_GLOBAL_OFFSET_TABLE_+920>,0xa90(r0)
   0x00016101 <+27>:    movl 0xfffffff8(fp),r0
   0x00016105 <+31>:    movab *0x860cc <_GLOBAL_OFFSET_TABLE_+780>,0xa94(r0)
   0x0001610e <+40>:    movl 0xfffffff8(fp),r0
   0x00016112 <+44>:    movab *0x860c8 <_GLOBAL_OFFSET_TABLE_+776>,0xa98(r0)

I have no idea why it keeps reloading r0 after every line, but it
seems to be inserted by the linker, as the GCC assembly output for the
"-g" version looks like:

        movl 16(%r7),%r0
        movab cl_addstr,2704(%r0)
        movab cl_waddstr,2708(%r0)
        movab cl_attr,2712(%r0)

One more anomaly that I noticed was that the version of /usr/bin/gdb
compiled with GCC 4.1 fails to start from a GCC 4.5 chroot due to this

Undefined symbol "__clz_tab" referenced from COPY relocation in

So there's another data point that might help solve these linker
mysteries. Thanks in advance for anyone who can help with this.


Home | Main Index | Thread Index | Old Index