PR 20814
This commit is contained in:
Nick Clifton 2024-06-26 13:17:25 +01:00
parent cbccccfdf1
commit 057a2b4c4b
14 changed files with 265 additions and 39 deletions

View File

@ -784,9 +784,10 @@ typedef struct export
int ordinal;
int constant;
int noname; /* Don't put name in image file. */
int private; /* Don't put reference in import lib. */
int private; /* Don't put reference in import lib. */
int data;
int forward; /* Number of forward label, 0 means no forward. */
int hint;
int forward; /* Number of forward label, 0 means no forward. */
struct export *next;
}
export_type;
@ -2697,8 +2698,10 @@ make_one_lib_file (export_type *exp, int i, int delay)
case IDATA6:
if (!exp->noname)
{
int idx = exp->ordinal;
/* This used to add 1 to exp->hint. I don't know
why it did that, and it does not match what I see
in programs compiled with the MS tools. */
int idx = exp->hint;
if (exp->its_name)
si->size = strlen (exp->its_name) + 3;
else
@ -3058,6 +3061,7 @@ gen_lib_file (int delay)
alias_exp.noname = exp->noname;
alias_exp.private = exp->private;
alias_exp.data = exp->data;
alias_exp.hint = exp->hint;
alias_exp.forward = exp->forward;
alias_exp.next = exp->next;
n = make_one_lib_file (&alias_exp, i + PREFIX_ALIAS_BASE, delay);
@ -3711,8 +3715,10 @@ mangle_defs (void)
{
/* First work out the minimum ordinal chosen. */
export_type *exp;
export_type **d_export_vec = xmalloc (sizeof (export_type *) * d_nfuncs);
int i;
int hint = 0;
export_type **d_export_vec = xmalloc (sizeof (export_type *) * d_nfuncs);
inform (_("Processing definitions"));
@ -3741,6 +3747,11 @@ mangle_defs (void)
qsort (d_exports_lexically, i, sizeof (export_type *), nfunc);
/* Fill exp entries with their hint values. */
for (i = 0; i < d_nfuncs; i++)
if (!d_exports_lexically[i]->noname || show_allnames)
d_exports_lexically[i]->hint = hint++;
inform (_("Processed definitions"));
}

View File

@ -457,7 +457,7 @@ Specify dependencies of this library. The dependencies must immediately
follow this option character, must use the same syntax as the linker
command line, and must be specified within a single argument. I.e., if
multiple items are needed, they must be quoted to form a single command
line argument. For example @samp{L "-L/usr/local/lib -lmydep1 -lmydep2"}
line argument. For example @samp{l "-L/usr/local/lib -lmydep1 -lmydep2"}
@item N
Uses the @var{count} parameter. This is used if there are multiple

View File

@ -7614,6 +7614,7 @@ command line option. @xref{Options}.
@menu
* libdep Plugin:: Static Library Dependencies Plugin
* lto Plugin:: LTO Plugin
@end menu
@node libdep Plugin
@ -7652,6 +7653,24 @@ the @samp{__.LIBDEP} member of @file{libssl.a} would contain
-L/usr/local/lib -lcrypto
@end smallexample
Note any library search directories added in this way are only used to
search for libraries which are also added the same plugin. They are
not used for searching for libraries specified on the linker command
line, linker scripts or other plugins. This does however present a
problem if multiple archives with @samp{__.LIBDEP} entries are present
as they will all be handled by the libdep plugin and thus they will
share library search paths. This could result in a library being
loaded from an unexpected location.
@node lto Plugin
@section LTO Plugin
Although not shipped with the binutils the LTO Plugin from the GCC
project is nevertheless a plugin that is designed to work with the
linker. The plugin intercepts object files as they are loaded by the
linker and instead sends them to the LTO compiler. When that compiler
finishes the resulting object file(s) are passed back to the linker
for normal processing.
@node Special Sections
@chapter Special Sections
When linking ELF format object files @command{ld} treats some sections

View File

@ -1170,7 +1170,7 @@ ldelf_handle_dt_needed (struct elf_link_hash_table *htab,
{
char *filename;
if (search->cmdline)
if (search->source != search_dir_linker_script)
continue;
filename = (char *) xmalloc (strlen (search->name) + len + 2);
sprintf (filename, "%s/%s", search->name, l->name);

View File

@ -40,12 +40,6 @@
#include "plugin.h"
#endif /* BFD_SUPPORTS_PLUGINS */
bool ldfile_assumed_script = false;
const char *ldfile_output_machine_name = "";
unsigned long ldfile_output_machine;
enum bfd_architecture ldfile_output_architecture;
search_dirs_type *search_head;
#ifdef VMS
static char *slash = "";
#else
@ -62,6 +56,12 @@ typedef struct search_arch
struct search_arch *next;
} search_arch_type;
bool ldfile_assumed_script = false;
const char * ldfile_output_machine_name = "";
unsigned long ldfile_output_machine;
enum bfd_architecture ldfile_output_architecture;
search_dirs_type * search_head;
static search_dirs_type **search_tail_ptr = &search_head;
static search_arch_type *search_arch_head;
static search_arch_type **search_arch_tail_ptr = &search_arch_head;
@ -303,21 +303,20 @@ is_sysrooted_pathname (const char *name)
}
/* Adds NAME to the library search path.
Makes a copy of NAME using xmalloc(). */
Makes a copy of NAME using xmalloc().
Returns a pointer to the newly created search_dirs_type structure
or NULL if there was a problem. */
void
ldfile_add_library_path (const char *name, bool cmdline)
search_dirs_type *
ldfile_add_library_path (const char *name, enum search_dir_source source)
{
search_dirs_type *new_dirs;
if (!cmdline && config.only_cmd_line_lib_dirs)
return;
if (source != search_dir_cmd_line && config.only_cmd_line_lib_dirs)
return NULL;
new_dirs = (search_dirs_type *) xmalloc (sizeof (search_dirs_type));
new_dirs->next = NULL;
new_dirs->cmdline = cmdline;
*search_tail_ptr = new_dirs;
search_tail_ptr = &new_dirs->next;
new_dirs->source = source;
/* If a directory is marked as honoring sysroot, prepend the sysroot path
now. */
@ -327,6 +326,25 @@ ldfile_add_library_path (const char *name, bool cmdline)
new_dirs->name = concat (ld_sysroot, name + strlen ("$SYSROOT"), (const char *) NULL);
else
new_dirs->name = xstrdup (name);
/* Accumulate script and command line sourced
search paths at the end of the current list. */
#if BFD_SUPPORTS_PLUGINS
/* PR 31904: But put plugin sourced paths at the start of the list. */
if (source == search_dir_plugin)
{
new_dirs->next = search_head;
search_head = new_dirs;
}
else
#endif
{
new_dirs->next = NULL;
*search_tail_ptr = new_dirs;
search_tail_ptr = &new_dirs->next;
}
return new_dirs;
}
/* Try to open a BFD for a lang_input_statement. */
@ -352,9 +370,9 @@ ldfile_try_open_bfd (const char *attempt,
return false;
}
/* PR 30568: Do not track lto generated temporary object files. */
/* PR 30568: Do not track plugin generated object files. */
#if BFD_SUPPORTS_PLUGINS
if (!entry->flags.lto_output)
if (entry->plugin != NULL)
#endif
track_dependency_files (attempt);
@ -365,7 +383,7 @@ ldfile_try_open_bfd (const char *attempt,
entry->the_bfd->is_linker_input = 1;
#if BFD_SUPPORTS_PLUGINS
if (entry->flags.lto_output)
if (entry->plugin != NULL)
entry->the_bfd->lto_output = 1;
#endif
@ -576,6 +594,14 @@ ldfile_open_file_search (const char *arch,
{
char *string;
#if BFD_SUPPORTS_PLUGINS
/* PR 31904: Only check a plugin sourced search
directory if the file is from the same plugin. */
if (search->source == search_dir_plugin
&& entry->plugin != search->plugin)
continue;
#endif
if (entry->flags.dynamic && !bfd_link_relocatable (&link_info))
{
if (ldemul_open_dynamic_archive (arch, search, entry))
@ -844,7 +870,7 @@ ldfile_find_command_file (const char *name,
{
search_dirs_type **save_tail_ptr = search_tail_ptr;
search_tail_ptr = &script_search;
ldfile_add_library_path (script_dir, true);
(void) ldfile_add_library_path (script_dir, search_dir_cmd_line);
search_tail_ptr = save_tail_ptr;
}
}
@ -858,6 +884,11 @@ ldfile_find_command_file (const char *name,
search != NULL;
search = search->next)
{
#if BFD_SUPPORTS_PLUGINS
/* Do not search for linker commands in plugin sourced search directories. */
if (search->source == search_dir_plugin)
continue;
#endif
path = concat (search->name, slash, name, (const char *) NULL);
result = try_open (path, sysrooted);
free (path);

View File

@ -26,6 +26,15 @@ extern unsigned long ldfile_output_machine;
extern enum bfd_architecture ldfile_output_architecture;
extern const char *ldfile_output_machine_name;
enum search_dir_source
{
search_dir_cmd_line,
#if BFD_SUPPORTS_PLUGINS
search_dir_plugin,
#endif
search_dir_linker_script
};
/* Structure used to hold the list of directories to search for
libraries. */
@ -35,8 +44,12 @@ typedef struct search_dirs
struct search_dirs *next;
/* Name of directory. */
const char *name;
/* TRUE if this is from the command line. */
bool cmdline;
/* Where the search path came from. */
enum search_dir_source source;
#if BFD_SUPPORTS_PLUGINS
/* For search dirs added by plugins, the plugin that added them. */
void * plugin;
#endif
} search_dirs_type;
enum script_open_style
@ -59,8 +72,8 @@ extern search_dirs_type *search_head;
extern void ldfile_add_arch
(const char *);
extern void ldfile_add_library_path
(const char *, bool cmdline);
extern search_dirs_type * ldfile_add_library_path
(const char *, enum search_dir_source);
extern void ldfile_open_command_file
(const char *name);
extern void ldfile_open_script_file

View File

@ -321,7 +321,7 @@ ifile_p1:
| TARGET_K '(' NAME ')'
{ lang_add_target($3); }
| SEARCH_DIR '(' filename ')'
{ ldfile_add_library_path ($3, false); }
{ ldfile_add_library_path ($3, search_dir_linker_script); }
| OUTPUT '(' filename ')'
{ lang_add_output($3, 1); }
| OUTPUT_FORMAT '(' NAME ')'

View File

@ -293,9 +293,6 @@ struct lang_input_statement_flags
/* Set if the file was claimed from an archive. */
unsigned int claim_archive : 1;
/* Set if added by the lto plugin add_input_file callback. */
unsigned int lto_output : 1;
#endif /* BFD_SUPPORTS_PLUGINS */
/* Head of list of pushed flags. */
@ -332,6 +329,11 @@ typedef struct lang_input_statement_struct
const char *target;
struct lang_input_statement_flags flags;
#if BFD_SUPPORTS_PLUGINS
/* If non-NULL the plugin that added this file. */
void * plugin;
#endif
} lang_input_statement_type;
typedef struct

View File

@ -1052,7 +1052,8 @@ parse_args (unsigned argc, char **argv)
xexit (0);
break;
case 'L':
ldfile_add_library_path (optarg, true);
/* FIXME: Check the return value ? */
(void) ldfile_add_library_path (optarg, search_dir_cmd_line);
break;
case 'l':
lang_add_input_file (optarg, lang_input_file_is_l_enum, NULL);
@ -2086,7 +2087,8 @@ set_default_dirlist (char *dirlist_ptr)
if (p != NULL)
*p = '\0';
if (*dirlist_ptr != '\0')
ldfile_add_library_path (dirlist_ptr, true);
/* FIXME: Check the return value ? */
(void) ldfile_add_library_path (dirlist_ptr, search_dir_cmd_line);
if (p == NULL)
break;
dirlist_ptr = p + 1;

View File

@ -928,7 +928,7 @@ add_input_file (const char *pathname)
NULL);
if (!is)
return LDPS_ERR;
is->flags.lto_output = 1;
is->plugin = called_plugin;
return LDPS_OK;
}
@ -943,17 +943,23 @@ add_input_library (const char *pathname)
NULL);
if (!is)
return LDPS_ERR;
is->flags.lto_output = 1;
is->plugin = called_plugin;
return LDPS_OK;
}
/* Set the extra library path to be used by libraries added via
add_input_library. */
static enum ld_plugin_status
set_extra_library_path (const char *path)
{
search_dirs_type * sdt;
ASSERT (called_plugin);
ldfile_add_library_path (xstrdup (path), false);
sdt = ldfile_add_library_path (xstrdup (path), search_dir_plugin);
if (sdt == NULL)
return LDPS_ERR;
sdt->plugin = called_plugin;
return LDPS_OK;
}

