aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2025-08-12 07:37:57 -0700
committerH.J. Lu <hjl.tools@gmail.com>2025-08-14 08:00:04 -0700
commitd048eee2910878bf46f333f2fdc8ef940bd1638e (patch)
tree3bf531d3ba7e6859d3e2d557306bad38477f36d7
parent546ddc53ee289c4a831f10adb16c03e363437e17 (diff)
downloadbinutils-d048eee2910878bf46f333f2fdc8ef940bd1638e.zip
binutils-d048eee2910878bf46f333f2fdc8ef940bd1638e.tar.gz
binutils-d048eee2910878bf46f333f2fdc8ef940bd1638e.tar.bz2
ld: Use stat to check if linker script appears multiple times
Use stat, instead of strcmp, to check if the same linker script file appears multiple times for $ ld -L... -T ././/script.t -T script.t ... Although ././/script.t and script.t access the same file, but their filenames are different. strcmp won't work here. Copy gnulib/import/same-inode.h to include since the gnulib directory isn't included in the binutils tarball. include/ PR ld/24576 * same-inode.h: New file. Copied from gnulib/import/same-inode.h. ld/ PR ld/24576 * ldfile.c: Include "same-inode.h". (ldfile_find_command_file): Change the second argument from bool to enum script_open_style. Check if the same linker script file appears multiple times by using stat, instead using strcmp. (ldfile_open_command_file_1): Don't check if the same linker script file appears multiple times here. * testsuite/ld-scripts/pr24576-1.d: Adjusted. * testsuite/ld-scripts/pr24576-2.d: New. * testsuite/ld-scripts/script.exp: Run pr24576-2. Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
-rw-r--r--include/same-inode.h47
-rw-r--r--ld/ldfile.c74
-rw-r--r--ld/testsuite/ld-scripts/pr24576-1.d2
-rw-r--r--ld/testsuite/ld-scripts/pr24576-2.d3
-rw-r--r--ld/testsuite/ld-scripts/script.exp1
5 files changed, 95 insertions, 32 deletions
diff --git a/include/same-inode.h b/include/same-inode.h
new file mode 100644
index 0000000..f65f3d0
--- /dev/null
+++ b/include/same-inode.h
@@ -0,0 +1,47 @@
+/* Determine whether two stat buffers are known to refer to the same file.
+
+ Copyright (C) 2006, 2009-2022 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#ifndef SAME_INODE_H
+# define SAME_INODE_H 1
+
+# include <sys/types.h>
+
+# if defined __VMS && __CRTL_VER < 80200000
+# define SAME_INODE(a, b) \
+ ((a).st_ino[0] == (b).st_ino[0] \
+ && (a).st_ino[1] == (b).st_ino[1] \
+ && (a).st_ino[2] == (b).st_ino[2] \
+ && (a).st_dev == (b).st_dev)
+# elif defined _WIN32 && ! defined __CYGWIN__
+ /* Native Windows. */
+# if _GL_WINDOWS_STAT_INODES
+ /* stat() and fstat() set st_dev and st_ino to 0 if information about
+ the inode is not available. */
+# 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)
+# else
+ /* stat() and fstat() set st_ino to 0 always. */
+# define SAME_INODE(a, b) 0
+# endif
+# else
+# define SAME_INODE(a, b) \
+ ((a).st_ino == (b).st_ino \
+ && (a).st_dev == (b).st_dev)
+# endif
+
+#endif
diff --git a/ld/ldfile.c b/ld/ldfile.c
index e642c7f..ce81fdc 100644
--- a/ld/ldfile.c
+++ b/ld/ldfile.c
@@ -35,6 +35,7 @@
#include "libiberty.h"
#include "filenames.h"
#include <fnmatch.h>
+#include "same-inode.h"
#if BFD_SUPPORTS_PLUGINS
#include "plugin.h"
#endif /* BFD_SUPPORTS_PLUGINS */
@@ -828,19 +829,26 @@ find_scripts_dir (void)
static FILE *
ldfile_find_command_file (const char *name,
- bool default_only,
+ enum script_open_style open_how,
bool *sysrooted)
{
search_dirs_type *search;
FILE *result = NULL;
- char *path;
+ char *path = NULL;
+ const char *filename = NULL;
+ struct script_name_list *script;
+ size_t len;
+ struct stat sbuf1;
- if (!default_only)
+ if (open_how != script_defaultT)
{
/* First try raw name. */
result = try_open (name, sysrooted);
if (result != NULL)
- return result;
+ {
+ filename = name;
+ goto success;
+ }
}
if (!script_search)
@@ -861,20 +869,47 @@ ldfile_find_command_file (const char *name,
*search_tail_ptr = script_search;
/* Try now prefixes. */
- for (search = default_only ? script_search : search_head;
+ for (search = open_how == script_defaultT ? script_search : search_head;
search != NULL;
search = search->next)
{
path = concat (search->name, slash, name, (const char *) NULL);
result = try_open (path, sysrooted);
- free (path);
if (result)
- break;
+ {
+ filename = path;
+ break;
+ }
}
/* Restore the original path list. */
*search_tail_ptr = NULL;
+ success:
+ /* PR 24576: Catch the case where the user has accidentally included
+ the same linker script twice. */
+ if (stat (filename, &sbuf1) == 0)
+ {
+ struct stat sbuf2;
+ for (script = processed_scripts;
+ script != NULL;
+ script = script->next)
+ if ((open_how != script_nonT || script->open_how != script_nonT)
+ && stat (script->name, &sbuf2) == 0
+ && SAME_INODE (sbuf1, sbuf2))
+ fatal (_("%P: error: linker script file '%s (%s)'"
+ " appears multiple times\n"), filename, script->name);
+ }
+
+ len = strlen (filename);
+ script = xmalloc (sizeof (*script) + len);
+ script->next = processed_scripts;
+ script->open_how = open_how;
+ memcpy (script->name, filename, len + 1);
+ processed_scripts = script;
+
+ free (path);
+
return result;
}
@@ -886,31 +921,8 @@ ldfile_open_command_file_1 (const char *name, enum script_open_style open_how)
{
FILE *ldlex_input_stack;
bool sysrooted;
- struct script_name_list *script;
- size_t len;
-
- /* PR 24576: Catch the case where the user has accidentally included
- the same linker script twice. */
- for (script = processed_scripts; script != NULL; script = script->next)
- {
- if ((open_how != script_nonT || script->open_how != script_nonT)
- && strcmp (name, script->name) == 0)
- {
- fatal (_("%P: error: linker script file '%s'"
- " appears multiple times\n"), name);
- return;
- }
- }
-
- len = strlen (name);
- script = xmalloc (sizeof (*script) + len);
- script->next = processed_scripts;
- script->open_how = open_how;
- memcpy (script->name, name, len + 1);
- processed_scripts = script;
- ldlex_input_stack = ldfile_find_command_file (name,
- open_how == script_defaultT,
+ ldlex_input_stack = ldfile_find_command_file (name, open_how,
&sysrooted);
if (ldlex_input_stack == NULL)
{
diff --git a/ld/testsuite/ld-scripts/pr24576-1.d b/ld/testsuite/ld-scripts/pr24576-1.d
index 9f9f487..6cc7621 100644
--- a/ld/testsuite/ld-scripts/pr24576-1.d
+++ b/ld/testsuite/ld-scripts/pr24576-1.d
@@ -1,3 +1,3 @@
#source: default-script.s
#ld: -defsym _START=0x800 -T default-script.t -T default-script.t
-#error: .*default-script.t' appears multiple times
+#error: .*default-script.t\)' appears multiple times
diff --git a/ld/testsuite/ld-scripts/pr24576-2.d b/ld/testsuite/ld-scripts/pr24576-2.d
new file mode 100644
index 0000000..2d26ab3
--- /dev/null
+++ b/ld/testsuite/ld-scripts/pr24576-2.d
@@ -0,0 +1,3 @@
+#source: default-script.s
+#ld: -defsym _START=0x800 -T ././/default-script.t -T default-script.t
+#error: .*default-script.t\)' appears multiple times
diff --git a/ld/testsuite/ld-scripts/script.exp b/ld/testsuite/ld-scripts/script.exp
index c223135..0b37675 100644
--- a/ld/testsuite/ld-scripts/script.exp
+++ b/ld/testsuite/ld-scripts/script.exp
@@ -234,6 +234,7 @@ run_dump_test "output-section-types"
run_dump_test "ld-version"
run_dump_test "ld-version-2"
run_dump_test "pr24576-1"
+run_dump_test "pr24576-2"
run_dump_test "segment-start" {{name (default)}}
run_dump_test "segment-start" {{name (overridden)} \