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>
This commit is contained in:
H.J. Lu
2025-08-12 07:37:57 -07:00
parent 546ddc53ee
commit d048eee291
5 changed files with 95 additions and 32 deletions

47
include/same-inode.h Normal file
View File

@@ -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

View File

@@ -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)
{
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)
{

View File

@@ -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

View File

@@ -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

View File

@@ -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)} \