View File

@ -0,0 +1,7 @@
extern int g (void);
int
f (void)
{
return g();
}

View File

@ -0,0 +1,5 @@
int
g (void)
{
return 4;
}

View File

@ -0,0 +1,7 @@
extern int f (void);
int
main (void)
{
return f();
}

View File

@ -0,0 +1,123 @@
# Expect script for ld-plugin LIBDEP tests
# Copyright (C) 2024 Free Software Foundation, Inc.
#
# This file is part of the GNU Binutils.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
# MA 02110-1301, USA.
# These tests require the plugin API.
if { ![check_plugin_api_available] } {
return
}
# Check to see if the C compiler works
# FIXME: This is being lazy, we could create assembler equivalents instead.
if { ![check_compiler_available] } {
return
}
proc run_test { } {
global CC_FOR_TARGET
global srcdir
global subdir
global ar
global ld
global libdep
global base_dir
set testname "libdep test"
# Create temporary directories if they do not already exist.
file mkdir -p libdep-a libdep-b
# Delete old versions of the files we are about to build, just in case.
file delete libdep-a/a.o libdep-a/liba.a libdep-b/b.o libdep-b/libc.a libdep-main.o
# Build object files.
if {![ld_compile $CC_FOR_TARGET $srcdir/$subdir/libdep-a.c libdep-a/a.o]} {
fail "$testname: could not compile source file 1"
return
}
if {![ld_compile $CC_FOR_TARGET $srcdir/$subdir/libdep-b.c libdep-b/b.o]} {
fail "$testname: could not compile source file 2"
return
}
if {![ld_compile $CC_FOR_TARGET $srcdir/$subdir/libdep-main.c libdep-main.o]} {
fail "$testname: could not compile source file 3"
return
}
# Create static archives from the objects.
# For the first archive we add a libdep element that loads the second library.
if {![ar_simple_create $ar {--record-libdeps "-Llibdep-b -lc"} libdep-a/liba.a libdep-a/a.o]} {
fail "$testname: could not create archive 1"
return
}
# For the second archive we choose a name - libc.a - that is likely to clash
# with a system library. This will help to check that the library loaded by
# following the libdep element in the first library is the one that we expect.
if {![ar_simple_create $ar {} libdep-b/libc.a libdep-b/b.o]} {
fail "$testname: could not create archive 2"
return
}
# Find the libdep plugin.
# Use libtool to find the path to the plugin rather
# than worrying about run paths or anything like that.
catch "exec $base_dir/libtool --config" lt_config
verbose "Full lt config: $lt_config" 2
# Look for "objdir=.libs"
regexp -line "^objdir=.*$" "$lt_config" lt_objdir
verbose "lt_objdir line is '$lt_objdir'" 2
set lt_objdir [regsub "objdir=" "$lt_objdir" ""]
if { [ file exists "$base_dir/$lt_objdir/libdep.so" ] } {
set libdep "$base_dir/$lt_objdir/libdep.so"
} else {
# FIXME: Check in the system bfd-plugin directory ?
fail "$testname - could not locate libdep plugin"
}
verbose "Full plugin path: $libdep" 1
# Link the main object file with the liba.a library.
# Use the libdep plugin to read the __.LIBDEP element in the liba.a library
# and so bring in the libdep-b.o object file from the libc.a library.
# Failure to locate the libc.a library, or loading the wrong libc.a library
# will result in an unresolved reference error.
set exec_output [run_host_cmd "$ld" "-plugin $libdep -o libdep.exe libdep-main.o -L libdep-a -la -e 0"]
set exec_output [prune_warnings $exec_output]
set expected_output "got deps for library libdep-a/liba.a: -Llibdep-b -lc"
if ![string match $expected_output $exec_output] then {
fail "$testname: did not get expected output from the linker"
return
}
regsub -all "$expected_output" $exec_output "\\1" exec_output
if {![string match "" $exec_output]} {
fail "$testname: unexpected output from linker: $exec_output"
return
}
pass "$testname"
}
run_test