[Top][All Lists]

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

[Bug gas/4558] New: branch on register condition accepts relocations >=

From: davem at davemloft dot net
Subject: [Bug gas/4558] New: branch on register condition accepts relocations >= 128K
Date: 28 May 2007 07:26:21 -0000

If the displacement from a "br*" instruction to the target of
the branch is 128K or more, gas writes garbace into the displacement
field(s) instead of generating a relocation overflow error.

The branch on register condition instructions have a 16-bit signed
displacement field, but it is split into two pieces of the instruction.
The low 14 bits are at bits 0-13 of the instruction, bits 14 and 15
of the displacement are at bits 21-20 of the instruction.

The test case is very simple:

1: nop
   .skip (128 * 1024)
   brz,pt %o0, 1b

Build this with "as -Av9a -o test.o test.s".  GAS allows this
erroneously, instead of generating a relocation failure.

You can look at the assembler of the object file with
"objdump --disassemble test.o" you will see output like:

00000000 <.text>:
       0:       01 00 00 00     nop
   20004:       02 da 3f ff     brz  %o0, 0x40000
   20008:       01 00 00 00     nop

which is obviously bogus.

sparc-opc.c uses 'k' character class for the relocation, this is
handled in tc-sparc.c with:

            case 'k':
              the_insn.reloc = /* RELOC_WDISP2_14 */ BFD_RELOC_SPARC_WDISP16;
              the_insn.pcrel = 1;
              goto immediate;

The comment reference to the mythical "RELOC_WDISP2_14" is quite
curious :-)

Later down in tc-sparc.c we have the handler for BFD_RELOC_SPARC_WDISP16:

        case BFD_RELOC_SPARC_WDISP16:
          /* FIXME: simplify.  */
          if (((val > 0) && (val & ~0x3fffc))
              || ((val < 0) && (~(val - 1) & ~0x3fffc)))
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relocation overflow"));
          /* FIXME: The +1 deserves a comment.  */
          val = (val >> 2) + 1;
          insn |= ((val & 0xc000) << 6) | (val & 0x3fff);

And here we have the bug, the reloc range checking is wrong.
The masks should be 0x1fffc instead of 0x3fffc.

           Summary: branch on register condition accepts relocations >= 128K
           Product: binutils
           Version: 2.18 (HEAD)
            Status: NEW
          Severity: normal
          Priority: P2
         Component: gas
        AssignedTo: unassigned at sources dot redhat dot com
        ReportedBy: davem at davemloft dot net
                CC: bug-binutils at gnu dot org
 GCC build triplet: sparc-unknown-linux-gnu
  GCC host triplet: sparc-unknown-linux-gnu
GCC target triplet: sparc-unknown-liunx-gnu


------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]