aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
Diffstat (limited to 'ld')
-rw-r--r--ld/NEWS9
-rw-r--r--ld/config.in3
-rwxr-xr-xld/configure2
-rw-r--r--ld/configure.ac2
-rw-r--r--ld/emulparams/aarch64elf.sh1
-rw-r--r--ld/emulparams/aarch64elf32.sh1
-rw-r--r--ld/emultempl/ppc64elf.em5
-rw-r--r--ld/ld.h37
-rw-r--r--ld/ld.texi80
-rw-r--r--ld/ldlang.c36
-rw-r--r--ld/ldlex.h1
-rw-r--r--ld/ldmain.c385
-rw-r--r--ld/lexsup.c17
-rw-r--r--ld/pe-dll.c1
-rw-r--r--ld/testsuite/ld-elf/sec64k.exp31
-rw-r--r--ld/testsuite/ld-elf/shared.exp14
-rw-r--r--ld/testsuite/ld-scripts/map-address.exp37
-rw-r--r--ld/testsuite/ld-scripts/map-stats.d5
-rw-r--r--ld/testsuite/ld-shared/shared.exp34
-rw-r--r--ld/testsuite/ld-vsb/vsb.exp16
-rw-r--r--ld/testsuite/ld-x86-64/x86-64.exp4
21 files changed, 661 insertions, 60 deletions
diff --git a/ld/NEWS b/ld/NEWS
index 494bb83..7b5e2e4 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,14 @@
-*- text -*-
+* The linker's --stats option can take an optional argument which if used is
+ interpreted as a filename into which resource usage information should be
+ stored. As an alternative mechanism the LD_STATS environment variable can
+ also be used to achieve the same results. Resource usage information for
+ various phases of the linking operation is now included in the report.
+ If a map file is being produced then the information is also included there.
+ The --no-stats option can be used to disable stat reporting, should it have
+ been enabled.
+
* Remove the linker -taso option for Alpha target, as Linux/Alpha kernel
support for 32-bit pointers has been removed.
diff --git a/ld/config.in b/ld/config.in
index 2d7b640..e10c9e7 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -122,6 +122,9 @@
/* Define to 1 if you have the `getpagesize' function. */
#undef HAVE_GETPAGESIZE
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
/* Define if the GNU gettext() function is already present or preinstalled. */
#undef HAVE_GETTEXT
diff --git a/ld/configure b/ld/configure
index b7af25d..3f745ac 100755
--- a/ld/configure
+++ b/ld/configure
@@ -18753,7 +18753,7 @@ fi
done
-for ac_func in close glob lseek mkstemp open realpath waitpid
+for ac_func in close getrusage glob lseek mkstemp open realpath waitpid
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/ld/configure.ac b/ld/configure.ac
index 228f2ee..1ee0c0c 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -414,7 +414,7 @@ AC_SUBST(NATIVE_LIB_DIRS)
AC_CHECK_HEADERS(fcntl.h elf-hints.h limits.h inttypes.h stdint.h \
sys/file.h sys/mman.h sys/param.h sys/stat.h sys/time.h \
sys/types.h unistd.h)
-AC_CHECK_FUNCS(close glob lseek mkstemp open realpath waitpid)
+AC_CHECK_FUNCS(close getrusage glob lseek mkstemp open realpath waitpid)
BFD_BINARY_FOPEN
diff --git a/ld/emulparams/aarch64elf.sh b/ld/emulparams/aarch64elf.sh
index 72616b5..aa051c7 100644
--- a/ld/emulparams/aarch64elf.sh
+++ b/ld/emulparams/aarch64elf.sh
@@ -18,6 +18,7 @@ GENERATE_SHLIB_SCRIPT=yes
GENERATE_PIE_SCRIPT=yes
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
ENTRY=_start
EMBEDDED=yes
diff --git a/ld/emulparams/aarch64elf32.sh b/ld/emulparams/aarch64elf32.sh
index 45bf31a..0565b7a 100644
--- a/ld/emulparams/aarch64elf32.sh
+++ b/ld/emulparams/aarch64elf32.sh
@@ -18,6 +18,7 @@ GENERATE_SHLIB_SCRIPT=yes
GENERATE_PIE_SCRIPT=yes
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
ENTRY=_start
EMBEDDED=yes
diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em
index f7a8f1e..857cf54 100644
--- a/ld/emultempl/ppc64elf.em
+++ b/ld/emultempl/ppc64elf.em
@@ -606,14 +606,15 @@ gld${EMULATION_NAME}_finish (void)
einfo (_("%X%P: can not build stubs: %E\n"));
fflush (stdout);
+ FILE * out = config.stats_file ? config.stats_file : stderr;
for (line = msg; line != NULL; line = endline)
{
endline = strchr (line, '\n');
if (endline != NULL)
*endline++ = '\0';
- fprintf (stderr, "%s: %s\n", program_name, line);
+ fprintf (out, "%s: %s\n", program_name, line);
}
- fflush (stderr);
+ fflush (out);
free (msg);
ldelf_finish ();
diff --git a/ld/ld.h b/ld/ld.h
index 254f0a0..c868815 100644
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -295,6 +295,10 @@ typedef struct
char *map_filename;
FILE *map_file;
+ char *stats_filename;
+ /* If non-NULL then resource use information should be written to this file. */
+ FILE *stats_file;
+
char *dependency_file;
unsigned int split_by_reloc;
@@ -330,6 +334,39 @@ typedef struct
enum compressed_debug_section_type compress_debug;
} ld_config_type;
+/* An enumeration of the linker phases for which resource usage information
+ is recorded. PHASE_ALL is special as it covers the entire link process.
+
+ Instructions for adding a new phase:
+ 1. Add an entry to this enumeration.
+ 2. Add an entry for the phase to the phase_data[] structure in ldmain.c.
+ 3. Add calls to ld_start_phase(PHASE_xxx) and ld_stop_phase(PHASE_xxx)
+ at the appropriate place(s) in the code. It does not matter if the
+ new phase overlaps with or is contained by any other phase.
+
+ Instructions for adding a new resource:
+ 1. If necessary add a new field to the phase_data structure defined in
+ ldmain.c.
+ 2. Add code to initialise the field in ld_main.c:ld_start_phase().
+ 3. Add code to finalise the field in ld_main.c:ld_stop_phase().
+ 4. Add code to report the field in ld_main.c:report_phases(). */
+typedef enum
+{
+ PHASE_ALL = 0,
+ PHASE_CTF,
+ PHASE_MERGE,
+ PHASE_PARSE,
+ PHASE_PLUGINS,
+ PHASE_PROCESS,
+ PHASE_WRITE,
+
+ NUM_PHASES /* This must be the last entry. */
+}
+ld_phase;
+
+extern void ld_start_phase (ld_phase);
+extern void ld_stop_phase (ld_phase);
+
extern ld_config_type config;
extern FILE * saved_script_handle;
diff --git a/ld/ld.texi b/ld/ld.texi
index b85d810..29bd0e1 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -2184,6 +2184,9 @@ Memory region Used Size Region Size %age Used
RAM: 32 B 2 GB 0.00%
@end smallexample
+Note: if you want to find out about the memory usage of the linker
+itself, then the @option{--stats} option will do this.
+
@cindex help
@cindex usage
@kindex --help
@@ -2706,10 +2709,76 @@ more than @var{count} relocations one output section will contain that
many relocations. @var{count} defaults to a value of 32768.
@kindex --stats
-@item --stats
+@item --stats[=@var{filename}]
Compute and display statistics about the operation of the linker, such
as execution time and memory usage.
+If the optional @var{filename} argument is not supplied then only
+basic information is reported, and it is sent to the standard error
+output stream. If the @var{filename} argument is supplied then
+extended information is written to the named file. If @var{filename}
+is set to just the @var{-} symbol, then the extended information is
+sent to the standard output stream. If the @var{filename} starts with
+@var{+} then the file is opened in append mode rather than overwrite
+mode.
+
+If the @option{-Map} option has been enabled then the information is
+also recorded in the map file as well. Note: if both the
+@option{--stats} option and the @option{-Map} options have been given
+@var{filename} arguments and they match, then the information will
+only be written out once not twice.
+
+If the @code{LD_STATS} environment variable is defined then this
+behaves likes the @option{--stats} option. If the variable's value is
+a string then this will used as the name of a file into which the
+information should be recorded. Otherwise the information
+will be sent to the standard output stream. Using the environment
+variable allows stats to be recorded without having to alter the
+linker's command line. Note: if both the environment variable and the
+@option{--stats} option are used then the @option{--stats} option
+takes precedence.
+
+The extended information reported includes the cpu time used and, if
+the @var{getrusage()} system library call is available then memory use
+is recorded as well. This information is reported for individual
+parts of the linking process which are referred to as @emph{phases}.
+In addition the information is also reported for a special phase
+called @emph{ALL} which covers the entire linking process. Note that
+individual phases can contain or overlap with each other so it should
+not be assumed that the overall resources used by the linker is the
+sum of the resources used by the individual phases.
+
+In addition when extended information is being reported the linker
+version, command line arguments and linker start time are also
+included. This makes it easier to handle the situation where multiple
+links are being invoked by a build system and to indentify exactly
+which arguments were responsible for producing the statistics that are
+reported.
+
+The extended output looks something like this:
+
+@smallexample
+Stats: linker version: (GNU Binutils) 2.44.50.20250401
+Stats: linker started: Wed Apr 2 09:36:41 2025
+Stats: args: ld -z norelro -z nomemory-seal -z no-separate-code -o a.out [...]
+
+Stats: phase cpu time memory user time system time
+Stats: name (microsec) (KiB) (seconds) (seconds)
+Stats: ALL 390082 217740 0 0
+Stats: ctf processing 12 0 0 0
+Stats: string merge 1324 0 0 0
+Stats: parsing 349 288 0 0
+Stats: plugins 1 0 0 0
+Stats: processing files 259616 214524 0 0
+Stats: write 116493 0 0 0
+@end smallexample
+
+@kindex --no-stats
+@item --no-stats
+Disables the reporting of usage statistics, should it have been
+enabled via the @option{--stats} command line option or the
+@var{LD_STATS} environment variable.
+
@kindex --sysroot=@var{directory}
@item --sysroot=@var{directory}
Use @var{directory} as the location of the sysroot, overriding the
@@ -4078,6 +4147,15 @@ If the PE/COFF specific @option{--insert-timestamp} is active and the
timestamp value in this variable will be inserted into the COFF header
instead of the current time.
+@kindex LD_STATS
+@cindex LD_STATS
+If the @code{LD_STATS} environment variable is defined then linker
+resource use information will be recorded, just as if the
+@option{--stats} option had been used. If the @code{LD_STATS}
+variable has a string value then this will used as the name of a file
+into which the information should be stored. Otherwise the information
+will be sent to the standard output stream.
+
@c man end
@end ifset
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 0048dfa..0bb9e17 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3807,6 +3807,8 @@ ldlang_open_ctf (void)
int any_ctf = 0;
int err;
+ ld_start_phase (PHASE_CTF);
+
LANG_FOR_EACH_INPUT_STATEMENT (file)
{
asection *sect;
@@ -3844,17 +3846,23 @@ ldlang_open_ctf (void)
if (!any_ctf)
{
ctf_output = NULL;
+ ld_stop_phase (PHASE_CTF);
return;
}
if ((ctf_output = ctf_create (&err)) != NULL)
- return;
+ {
+ ld_stop_phase (PHASE_CTF);
+ return;
+ }
einfo (_("%P: warning: CTF output not created: `%s'\n"),
ctf_errmsg (err));
LANG_FOR_EACH_INPUT_STATEMENT (errfile)
ctf_close (errfile->the_ctf);
+
+ ld_stop_phase (PHASE_CTF);
}
/* Merge together CTF sections. After this, only the symtab-dependent
@@ -3869,6 +3877,8 @@ lang_merge_ctf (void)
if (!ctf_output)
return;
+ ld_start_phase (PHASE_CTF);
+
output_sect = bfd_get_section_by_name (link_info.output_bfd, ".ctf");
/* If the section was discarded, don't waste time merging. */
@@ -3882,6 +3892,8 @@ lang_merge_ctf (void)
ctf_close (file->the_ctf);
file->the_ctf = NULL;
}
+
+ ld_stop_phase (PHASE_CTF);
return;
}
@@ -3924,6 +3936,8 @@ lang_merge_ctf (void)
}
/* Output any lingering errors that didn't come from ctf_link. */
lang_ctf_errs_warnings (ctf_output);
+
+ ld_stop_phase (PHASE_CTF);
}
/* Let the emulation acquire strings from the dynamic strtab to help it optimize
@@ -3932,7 +3946,9 @@ lang_merge_ctf (void)
void
ldlang_ctf_acquire_strings (struct elf_strtab_hash *dynstrtab)
{
+ ld_start_phase (PHASE_CTF);
ldemul_acquire_strings_for_ctf (ctf_output, dynstrtab);
+ ld_stop_phase (PHASE_CTF);
}
/* Inform the emulation about the addition of a new dynamic symbol, in BFD
@@ -3954,16 +3970,24 @@ lang_write_ctf (int late)
if (!ctf_output)
return;
+ ld_start_phase (PHASE_CTF);
+
if (late)
{
/* Emit CTF late if this emulation says it can do so. */
if (ldemul_emit_ctf_early ())
- return;
+ {
+ ld_stop_phase (PHASE_CTF);
+ return;
+ }
}
else
{
if (!ldemul_emit_ctf_early ())
- return;
+ {
+ ld_stop_phase (PHASE_CTF);
+ return;
+ }
}
/* Inform the emulation that all the symbols that will be received have
@@ -3998,6 +4022,8 @@ lang_write_ctf (int late)
LANG_FOR_EACH_INPUT_STATEMENT (file)
file->the_ctf = NULL;
+
+ ld_stop_phase (PHASE_CTF);
}
/* Write out the CTF section late, if the emulation needs that. */
@@ -8547,6 +8573,8 @@ lang_process (void)
{
asection *found;
+ ld_start_phase (PHASE_MERGE);
+
/* Merge SEC_MERGE sections. This has to be done after GC of
sections, so that GCed sections are not merged, but before
assigning dynamic symbols, since removing whole input sections
@@ -8554,6 +8582,8 @@ lang_process (void)
if (!bfd_merge_sections (link_info.output_bfd, &link_info))
fatal (_("%P: bfd_merge_sections failed: %E\n"));
+ ld_stop_phase (PHASE_MERGE);
+
/* Look for a text section and set the readonly attribute in it. */
found = bfd_get_section_by_name (link_info.output_bfd, ".text");
diff --git a/ld/ldlex.h b/ld/ldlex.h
index 999d0de..815da76 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -46,6 +46,7 @@ enum option_values
OPTION_MAP,
OPTION_NO_DEMANGLE,
OPTION_NO_KEEP_MEMORY,
+ OPTION_NO_STATS,
OPTION_NO_WARN_MISMATCH,
OPTION_NO_WARN_SEARCH_MISMATCH,
OPTION_NOINHIBIT_EXEC,
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 54a834e..91237a4 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -21,6 +21,7 @@
#include "sysdep.h"
#include "bfd.h"
+#include "bfdver.h"
#include "safe-ctype.h"
#include "libiberty.h"
#include "bfdlink.h"
@@ -51,6 +52,10 @@
#include <string.h>
+#if defined (HAVE_GETRUSAGE)
+#include <sys/resource.h>
+#endif
+
#ifndef TARGET_SYSTEM_ROOT
#define TARGET_SYSTEM_ROOT ""
#endif
@@ -224,6 +229,10 @@ ld_cleanup (void)
bfd_close_all_done (ibfd);
}
#if BFD_SUPPORTS_PLUGINS
+ /* Note - we do not call ld_plugin_start (PHASE_PLUGINS) here as this
+ function is only called when the linker is exiting - ie after any
+ stats may have been reported, and potentially in the middle of a
+ phase where we have already started recording plugin stats. */
plugin_call_cleanup ();
#endif
if (output_filename && delete_output_file_on_failure)
@@ -270,11 +279,305 @@ display_external_script (void)
free (buf);
}
+struct ld_phase_data
+{
+ const char * name;
+
+ unsigned long start;
+ unsigned long duration;
+
+ bool started;
+ bool broken;
+
+#if defined (HAVE_GETRUSAGE)
+ struct rusage begin;
+ struct rusage use;
+#endif
+};
+
+static struct ld_phase_data phase_data [NUM_PHASES] =
+{
+ [PHASE_ALL] = { .name = "ALL" },
+ [PHASE_CTF] = { .name = "ctf processing" },
+ [PHASE_MERGE] = { .name = "string merge" },
+ [PHASE_PARSE] = { .name = "parsing" },
+ [PHASE_PLUGINS] = { .name = "plugins" },
+ [PHASE_PROCESS] = { .name = "processing files" },
+ [PHASE_WRITE] = { .name = "write" },
+};
+
+void
+ld_start_phase (ld_phase phase)
+{
+ struct ld_phase_data * pd = phase_data + phase;
+
+ /* We record data even if config.stats_file is NULL. This allows
+ us to record data about phases that start before the command line
+ arguments have been parsed. ie PHASE_ALL and PHASE_PARSE. */
+
+ /* Do not overwrite the fields if we have already started recording. */
+ if (pd->started)
+ {
+ /* Since we do not queue phase starts and stops, if a phase is started
+ multiple times there is a likelyhood that it will be stopped multiple
+ times as well. This is problematic as we will only record the data
+ for the first time the phase stops and ignore all of the other stops.
+
+ So let the user know. Ideally real users will never actually see
+ this message, and instead only developers who are adding new phase
+ tracking code will ever encounter it. */
+ einfo ("%P: --stats: phase %s started twice - data may be unreliable\n",
+ pd->name);
+ return;
+ }
+
+ /* It is OK if other phases are also active at this point.
+ It just means that the phases overlap or that one phase is a sub-task
+ of another. Since we record resources on a per-phase basis, this
+ should not matter. */
+
+ pd->started = true;
+ pd->start = get_run_time ();
+
+#if defined (HAVE_GETRUSAGE)
+ /* Record the resource usage at the start of the phase. */
+ struct rusage usage;
+
+ if (getrusage (RUSAGE_SELF, & usage) != 0)
+ /* FIXME: Complain ? */
+ return;
+
+ memcpy (& pd->begin, & usage, sizeof usage);
+#endif
+}
+
+void
+ld_stop_phase (ld_phase phase)
+{
+ struct ld_phase_data * pd = phase_data + phase;
+
+ if (!pd->started)
+ {
+ /* We set the broken flag to indicate that the data
+ recorded for this phase is inconsistent. */
+ pd->broken = true;
+ return;
+ }
+
+ pd->duration += get_run_time () - pd->start;
+ pd->started = false;
+
+#if defined (HAVE_GETRUSAGE)
+ struct rusage usage;
+
+ if (getrusage (RUSAGE_SELF, & usage) != 0)
+ /* FIXME: Complain ? */
+ return;
+
+ if (phase == PHASE_ALL)
+ memcpy (& pd->use, & usage, sizeof usage);
+ else
+ {
+ struct timeval t;
+
+ /* For sub-phases we record the increase in specific fields. */
+ /* FIXME: Most rusage{} fields appear to be irrelevent to when considering
+ linker resource usage. Currently we record maxrss and user and system
+ cpu times. Are there any other fields that might be useful ? */
+
+#ifndef timeradd /* Macros copied from <sys/time.h>. */
+#define timeradd(a, b, result) \
+ do \
+ { \
+ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
+ if ((result)->tv_usec >= 1000000) \
+ { \
+ ++(result)->tv_sec; \
+ (result)->tv_usec -= 1000000; \
+ } \
+ } \
+ while (0)
+#endif
+
+#ifndef timersub
+#define timersub(a, b, result) \
+ do \
+ { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) \
+ { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+ } \
+ while (0)
+#endif
+
+ timersub (& usage.ru_utime, & pd->begin.ru_utime, & t);
+ timeradd (& pd->use.ru_utime, &t, & pd->use.ru_utime);
+
+ timersub (& usage.ru_stime, & pd->begin.ru_stime, & t);
+ timeradd (& pd->use.ru_stime, &t, & pd->use.ru_stime);
+
+ if (pd->begin.ru_maxrss < usage.ru_maxrss)
+ pd->use.ru_maxrss += usage.ru_maxrss - pd->begin.ru_maxrss;
+#endif
+ }
+}
+
+static void
+report_phases (FILE * file, time_t * start, char ** argv)
+{
+ unsigned long i;
+
+ if (file == NULL)
+ return;
+
+ /* We might be writing to stdout, so make sure
+ that we do not have any pending error output. */
+ fflush (stderr);
+
+ /* We do not translate "Stats" as we provide this as a key
+ word that can be searched for by grep and the like. */
+#define STATS_PREFIX "Stats: "
+
+ fprintf (file, STATS_PREFIX "linker version: %s\n", BFD_VERSION_STRING);
+
+ /* No \n at the end of the string as ctime() provides its own. */
+ fprintf (file, STATS_PREFIX "linker started: %s", ctime (start));
+
+ /* We include the linker command line arguments since
+ they can be hard to track down by other means. */
+ if (argv != NULL)
+ {
+ fprintf (file, STATS_PREFIX "args: ");
+ for (i = 0; argv[i] != NULL; i++)
+ fprintf (file, "%s ", argv[i]);
+ fprintf (file, "\n\n"); /* Blank line to separate the args from the stats. */
+ }
+
+ /* All of this song and dance with the column_info struct and printf
+ formatting is so that we can have a nicely formated table with regular
+ column spacing, whilst allowing for the column headers to be translated,
+ and coping nicely with extra long strings or numbers. */
+ struct column_info
+ {
+ const char * header;
+ const char * sub_header;
+ int width;
+ int pad;
+ } columns[] =
+#define COLUMNS_FIELD(HEADER,SUBHEADER) \
+ { .header = N_( HEADER ), .sub_header = N_( SUBHEADER ) },
+ {
+ COLUMNS_FIELD ("phase", "name")
+ COLUMNS_FIELD ("cpu time", "(microsec)")
+#if defined (HAVE_GETRUSAGE)
+ /* Note: keep these columns in sync with the
+ information recorded in ld_stop_phase(). */
+ COLUMNS_FIELD ("memory", "(KiB)")
+ COLUMNS_FIELD ("user time", "(seconds)")
+ COLUMNS_FIELD ("system time", "(seconds)")
+#endif
+ };
+
+#ifndef max
+#define max(A,B) ((A) < (B) ? (B) : (A))
+#endif
+
+ size_t maxwidth = 1;
+ for (i = 0; i < NUM_PHASES; i++)
+ maxwidth = max (maxwidth, strlen (phase_data[i].name));
+
+ fprintf (file, "%s", STATS_PREFIX);
+
+ for (i = 0; i < ARRAY_SIZE (columns); i++)
+ {
+ int padding;
+
+ if (i == 0)
+ columns[i].width = fprintf (file, "%-*s", (int) maxwidth, columns[i].header);
+ else
+ columns[i].width = fprintf (file, "%s", columns[i].header);
+ padding = columns[i].width % 8;
+ if (padding < 4)
+ padding = 4;
+ columns[i].pad = fprintf (file, "%*c", padding, ' ');
+ }
+
+ fprintf (file, "\n");
+
+ int bias = 0;
+#define COLUMN_ENTRY(VAL, FORMAT, N) \
+ do \
+ { \
+ int l; \
+ \
+ if (N == 0) \
+ l = fprintf (file, "%-*" FORMAT, columns[N].width, VAL); \
+ else \
+ l = fprintf (file, "%*" FORMAT, columns[N].width - bias, VAL); \
+ bias = 0; \
+ if (l < columns[N].width) \
+ l = columns[N].pad; \
+ else if (l < columns[N].width + columns[N].pad) \
+ l = columns[N].pad - (l - columns[N].width); \
+ else \
+ { \
+ bias = l - (columns[N].width + columns[N].pad); \
+ l = 0; \
+ } \
+ if (l) \
+ fprintf (file, "%*c", l, ' '); \
+ } \
+ while (0)
+
+ fprintf (file, "%s", STATS_PREFIX);
+
+ for (i = 0; i < ARRAY_SIZE (columns); i++)
+ COLUMN_ENTRY (columns[i].sub_header, "s", i);
+
+ fprintf (file, "\n");
+
+ for (i = 0; i < NUM_PHASES; i++)
+ {
+ struct ld_phase_data * pd = phase_data + i;
+ /* This should not be needed... */
+ const char * name = pd->name ? pd->name : "<unnamed>";
+
+ if (pd->broken)
+ {
+ fprintf (file, "%s %s: %s",
+ STATS_PREFIX, name, _("WARNING: Data is unreliable!\n"));
+ continue;
+ }
+
+ fprintf (file, "%s", STATS_PREFIX);
+
+ /* Care must be taken to keep the lines below in sync with
+ entries in the columns_info array.
+ FIXME: There ought to be a better way to do this... */
+ COLUMN_ENTRY (name, "s", 0);
+ COLUMN_ENTRY (pd->duration, "ld", 1);
+#if defined (HAVE_GETRUSAGE)
+ COLUMN_ENTRY (pd->use.ru_maxrss, "ld", 2);
+ COLUMN_ENTRY (pd->use.ru_utime.tv_sec, "ld", 3);
+ COLUMN_ENTRY (pd->use.ru_stime.tv_sec, "ld", 4);
+#endif
+ fprintf (file, "\n");
+ }
+
+ fflush (file);
+}
+
int
main (int argc, char **argv)
{
char *emulation;
long start_time = get_run_time ();
+ time_t start_seconds = time (NULL);
#ifdef HAVE_LC_MESSAGES
setlocale (LC_MESSAGES, "");
@@ -286,7 +589,23 @@ main (int argc, char **argv)
program_name = argv[0];
xmalloc_set_program_name (program_name);
+ /* Check the LD_STATS environment variable before parsing the command line
+ so that the --stats option, if used, can override the environment variable. */
+ char * stats_filename;
+ if ((stats_filename = getenv ("LD_STATS")) != NULL)
+ {
+ if (ISPRINT (stats_filename[0]))
+ config.stats_filename = stats_filename;
+ else
+ config.stats_filename = "-";
+ config.stats = true;
+ }
+
+ ld_start_phase (PHASE_ALL);
+ ld_start_phase (PHASE_PARSE);
+
expandargv (&argc, &argv);
+ char ** saved_argv = dupargv (argv);
if (bfd_init () != BFD_INIT_MAGIC)
fatal (_("%P: fatal error: libbfd ABI mismatch\n"));
@@ -404,11 +723,17 @@ main (int argc, char **argv)
if (config.hash_table_size != 0)
bfd_hash_set_default_size (config.hash_table_size);
+ ld_stop_phase (PHASE_PARSE);
+
#if BFD_SUPPORTS_PLUGINS
+ ld_start_phase (PHASE_PLUGINS);
/* Now all the plugin arguments have been gathered, we can load them. */
plugin_load_plugins ();
+ ld_stop_phase (PHASE_PLUGINS);
#endif /* BFD_SUPPORTS_PLUGINS */
+ ld_start_phase (PHASE_PARSE);
+
ldemul_set_symbols ();
/* If we have not already opened and parsed a linker script,
@@ -531,7 +856,31 @@ main (int argc, char **argv)
link_info.has_map_file = true;
}
+ if (config.stats_filename != NULL)
+ {
+ if (config.map_filename != NULL
+ && strcmp (config.stats_filename, config.map_filename) == 0)
+ config.stats_file = NULL;
+ else if (strcmp (config.stats_filename, "-") == 0)
+ config.stats_file = stdout;
+ else
+ {
+ if (config.stats_filename[0] == '+')
+ config.stats_file = fopen (config.stats_filename + 1, "a");
+ else
+ config.stats_file = fopen (config.stats_filename, "w");
+
+ if (config.stats_file == NULL)
+ einfo ("%P: Warning: failed to open resource record file: %s\n",
+ config.stats_filename);
+ }
+ }
+
+ ld_stop_phase (PHASE_PARSE);
+
+ ld_start_phase (PHASE_PROCESS);
lang_process ();
+ ld_stop_phase (PHASE_PROCESS);
/* Print error messages for any missing symbols, for any warning
symbols, and possibly multiple definitions. */
@@ -558,7 +907,11 @@ main (int argc, char **argv)
link_info.output_bfd->flags
|= flags & bfd_applicable_file_flags (link_info.output_bfd);
+
+ ld_start_phase (PHASE_WRITE);
ldwrite ();
+ ld_stop_phase (PHASE_WRITE);
+
if (config.map_file != NULL)
lang_map ();
@@ -653,19 +1006,38 @@ main (int argc, char **argv)
if (config.emit_gnu_object_only)
cmdline_emit_object_only_section ();
+ ld_stop_phase (PHASE_ALL);
+
if (config.stats)
{
- long run_time = get_run_time () - start_time;
+ report_phases (config.map_file, & start_seconds, saved_argv);
+
+ if (config.stats_filename)
+ {
+ report_phases (config.stats_file, & start_seconds, saved_argv);
+
+ if (config.stats_file != stdout && config.stats_file != stderr)
+ {
+ fclose (config.stats_file);
+ config.stats_file = NULL;
+ }
+ }
+ else /* This is for backwards compatibility. */
+ {
+ long run_time = get_run_time () - start_time;
- fflush (stdout);
- fprintf (stderr, _("%s: total time in link: %ld.%06ld\n"),
- program_name, run_time / 1000000, run_time % 1000000);
- fflush (stderr);
+ fflush (stdout);
+ fprintf (stderr, _("%s: total time in link: %ld.%06ld\n"),
+ program_name, run_time / 1000000, run_time % 1000000);
+ fflush (stderr);
+ }
}
/* Prevent ld_cleanup from deleting the output file. */
output_filename = NULL;
+ freeargv (saved_argv);
+
xexit (0);
return 0;
}
@@ -942,8 +1314,11 @@ add_archive_element (struct bfd_link_info *info,
&& (!no_more_claiming
|| bfd_get_lto_type (abfd) != lto_fat_ir_object))
{
+ ld_start_phase (PHASE_PLUGINS);
/* We must offer this archive member to the plugins to claim. */
plugin_maybe_claim (input);
+ ld_stop_phase (PHASE_PLUGINS);
+
if (input->flags.claimed)
{
if (no_more_claiming)
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 7de6e25..bde2046 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -499,8 +499,10 @@ static const struct ld_option ld_options[] =
{ {"split-by-reloc", optional_argument, NULL, OPTION_SPLIT_BY_RELOC},
'\0', N_("[=COUNT]"), N_("Split output sections every COUNT relocs"),
TWO_DASHES },
- { {"stats", no_argument, NULL, OPTION_STATS},
- '\0', NULL, N_("Print memory usage statistics"), TWO_DASHES },
+ { {"stats", optional_argument, NULL, OPTION_STATS},
+ '\0', NULL, N_("Print resource usage statistics"), TWO_DASHES },
+ { {"no-stats", optional_argument, NULL, OPTION_NO_STATS},
+ '\0', NULL, N_("Do not print resource usage statistics"), TWO_DASHES },
{ {"target-help", no_argument, NULL, OPTION_TARGET_HELP},
'\0', NULL, N_("Display target specific options"), TWO_DASHES },
{ {"task-link", required_argument, NULL, OPTION_TASK_LINK},
@@ -1412,6 +1414,17 @@ parse_args (unsigned argc, char **argv)
break;
case OPTION_STATS:
config.stats = true;
+ if (optarg)
+ config.stats_filename = optarg;
+ else
+ {
+ config.stats_filename = NULL;
+ config.stats_file = stderr;
+ }
+ break;
+ case OPTION_NO_STATS:
+ config.stats = false;
+ config.stats_filename = NULL;
break;
case OPTION_NO_SYMBOLIC:
opt_symbolic = symbolic_unset;
diff --git a/ld/pe-dll.c b/ld/pe-dll.c
index 4e72f1b..de1cfaf 100644
--- a/ld/pe-dll.c
+++ b/ld/pe-dll.c
@@ -381,6 +381,7 @@ static const autofilter_entry_type autofilter_liblist[] =
{ STRING_COMMA_LEN ("libmsvcrt") },
{ STRING_COMMA_LEN ("libmsvcrt-os") },
{ STRING_COMMA_LEN ("libucrt") },
+ { STRING_COMMA_LEN ("libucrtapp") },
{ STRING_COMMA_LEN ("libucrtbase") },
{ STRING_COMMA_LEN ("libpthread") },
{ STRING_COMMA_LEN ("libwinpthread") },
diff --git a/ld/testsuite/ld-elf/sec64k.exp b/ld/testsuite/ld-elf/sec64k.exp
index 8dcb021..deb46d3 100644
--- a/ld/testsuite/ld-elf/sec64k.exp
+++ b/ld/testsuite/ld-elf/sec64k.exp
@@ -168,9 +168,9 @@ if [catch { set ofd [open "tmpdir/$test2.d" w] } x] {
return
}
-# too big for avr, d10v and msp
-# lack of fancy orphan section handling causes overlap on fr30 and iq2000
-# bfin and lm32 complain about relocations in read-only sections
+# Too big for avr, d10v and msp.
+# Lack of fancy orphan section handling causes overlap on fr30 and iq2000.
+# bfin and lm32 complain about relocations in read-only sections.
if { ![istarget "d10v-*-*"]
&& ![istarget "avr-*-*"]
&& ![istarget "msp*-*-*"]
@@ -179,7 +179,13 @@ if { ![istarget "d10v-*-*"]
&& ![istarget "bfin-*-linux*"]
&& ![istarget "lm32-*-linux*"]
&& ![istarget "pru-*-*"] } {
+
+ # Create a 64ksec.d test control file...
+
+ # List the input files.
foreach sfile $sfiles { puts $ofd "#source: $sfile" }
+
+ # Add any needed linker command line options.
if { [istarget spu*-*-*] } {
puts $ofd "#ld: --local-store 0:0"
} elseif { [istarget "i?86-*-linux*"] || [istarget "x86_64-*-linux*"] } {
@@ -187,10 +193,20 @@ if { ![istarget "d10v-*-*"]
} else {
puts $ofd "#ld:"
}
- #force z80 target to compile for eZ80 in ADL mode
+
+ # Enable the accumulation of internal linker statistics in a separate file.
+ # Enabled this way as you cannot have multiple #ld: options in a .d file.
+ # The + character causes the file to opened in append mode, so that multiple
+ # runs of this test will accumulate data over time. Thus allowing regular
+ # testers to see changes in the performance of the linker.
+ puts $ofd "#ld_after_inputfiles: --stats=+tmpdir/$test2.stats"
+
+ # Force z80 target to compile for eZ80 in ADL mode.
if { [istarget "z80-*-*"] } then {
puts $ofd "#as: -ez80-adl"
}
+
+ # Add a test of the linked binary.
puts $ofd "#readelf: -W -wN -Ss"
puts $ofd "There are 660.. section headers.*:"
puts $ofd "#..."
@@ -199,6 +215,7 @@ if { ![istarget "d10v-*-*"]
puts $ofd " \\\[65279\\\] \\.foo\\.\[0-9\]+ .*"
puts $ofd " \\\[65280\\\] \\.foo\\.\[0-9\]+ .*"
puts $ofd "#..."
+
if { [is_elf_unused_section_symbols ] } {
puts $ofd " 660..: \[0-9a-f\]+\[ \]+0\[ \]+SECTION\[ \]+LOCAL\[ \]+DEFAULT\[ \]+660...*"
puts $ofd "#..."
@@ -209,6 +226,7 @@ if { ![istarget "d10v-*-*"]
puts $ofd " 66...: \[0-9a-f\]+\[ \]+0\[ \]+NOTYPE\[ \]+LOCAL\[ \]+DEFAULT\[ \]+660.. bar_66000$"
}
puts $ofd "#..."
+
# Global symbols are not in "alphanumeric" order, so we just check
# that the first and the last are present in any order (assuming no
# duplicates).
@@ -217,9 +235,14 @@ if { ![istarget "d10v-*-*"]
puts $ofd ".* (\[0-9\] foo_1|66... foo_66000)$"
puts $ofd "#pass"
close $ofd
+
+ # Now run the constructed test file.
run_dump_test "tmpdir/$test2"
+
+ # Leave the test file around in case the user wants to examine it.
}
+# Tidy up.
for { set i 1 } { $i < $max_sec / $secs_per_file } { incr i } {
catch "exec rm -f tmpdir/dump$i.o" status
}
diff --git a/ld/testsuite/ld-elf/shared.exp b/ld/testsuite/ld-elf/shared.exp
index bf8952a..09669b5 100644
--- a/ld/testsuite/ld-elf/shared.exp
+++ b/ld/testsuite/ld-elf/shared.exp
@@ -1618,12 +1618,12 @@ if { [istarget *-*-linux*]
] \
[list \
"Run pr21964-4" \
- "" \
+ "$NOPIE_LDFLAGS" \
"" \
{pr21964-4.c} \
"pr21964-4" \
"pass.out" \
- "" \
+ "$NOPIE_CFLAGS" \
"" \
"" \
"-ldl" \
@@ -1664,7 +1664,7 @@ proc mix_pic_and_non_pic {xfails cflags ldflags exe} {
run_ld_link_exec_tests [list \
[list \
- "Run $exe fun defined" \
+ "Run $exe fun undefined" \
"-Wl,--no-as-needed,-rpath,tmpdir $ldflags tmpdir/libpr19719b.o tmpdir/libpr19719.so" \
"" \
{ pr19719a.c pr19719c.c } \
@@ -1682,19 +1682,19 @@ proc mix_pic_and_non_pic {xfails cflags ldflags exe} {
}
if ![isnative] {
- unsupported "Run $exe fun undefined"
+ unsupported "Run $exe fun defined"
return
}
set exec_output [run_host_cmd "tmpdir/$exe" ""]
if {![string match "PASS\n" $exec_output]} {
- fail "Run $exe fun undefined"
+ fail "Run $exe fun defined"
} else {
- pass "Run $exe fun undefined"
+ pass "Run $exe fun defined"
}
}
-mix_pic_and_non_pic [list "arm*-*-*"] "" "" "pr19719"
+mix_pic_and_non_pic [list "arm*-*-*"] "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" "pr19719"
mix_pic_and_non_pic [] "-fPIE" "-pie" "pr19719pie"
set AFLAGS_PIE ""
diff --git a/ld/testsuite/ld-scripts/map-address.exp b/ld/testsuite/ld-scripts/map-address.exp
index 2291302..776fed4 100644
--- a/ld/testsuite/ld-scripts/map-address.exp
+++ b/ld/testsuite/ld-scripts/map-address.exp
@@ -130,19 +130,38 @@ if { [is_elf_format] } {
$IMAGE_BASE tmpdir/map-address.o \
-Map=tmpdir/map-locals.map --print-map-locals"]} {
fail $testname
- return
- }
- if [is_remote host] then {
- remote_upload host "tmpdir/map-locals.map"
- }
+ } else {
- # Some ELF targets do not preserve their local symbols.
- setup_xfail "d30v-*-*" "dlx-*-*" "pj-*-*" "s12z-*-*" "xgate-*-*"
+ if [is_remote host] then {
+ remote_upload host "tmpdir/map-locals.map"
+ }
+
+ # Some ELF targets do not preserve their local symbols.
+ setup_xfail "d30v-*-*" "dlx-*-*" "pj-*-*" "s12z-*-*" "xgate-*-*"
+ if {[regexp_diff \
+ "tmpdir/map-locals.map" \
+ "$srcdir/$subdir/map-locals.d"]} {
+ fail $testname
+ } else {
+ pass $testname
+ }
+ }
+}
+
+set testname "map with resource usage"
+
+if {![ld_link $ld tmpdir/map-address \
+ "$LDFLAGS -T $srcdir/$subdir/map-address.t \
+ $IMAGE_BASE tmpdir/map-address.o \
+ -Map=tmpdir/map-locals.map \
+ --stats=tmpdir/map-stats.map"]} {
+ fail $testname
+} else {
if {[regexp_diff \
- "tmpdir/map-locals.map" \
- "$srcdir/$subdir/map-locals.d"]} {
+ "tmpdir/map-stats.map" \
+ "$srcdir/$subdir/map-stats.d"]} {
fail $testname
} else {
pass $testname
diff --git a/ld/testsuite/ld-scripts/map-stats.d b/ld/testsuite/ld-scripts/map-stats.d
new file mode 100644
index 0000000..ba9adf8
--- /dev/null
+++ b/ld/testsuite/ld-scripts/map-stats.d
@@ -0,0 +1,5 @@
+#...
+Stats: phase.*
+Stats: name.*
+Stats: ALL.*
+#pass
diff --git a/ld/testsuite/ld-shared/shared.exp b/ld/testsuite/ld-shared/shared.exp
index bdbe9a9..a8ddac2 100644
--- a/ld/testsuite/ld-shared/shared.exp
+++ b/ld/testsuite/ld-shared/shared.exp
@@ -121,6 +121,7 @@ proc shared_test { progname testname main sh1 sh2 dat args } {
global tmpdir
if [llength $args] { set shldflags [lindex $args 0] } else { set shldflags "" }
+ if { [llength $args] >= 2 } { set ldflags [lindex $args 1] } else { set ldflags "" }
# Build the shared library.
set shared -shared
@@ -146,7 +147,7 @@ proc shared_test { progname testname main sh1 sh2 dat args } {
set rpath /lib:$tmpdir
set exportflag " -Wl,-bexpall"
}
- if ![ld_link $CC_FOR_TARGET $tmpdir/$progname "-Wl,-rpath,$rpath $tmpdir/$main $tmpdir/$progname.so $exportflag"] {
+ if ![ld_link $CC_FOR_TARGET $tmpdir/$progname "-Wl,-rpath,$rpath $ldflags $tmpdir/$main $tmpdir/$progname.so $exportflag"] {
fail "$testname"
return
}
@@ -205,7 +206,9 @@ if { [istarget mips*-*-*] && ! [at_least_gcc_version 4 3] } then {
verbose "Using $picflag to compile PIC code"
# Compile the main program.
-if ![ld_compile "$CC_FOR_TARGET $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.o] {
+global PLT_CFLAGS NOPIE_CFLAGS NOPIE_LDFLAGS
+verbose "Using $NOPIE_CFLAGS to compile and $NOPIE_LDFLAGS to link non PIC code"
+if ![ld_compile "$CC_FOR_TARGET $NOPIE_CFLAGS $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.o] {
unsupported "shared (non PIC)"
unsupported "shared"
} else {
@@ -215,12 +218,11 @@ if ![ld_compile "$CC_FOR_TARGET $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.
# will need to do more relocation work. However, note that not
# using -fpic will cause some of the tests to return different
# results. Make sure that PLT is used since PLT is expected.
- global PLT_CFLAGS NOPIE_CFLAGS
if { ![ld_compile "$CC_FOR_TARGET $PLT_CFLAGS $NOPIE_CFLAGS $SHCFLAG" $srcdir/$subdir/sh1.c $tmpdir/sh1np.o]
- || ![ld_compile "$CC_FOR_TARGET $PLT_CFLAGS $SHCFLAG" $srcdir/$subdir/sh2.c $tmpdir/sh2np.o] } {
+ || ![ld_compile "$CC_FOR_TARGET $PLT_CFLAGS $NOPIE_CFLAGS $SHCFLAG" $srcdir/$subdir/sh2.c $tmpdir/sh2np.o] } {
unsupported "shared (non PIC)"
} else { if { [is_xcoff_format] } {
- shared_test shnp "shared (nonPIC)" mainnp.o sh1np.o sh2np.o xcoff
+ shared_test shnp "shared (non PIC)" mainnp.o sh1np.o sh2np.o xcoff "" $NOPIE_LDFLAGS
} else {
# Solaris defaults to -z text.
setup_xfail "*-*-solaris2*"
@@ -243,7 +245,7 @@ if ![ld_compile "$CC_FOR_TARGET $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.
setup_xfail "arm*-*-linux*"
}
setup_xfail "aarch64*-*-linux*"
- shared_test shnp "shared (non PIC)" mainnp.o sh1np.o sh2np.o shared
+ shared_test shnp "shared (non PIC)" mainnp.o sh1np.o sh2np.o shared "" $NOPIE_LDFLAGS
# Test ELF shared library relocations with a non-zero load
# address for the library. Near as I can tell, the R_*_RELATIVE
@@ -273,7 +275,7 @@ if ![ld_compile "$CC_FOR_TARGET $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.
setup_xfail "*-*-solaris2*"
shared_test shnp "shared (non PIC, load offset)" \
mainnp.o sh1np.o sh2np.o shared \
- "-Wl,-T,$srcdir/$subdir/elf-offset.ld,--hash-style=sysv"
+ "-Wl,-T,$srcdir/$subdir/elf-offset.ld,--hash-style=sysv" $NOPIE_LDFLAGS
} }
# Now compile the code using -fpic.
@@ -283,13 +285,13 @@ if ![ld_compile "$CC_FOR_TARGET $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.
unsupported "shared"
} else {
if { [is_xcoff_format] } {
- shared_test shp "shared" mainnp.o sh1p.o sh2p.o xcoff
+ shared_test shp "shared" mainnp.o sh1p.o sh2p.o xcoff "" $NOPIE_LDFLAGS
} else {
- shared_test shp "shared" mainnp.o sh1p.o sh2p.o shared
- ld_compile "$CC_FOR_TARGET -DSYMBOLIC_TEST $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.o
+ shared_test shp "shared" mainnp.o sh1p.o sh2p.o shared "" $NOPIE_LDFLAGS
+ ld_compile "$CC_FOR_TARGET $NOPIE_CFLAGS -DSYMBOLIC_TEST $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.o
ld_compile "$CC_FOR_TARGET -DSYMBOLIC_TEST $SHCFLAG $picflag" $srcdir/$subdir/sh1.c $tmpdir/sh1p.o
- shared_test shp "shared -Bsymbolic" mainnp.o sh1p.o sh2p.o symbolic "-Bsymbolic"
- ld_compile "$CC_FOR_TARGET $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.o
+ shared_test shp "shared -Bsymbolic" mainnp.o sh1p.o sh2p.o symbolic "-Bsymbolic" $NOPIE_LDFLAGS
+ ld_compile "$CC_FOR_TARGET $NOPIE_CFLAGS $SHCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.o
ld_compile "$CC_FOR_TARGET $SHCFLAG $picflag" $srcdir/$subdir/sh1.c $tmpdir/sh1p.o
}
}
@@ -302,7 +304,7 @@ if ![ld_compile "$CC_FOR_TARGET $SHCFLAG $picflag" $srcdir/$subdir/main.c $tmpdi
} else {
if { [file exists $tmpdir/sh1np.o ] && [ file exists $tmpdir/sh2np.o ] } {
if { [is_xcoff_format] } {
- shared_test shmpnp "shared (PIC main, non PIC so)" mainp.o sh1np.o sh2np.o xcoff
+ shared_test shmpnp "shared (PIC main, non PIC so)" mainp.o sh1np.o sh2np.o xcoff "" $NOPIE_LDFLAGS
} else {
# Solaris defaults to -z text.
setup_xfail "*-*-solaris2*"
@@ -325,7 +327,7 @@ if ![ld_compile "$CC_FOR_TARGET $SHCFLAG $picflag" $srcdir/$subdir/main.c $tmpdi
setup_xfail "arm*-*-linux*"
}
setup_xfail "aarch64*-*-linux*"
- shared_test shmpnp "shared (PIC main, non PIC so)" mainp.o sh1np.o sh2np.o shared
+ shared_test shmpnp "shared (PIC main, non PIC so)" mainp.o sh1np.o sh2np.o shared "" $NOPIE_LDFLAGS
}
} else {
unsupported "shared (PIC main, non PIC so)"
@@ -333,9 +335,9 @@ if ![ld_compile "$CC_FOR_TARGET $SHCFLAG $picflag" $srcdir/$subdir/main.c $tmpdi
if { [file exists $tmpdir/sh1p.o ] && [ file exists $tmpdir/sh2p.o ] } {
if { [is_xcoff_format] } {
- shared_test shmpp "shared (PIC main)" mainp.o sh1p.o sh2p.o xcoff
+ shared_test shmpp "shared (PIC main)" mainp.o sh1p.o sh2p.o xcoff "" $NOPIE_LDFLAGS
} else {
- shared_test shmpp "shared (PIC main)" mainp.o sh1p.o sh2p.o shared
+ shared_test shmpp "shared (PIC main)" mainp.o sh1p.o sh2p.o shared "" $NOPIE_LDFLAGS
}
} else {
unsupported "shared (PIC main)"
diff --git a/ld/testsuite/ld-vsb/vsb.exp b/ld/testsuite/ld-vsb/vsb.exp
index 9a61e9d..e44ac39 100644
--- a/ld/testsuite/ld-vsb/vsb.exp
+++ b/ld/testsuite/ld-vsb/vsb.exp
@@ -134,6 +134,7 @@ proc visibility_test { visibility progname testname main sh1 sh2 dat args } {
global tmpdir
if [llength $args] { set shldflags [lindex $args 0] } else { set shldflags "" }
+ if { [llength $args] >= 2 } { set ldflags [lindex $args 1] } else { set ldflags "" }
# Build the shared library.
set shared -shared
@@ -169,7 +170,7 @@ proc visibility_test { visibility progname testname main sh1 sh2 dat args } {
set rpath /lib:$tmpdir
set exportflag " -Wl,-bexpall"
}
- if ![ld_link $CC_FOR_TARGET $tmpdir/$progname "-Wl,-rpath,$rpath $tmpdir/$main $tmpdir/$progname.so $exportflag"] {
+ if ![ld_link $CC_FOR_TARGET $tmpdir/$progname "-Wl,-rpath,$rpath $ldflags $tmpdir/$main $tmpdir/$progname.so $exportflag"] {
if { [ string match $visibility "hidden" ]
&& [regexp "undefined reference to \`\.?visibility\'" $link_output]
&& [regexp "undefined reference to \`visibility_var\'" $link_output] } {
@@ -235,6 +236,7 @@ proc visibility_run {visibility} {
global shared_needs_pic
global PLT_CFLAGS
global NOPIE_CFLAGS
+ global NOPIE_LDFLAGS
global COMPRESS_LDFLAG
global NOSANITIZE_CFLAGS
global NOLTO_CFLAGS
@@ -284,7 +286,7 @@ proc visibility_run {visibility} {
} else {
# Compile the main program. Make sure that PLT is used since PLT
# is expected.
- if ![ld_compile "$CC_FOR_TARGET -g $PLT_CFLAGS $SHCFLAG $VSBCFLAG $NOSANITIZE_CFLAGS $NOLTO_CFLAGS" $srcdir/$subdir/main.c $tmpdir/mainnp.o] {
+ if ![ld_compile "$CC_FOR_TARGET -g $NOPIE_CFLAGS $PLT_CFLAGS $SHCFLAG $VSBCFLAG $NOSANITIZE_CFLAGS $NOLTO_CFLAGS" $srcdir/$subdir/main.c $tmpdir/mainnp.o] {
unsupported "visibility ($visibility) (non PIC)"
unsupported "visibility ($visibility)"
} else {
@@ -343,7 +345,7 @@ proc visibility_run {visibility} {
setup_xfail "*-*-beos*"
}
- visibility_test $visibility vnp "visibility ($visibility) (non PIC)" mainnp.o sh1np.o sh2np.o $datfile
+ visibility_test $visibility vnp "visibility ($visibility) (non PIC)" mainnp.o sh1np.o sh2np.o $datfile "" $NOPIE_LDFLAGS
# Test ELF shared library relocations with a non-zero load
# address for the library. Near as I can tell, the R_*_RELATIVE
@@ -395,7 +397,7 @@ proc visibility_run {visibility} {
if { ![is_xcoff_format] } {
visibility_test $visibility vnp "visibility ($visibility) (non PIC, load offset)" \
mainnp.o sh1np.o sh2np.o $datfile \
- "-Wl,-T,$srcdir/$subdir/elf-offset.ld,--hash-style=sysv"
+ "-Wl,-T,$srcdir/$subdir/elf-offset.ld,--hash-style=sysv" $NOPIE_LDFLAGS
}
}
@@ -411,7 +413,7 @@ proc visibility_run {visibility} {
setup_xfail $target_triplet
}
}
- visibility_test $visibility vp "visibility ($visibility)" mainnp.o sh1p.o sh2p.o $datfile $COMPRESS_LDFLAG
+ visibility_test $visibility vp "visibility ($visibility)" mainnp.o sh1p.o sh2p.o $datfile $COMPRESS_LDFLAG $NOPIE_LDFLAGS
}
}}
@@ -466,7 +468,7 @@ proc visibility_run {visibility} {
setup_xfail "*-*-beos*"
}
- visibility_test $visibility vmpnp "visibility ($visibility) (PIC main, non PIC so)" mainp.o sh1np.o sh2np.o $datfile
+ visibility_test $visibility vmpnp "visibility ($visibility) (PIC main, non PIC so)" mainp.o sh1np.o sh2np.o $datfile "" $NOPIE_LDFLAGS
} else {
unsupported "visibility (PIC main, non PIC so)"
}
@@ -488,7 +490,7 @@ proc visibility_run {visibility} {
setup_xfail "*-*-beos*"
}
- visibility_test $visibility vmpp "visibility ($visibility) (PIC main)" mainp.o sh1p.o sh2p.o $datfile
+ visibility_test $visibility vmpp "visibility ($visibility) (PIC main)" mainp.o sh1p.o sh2p.o $datfile "" $NOPIE_LDFLAGS
} else {
unsupported "visibility ($visibility) (PIC main)"
}
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index 01d6459..52c4d5e 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -2168,9 +2168,9 @@ if { [isnative] && [check_compiler_available] } {
}
undefined_weak "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS"
- undefined_weak "-fPIE" ""
+ undefined_weak "-fPIE" "$NOPIE_LDFLAGS"
undefined_weak "-fPIE" "-pie"
- undefined_weak "-fPIE" "-Wl,-z,nodynamic-undefined-weak"
+ undefined_weak "-fPIE" "$NOPIE_LDFLAGS -Wl,-z,nodynamic-undefined-weak"
undefined_weak "-fPIE" "-pie -Wl,-z,nodynamic-undefined-weak"
}