Subject: load/store address overflow on binutils 2.14

From: Atsushi Nemoto <[email-masked]>
Date: Thu, 07 Aug 2003 19:03:30 +0900 (JST)

I'm trying binutils 2.14 (and binutils 2.14.90.0.5).  These versions
can not compile this inctruction.

	lw	$2, 0x80000000

$ mips-linux-gcc -c foo.s
b.S: Assembler messages:
foo.S:1: Error: load/store address overflow (max 32 bits)

Using such an immediate address for load instructions is legal?  I
found the error message in tc-mips.c and it looks like something
related to 64bit ABIs, but I just want to compile 32bit (standalone)
program.

Is this code really needed for 32bit ABI?

binutils-2.14/gas/config/tc-mips.c:6297
 	  else if (offset_expr.X_op == O_constant
 		   && !HAVE_64BIT_ADDRESS_CONSTANTS
 		   && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
 	    as_bad (_("load/store address overflow (max 32 bits)"));

---
Atsushi Nemoto

---

From: Thiemo Seufer <[email-masked]>
Date: Fri, 8 Aug 2003 01:15:18 +0200

>  	    as_bad (_("load/store address overflow (max 32 bits)"));

It shouldn't trigger for 32bit, because 0x80000000 is a sign-extended
32bit number. How is mips-linux-as actually invoked?

Thiemo

---

From: Atsushi Nemoto <[email-masked]>
Date: Fri, 08 Aug 2003 10:11:02 +0900 (JST)

>>>>> On Fri, 8 Aug 2003 01:15:18 +0200, Thiemo Seufer <[email-masked]> said:
Thiemo> It shouldn't trigger for 32bit, because 0x80000000 is a
Thiemo> sign-extended 32bit number. How is mips-linux-as actually
Thiemo> invoked?

Like this (using mipsel):

$ mipsel-linux-gcc -o b.o -c -v b.S
Reading specs from /usr/lib/gcc-lib/mipsel-linux/3.3/specs
Configured with: ../gcc-3.3/configure --target=mipsel-linux --prefix=/usr --disable-nls --enable-languages=c --disable-shared --disable-threads
Thread model: single
gcc version 3.3
 /usr/lib/gcc-lib/mipsel-linux/3.3/cc1 -E -lang-asm -quiet -v -D__GNUC__=3 -D__GNUC_MINOR__=3 -D__GNUC_PATCHLEVEL__=0 b.S -o /tmp/cceVg6Jo.s
ignoring nonexistent directory "/usr/mipsel-linux/sys-include"
ignoring nonexistent directory "/usr/mipsel-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc-lib/mipsel-linux/3.3/include
End of search list.
 /usr/lib/gcc-lib/mipsel-linux/3.3/../../../../mipsel-linux/bin/as -EL -g0 -32 -v -KPIC -o b.o /tmp/cceVg6Jo.s
GNU assembler version 2.14 (mipsel-linux) using BFD version 2.14 20030612
b.S: Assembler messages:
b.S:1: Error: load/store address overflow (max 32 bits)

The b.S is just one line "lw $2, 0x80000000".

Just typing "mipsel-linux-as -o b.o b.S" produces same error.

---
Atsushi Nemoto

---

From: Thiemo Seufer <[email-masked]>
Date: Fri, 8 Aug 2003 05:07:05 +0200

> The b.S is just one line "lw $2, 0x80000000".

Using  0xffffffff80000000 is a really ugly workaround for it.
Seems like the constant isn't properly sign-extended inernally
by the assembler.

Thiemo

---

From: Atsushi Nemoto <[email-masked]>
Date: Sat, 09 Aug 2003 00:06:03 +0900 (JST)

>>>>> On Fri, 8 Aug 2003 05:07:05 +0200, Thiemo Seufer <[email-masked]> said:
Thiemo> Using 0xffffffff80000000 is a really ugly workaround for it.
Thiemo> Seems like the constant isn't properly sign-extended inernally
Thiemo> by the assembler.

Yes the workaround works.  But I modified binutils (just remove the
checking code) instead of changing many constant definitions in my
programs.  For now it is enough for me.  Thank you.
---
Atsushi Nemoto

---

From: Thiemo Seufer <[email-masked]>
Date: Sun, 10 Aug 2003 14:08:44 +0200

> programs.  For now it is enough for me.  Thank you.

It is probably not a real binutils bug, but related to gcc mishandling
'unsigned long long'. The simple testcase

int main(void)
{
        unsigned long long a = 0;

        printf("%016x\n", ~a);

        return 0;
}

outputs

00000000ffffffff

on my i386-linux system. On mips-linux it's even worse, the result is

000000000000000b

If this is really an arch-independent problem, any (cross-)compile on
a 32bit system for 64bit BFD can be broken.

Thiemo

---

From: Chip Coldwell <[email-masked]>
Date: Sun, 10 Aug 2003 10:36:51 -0400 (EDT)

On Sun, 10 Aug 2003, Thiemo Seufer wrote:

> on my i386-linux system.

Strangely, this is actually "correct" behavior.  Arguments on
variable-length argument lists are implicitly "promoted" to unsigned
int at the widest.  See K&R 2nd ed. A6.1 and A7.3.2.  Things may have
changed with C99, but this would have been expected behavior for ANSI
C, and strange results were to be had when "long int" was wider than
"int" and was passed on a variable-length argument list.

Chip

-- 
Charles  M. "Chip" Coldwell      __o
"Turn on, log in, tune out"      \<
                              (@)/(@) 
-------------------------------------

---

From: Thiemo Seufer <[email-masked]>
Date: Sun, 10 Aug 2003 16:54:25 +0200

Chip Coldwell wrote:
[snip]
> int at the widest.  See K&R 2nd ed. A6.1 and A7.3.2.

Ugh. Thanks for pointing this out. I wasn't aware of it.

	printf("%016Lx\n", ~a);

Produces the expected output. So it is actually an implementation
bug in binutils, which isn't fixable for 2.14 and earlier, because
those have to remain at K&R C level. The K&R requirement was only
recenly loosened.

Thiemo

---

From: "Maciej W. Rozycki" <[email-masked]>
Date: Mon, 11 Aug 2003 12:55:02 +0200 (MET DST)

> those have to remain at K&R C level. The K&R requirement was only

 Strangely enough, the Atsushi's code builds just fine with 2.13.2.1. 

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: [email-masked], PGP key available        +

---

From: Geert Uytterhoeven <[email-masked]>
Date: Mon, 11 Aug 2003 22:58:13 +0200 (MEST)

> those have to remain at K&R C level. The K&R requirement was only

How can it print the correct output if ~a is `promoted' to unsigned int, while
you specify %Lx in the format string?

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email-masked]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds

---

From: Thiemo Seufer <[email-masked]>
Date: Tue, 12 Aug 2003 01:10:19 +0200

>  Strangely enough, the Atsushi's code builds just fine with 2.13.2.1.

The test in binutils it stumbled over was added later.

Thiemo

---

From: Thiemo Seufer <[email-masked]>
Date: Tue, 12 Aug 2003 01:16:35 +0200

Geert Uytterhoeven wrote:
[snip]
> you specify %Lx in the format string?

From 'info gcc':

Double-Word Integers
====================

   ISO C99 supports data types for integers that are at least 64 bits
wide, and as an extension GCC supports them in C89 mode and in C++.
[...]
   There may be pitfalls when you use `long long' types for function
arguments, unless you declare function prototypes.  If a function
expects type `int' for its argument, and you pass a value of type `long
long int', confusion will result because the caller and the subroutine
will disagree about the number of bytes for the argument.  Likewise, if
the function expects `long long int' and you pass `int'.  The best way
to avoid such problems is to use prototypes.

Thiemo