Bug 31096 - nm for mips32 (native or cross-compiled) shows 32bit addresses as sign-extended 64bit addresses
Summary: nm for mips32 (native or cross-compiled) shows 32bit addresses as sign-extend...
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Alan Modra
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-11-29 12:28 UTC by Nicolas Schier
Modified: 2023-12-06 04:03 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2023-12-04 00:00:00


Attachments
nm: Enforce 32-bit width limit when printing 32-bit values (797 bytes, patch)
2023-12-04 13:07 UTC, Nicolas Schier
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Nicolas Schier 2023-11-29 12:28:14 UTC
nm for MIPS32 shows addresses from 0x8000000 and above as sign-extended(!) 64bit addresses.  To reproduce:

    $ cat <<-eof >test.c
    int test(void) {
        return 0;
    }
    eof

    $ echo ". = 0x80000000;" >test.lds

    $ mips-linux-gnu-gcc test.c -Wl,-T,test.lds -static -nostdlib -ffreestanding -o test

    $ mips-linux-gnu-nm test
    ffffffff80000000 T test

    $ x86_64-gnu-linux-nm test
    80000000 T test

Tested with x86_64-cross-mips32-nm (binutils 2.33, 2.40 (alpine); 2.35, 2.41 (Debian)) as well as with native nm (under qemu-mips-chroot).  (Same behaviour was also observed with binutils-multiarch (Debian).)

Initially, the failure was observed during compilation of Linux for MIPS32, where mips32-nm produces a System.map with sign-extended 64bit addresses.  Native x86_64-nm shows correct 32bit addresses on the same binary files.
Comment 1 Nick Clifton 2023-11-30 12:41:28 UTC
Hi Nicolas,

  This is actually expected behaviour.

  The MIPS architecture uses a signed address space, and tools configured to support the MIPS are aware of this.  Hence the mips-linux-gnu-nm tool displays a signed address.  Some tools however can be used on architectures for which they were not configured.  Nm is one of these tools.  So if you use x86_64-linux-gnu-nm on a MIPS binary, it will be able to display the symbols, but it will display their addresses as unsigned values, since that is how the x86_64 architecture treats its addresses.

  Basically if you want to discover information about MIPS binaries, use tools that are configured to support the MIPS architecture.

  Note - it is still possible to use cross tools, they just need to support the MIPS.  So for example if you build the binutils on an x86_64 host and use the "--enable-targets=all" configure option, then they will be able to correctly handle MIPS binaries, as well as x86_64 binaries and indeed most other architectures as well.

  Does this make sense ?

Cheers
  Nick
Comment 2 Nicolas Schier 2023-12-04 10:26:09 UTC
Hi Nick,

(In reply to Nick Clifton from comment #1)
> Hi Nicolas,
> 
>   This is actually expected behaviour.
> 
>   The MIPS architecture uses a signed address space, and tools configured to
> support the MIPS are aware of this.  Hence the mips-linux-gnu-nm tool
> displays a signed address.  Some tools however can be used on architectures
> for which they were not configured.  Nm is one of these tools.  So if you
> use x86_64-linux-gnu-nm on a MIPS binary, it will be able to display the
> symbols, but it will display their addresses as unsigned values, since that
> is how the x86_64 architecture treats its addresses.
> 
>   Basically if you want to discover information about MIPS binaries, use
> tools that are configured to support the MIPS architecture.

thanks for the insights and explanations, I am still a bit bewildered of 
"signed address space" and its implications.  The most irritating thing for me
is still that a mip32-native `nm` shows addresses of a mips32-native binary as
64-bit addresses, while mips32-native `objdump` shows 32-bit addresses:

    $ objdump -t ../my-mips32-binary 
    
    ../my-mips32-binary:     file format elf32-tradlittlemips
    
    SYMBOL TABLE:
    80000000 l    d  .note.gnu.build-id     00000000 .note.gnu.build-id
    80000030 l    d  .text  00000000 .text
    [...]
    00000000 l    df *ABS*  00000000 test.c
    80000030 g     F .text  00000024 test
    
    $ nm ../my-mips32-binary
    ffffffff80000030 T test

For my local work, a simple patch such as:

diff --git a/binutils/nm.c b/binutils/nm.c
index e4c8036df1b..7e42ce8f469 100644
--- a/binutils/nm.c
+++ b/binutils/nm.c
@@ -1821,6 +1821,9 @@ print_value (bfd *abfd ATTRIBUTE_UNUSED, bfd_vma val)
   switch (print_width)
     {
     case 32:
+      printf (print_format_string, 0xffffffff & (uint64_t) val);
+      break;
+
     case 64:
       printf (print_format_string, (uint64_t) val);
       break;

would be sufficient to get the output that I expect:

    $ binutils/nm-new ../mips32-test
    80000030 T test

here, `nm-new` is a mips32-native `nm`.  A native mips64el build of `nm`
shows this:

    $ binutils/nm-new /tmp/mips64el-test 
    0000000080000030 T test
    $ binutils/nm-new /tmp/mips32-test 
    80000030 T test

which is exactly what I had originally expected.

Am I still missing some point?  Is it really intended that `nm` shows 64-bit
addresses for mips32 targets?

If not, I plan to forward the patch to binutils@sourceware.org.

Kind regards,
Nicolas
Comment 3 Nick Clifton 2023-12-04 11:51:23 UTC
(In reply to Nicolas Schier from comment #2)
 
> thanks for the insights and explanations, I am still a bit bewildered of 
> "signed address space" and its implications.

Agreed.  I have always felt that it was a strange choice by the MIPS designers.

 
> Am I still missing some point?  Is it really intended that `nm` shows 64-bit
> addresses for mips32 targets?

No - you are right, this is a bug.

> If not, I plan to forward the patch to binutils@sourceware.org.

Please do.

Cheers
  Nick
Comment 4 Nicolas Schier 2023-12-04 13:07:17 UTC
Created attachment 15234 [details]
nm: Enforce 32-bit width limit when printing 32-bit values

Patch is sent to binutils@sourceware.org: https://sourceware.org/pipermail/binutils/2023-December/130966.html
Comment 5 Sourceware Commits 2023-12-06 02:59:43 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3c8852fcc806915fdeab8b3d6f49be7347160527

commit 3c8852fcc806915fdeab8b3d6f49be7347160527
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Dec 5 09:23:41 2023 +1030

    PR31096, nm shows 32bit addresses as 64bit addresses
    
    Prior to commit 0e3c1eebb2 nm output depended on the host unsigned
    long when printing "negative" symbol values for 32-bit targets.
    Commit 0e3c1eebb22 made the output match that seen with a 64-bit host
    unsigned long.  The fact that nm output changed depending on host is
    of course a bug, but it is reasonable to expect 32-bit target output
    is only 32 bits.  So this patch makes 32-bit target output the same as
    it was on 32-bit hosts prior to 0e3c1eebb2.
    
            PR 31096
            * nm.c (print_format_string): Make it a static buffer.
            (get_print_format): Merge into..
            (set_print_format): ..this, renamed from set_print_width.  When
            print_width is 32, set up print_format_string for an int32_t
            value.  Don't malloc print_format_string.  Adjust calls.
            (print_value): Correct printing of 32-bit values.
Comment 6 Alan Modra 2023-12-06 04:03:06 UTC
Fixed