diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2025-08-12 07:37:57 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2025-08-14 08:00:04 -0700 |
commit | d048eee2910878bf46f333f2fdc8ef940bd1638e (patch) | |
tree | 3bf531d3ba7e6859d3e2d557306bad38477f36d7 | |
parent | 546ddc53ee289c4a831f10adb16c03e363437e17 (diff) | |
download | binutils-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.h | 47 | ||||
-rw-r--r-- | ld/ldfile.c | 74 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/pr24576-1.d | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/pr24576-2.d | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/script.exp | 1 |
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)} \ |