https://sourceware.org/bugzilla/show_bug.cgi?id=34540

            Bug ID: 34540
           Summary: SAME_INODE change makes two distinct -T linker scripts
                    fail on mingw hosts
           Product: binutils
           Version: 2.47
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: ld
          Assignee: unassigned at sourceware dot org
          Reporter: [email protected]
  Target Milestone: ---

Since 2.47, linking with two distinct -T scripts fails on a Windows host:

ld.exe: error: linker script file 'C:/src/file1.ld (C:/src/file2.ld)' appears
multiple times

The two files are unrelated. 2.46.1 links the same command line properly, and
ld/ldfile.c is byte-identical between the two releases.

The change is in include/same-inode.h, "same-inode.h: don't depend on
_GL_WINDOWS_STAT_INODES". Before that, the _WIN32 branch fell through to
#define SAME_INODE(a, b) 0 unless _GL_WINDOWS_STAT_INODES was defined, and it
isn't defined anywhere in the binutils tree outside gnulib/gdb, so the PR 24576
duplicate-script check in ldfile_find_command_file wasn't doing anything on
Windows. Now it runs this code:

#define SAME_INODE(a, b) \
  (!((a).st_ino == 0 && (a).st_dev == 0) \
   && (a).st_ino == (b).st_ino && (a).st_dev == (b).st_dev)

and without gnulib's windows-stat-inodes replacement, msvcrt's stat() sets
st_ino to 0 but leaves st_dev as the drive number. So the "information not
available" guard never triggers since st_dev is nonzero, and the comparison
then succeeds on 0 == 0 && drive == drive. Any two files on the same drive look
like the same file.

Compiling both releases' headers as-is with mingw and stat()ing two obviously
different files:

2.46.1   a: dev=25 ino=0 | b: dev=25 ino=0 | SAME_INODE=0
2.47     a: dev=25 ino=0 | b: dev=25 ino=0 | SAME_INODE=1

Keying the guard on st_ino alone, which is the field the CRT leaves unset,
fixes it: 

-    (!((a).st_ino == 0 && (a).st_dev == 0) \
+    ((a).st_ino != 0 \
       && (a).st_ino == (b).st_ino && (a).st_dev == (b).st_dev)

That restores 2.46.1 behaviour for plain stat(). SAME_INODE is simply never
true, so the duplicate check goes back to a no-op on Windows, while staying
correct for consumers that do use gnulib's replacement, where st_ino is a
nonzero file index. It doesn't make the duplicate check actually work on
Windows, and the commit message already said it wouldn't, but a linker that
refuses to link is worse than one that misses a diagnostic.

Patching 2.47 with the above and rebuilding the mipsel-none-elf cross toolchain
gives an ld that links the original command line fine on Windows.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to