From 23ae20f5e3afeeab9aa616c63ab3b357668476d5 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 16 Oct 2020 11:37:26 +0100 Subject: [PATCH] Add a new option to the linker: --error-handling-script=. Run the script if an undefined symbol or unfound library error is encountered. PR 26626 * ldmain.c (undefined_symbol): If an error handlign script is available, call it. * ldfile.c (error_handling_script): Declare. (ldfile_open_file): If a library cannot be found and an error handling script is available, call it. * ldmain.h (error_handling_script): Prototype. * ldlex.h (OPTION_ERROR_HANDLING_SCRIPT): Define. * lexsup.c (ld_options): Add --error-handling-script. (parse_args): Add support for --errror-handling-script. * ld.texi: Document the new feature. * configure.ac: Add --error-handling-script option to disable support for the new feature. * NEWS: Mention the new feature. * config.in: Regenerate. * configure: Regenerate. --- ld/ChangeLog | 19 +++++++++++++++++++ ld/NEWS | 5 +++++ ld/config.in | 4 ++++ ld/configure | 28 ++++++++++++++++++++++++++-- ld/configure.ac | 17 +++++++++++++++++ ld/ld.texi | 15 +++++++++++++++ ld/ldfile.c | 34 ++++++++++++++++++++++++++++++++++ ld/ldlex.h | 3 +++ ld/ldmain.c | 38 ++++++++++++++++++++++++++++++++++++++ ld/ldmain.h | 3 +++ ld/lexsup.c | 14 ++++++++++++++ 11 files changed, 178 insertions(+), 2 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index 780bb4b595..18dc37bdd8 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,22 @@ +2020-10-16 Nick Clifton + + PR 26626 + * ldmain.c (undefined_symbol): If an error handlign script is + available, call it. + * ldfile.c (error_handling_script): Declare. + (ldfile_open_file): If a library cannot be found and an error + handling script is available, call it. + * ldmain.h (error_handling_script): Prototype. + * ldlex.h (OPTION_ERROR_HANDLING_SCRIPT): Define. + * lexsup.c (ld_options): Add --error-handling-script. + (parse_args): Add support for --errror-handling-script. + * ld.texi: Document the new feature. + * configure.ac: Add --error-handling-script option to disable + support for the new feature. + * NEWS: Mention the new feature. + * config.in: Regenerate. + * configure: Regenerate. + 2020-10-16 Nelson Chu * testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.s: New testcase. diff --git a/ld/NEWS b/ld/NEWS index 2f20a5fbcd..81c44191d2 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -1,5 +1,10 @@ -*- text -*- +* Add --error-handling-script= command line option to allow a helper + script to be invoked when an undefined symbol or a missing library is + encountered. This option can be suppressed via the configure time + switch: --enable-error-handling-script=no. + * Add -z x86-64-v[234] to the x86 ELF linker to mark x86-64-v[234] ISA level as needed. diff --git a/ld/config.in b/ld/config.in index 2f4e5ea33e..7b60d77858 100644 --- a/ld/config.in +++ b/ld/config.in @@ -215,6 +215,10 @@ /* Define if you can safely include both and . */ #undef STRING_WITH_STRINGS +/* Define to 1 if you want to support the --error-handling-script command line + option. */ +#undef SUPPORT_ERROR_HANDLING_SCRIPT + /* Use b modifier when opening binary files? */ #undef USE_BINARY_FOPEN diff --git a/ld/configure b/ld/configure index b0b92a3cbf..afe52ef5ef 100755 --- a/ld/configure +++ b/ld/configure @@ -835,6 +835,7 @@ enable_new_dtags enable_relro enable_textrel_check enable_separate_code +enable_error_handling_script enable_default_hash_style enable_libctf enable_werror @@ -1505,6 +1506,9 @@ Optional Features: --enable-textrel-check=[yes|no|warning|error] enable DT_TEXTREL check in ELF linker --enable-separate-code enable -z separate-code in ELF linker by default + --enable-error-handling-script + enable/disable support for the + --error-handling-script option --enable-default-hash-style={sysv,gnu,both} use this default hash style --enable-libctf Handle .ctf type-info sections [default=yes] @@ -12039,7 +12043,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12042 "configure" +#line 12046 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12145,7 +12149,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12148 "configure" +#line 12152 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -15945,6 +15949,17 @@ esac fi +# Decide if --error-handling-script should be supported. +ac_support_error_handling_script=unset +# Check whether --enable-error-handling-script was given. +if test "${enable_error_handling_script+set}" = set; then : + enableval=$enable_error_handling_script; case "${enableval}" in + yes) ac_support_error_handling_script=1 ;; + no) ac_support_error_handling_script=0 ;; +esac +fi + + # Decide which "--hash-style" to use by default # Provide a configure time option to override our default. # Check whether --enable-default-hash-style was given. @@ -17739,6 +17754,15 @@ cat >>confdefs.h <<_ACEOF _ACEOF +if test "${ac_support_error_handling_script}" = unset; then + ac_support_error_handling_script=1 +fi + +cat >>confdefs.h <<_ACEOF +#define SUPPORT_ERROR_HANDLING_SCRIPT $ac_support_error_handling_script +_ACEOF + + cat >>confdefs.h <<_ACEOF #define DEFAULT_EMIT_SYSV_HASH $ac_default_emit_sysv_hash diff --git a/ld/configure.ac b/ld/configure.ac index 74bcdfec36..7676009d91 100644 --- a/ld/configure.ac +++ b/ld/configure.ac @@ -195,6 +195,16 @@ AC_ARG_ENABLE(separate-code, no) ac_default_ld_z_separate_code=0 ;; esac]) +# Decide if --error-handling-script should be supported. +ac_support_error_handling_script=unset +AC_ARG_ENABLE(error-handling-script, + AS_HELP_STRING([--enable-error-handling-script], + [enable/disable support for the --error-handling-script option]), +[case "${enableval}" in + yes) ac_support_error_handling_script=1 ;; + no) ac_support_error_handling_script=0 ;; +esac]) + # Decide which "--hash-style" to use by default # Provide a configure time option to override our default. AC_ARG_ENABLE([default-hash-style], @@ -489,6 +499,13 @@ AC_DEFINE_UNQUOTED(DEFAULT_LD_Z_SEPARATE_CODE, $ac_default_ld_z_separate_code, [Define to 1 if you want to enable -z separate-code in ELF linker by default.]) +if test "${ac_support_error_handling_script}" = unset; then + ac_support_error_handling_script=1 +fi +AC_DEFINE_UNQUOTED(SUPPORT_ERROR_HANDLING_SCRIPT, + $ac_support_error_handling_script, + [Define to 1 if you want to support the --error-handling-script command line option.]) + AC_DEFINE_UNQUOTED([DEFAULT_EMIT_SYSV_HASH], [$ac_default_emit_sysv_hash], [Define to 1 if you want to emit sysv hash in the ELF linker by default.]) diff --git a/ld/ld.texi b/ld/ld.texi index 66bede283e..95f31ea530 100644 --- a/ld/ld.texi +++ b/ld/ld.texi @@ -1923,6 +1923,21 @@ architecture. This is used, for example, to dynamically select an appropriate memset function. @end itemize +@kindex --error-handling-script=@var{scriptname} +@item --error-handling-script=@var{scriptname} +If this option is provided then the linker will invoke +@var{scriptname} whenever an error is encountered. Currently however +only two kinds of error are supported: missing symbols and missing +libraries. Two arguments will be passed to script: the keyword +``missing-symbol'' or `missing-lib'' and the @var{name} of the +missing symbol or library. The intention is that the script will +provide suggestions to the user as to where the symbol or library +might be found. After the script has finished then the normal linker +error message will be displayed. + +The availability of this option is controlled by a configure time +switch, so it may not be present in specific implementations. + @kindex --no-undefined-version @item --no-undefined-version Normally when a symbol has an undefined version, the linker will ignore diff --git a/ld/ldfile.c b/ld/ldfile.c index e39170b5d9..51f878de95 100644 --- a/ld/ldfile.c +++ b/ld/ldfile.c @@ -461,6 +461,39 @@ ldfile_open_file (lang_input_statement_type *entry) && IS_ABSOLUTE_PATH (entry->local_sym_name)) einfo (_("%P: cannot find %s inside %s\n"), entry->local_sym_name, ld_sysroot); +#if SUPPORT_ERROR_HANDLING_SCRIPT + else if (error_handling_script != NULL) + { + char * argv[4]; + const char * res; + int status, err; + + argv[0] = error_handling_script; + argv[1] = "missing-lib"; + argv[2] = (char *) entry->local_sym_name; + argv[3] = NULL; + + if (verbose) + einfo (_("%P: About to run error handling script '%s' with arguments: '%s' '%s'\n"), + argv[0], argv[1], argv[2]); + + res = pex_one (PEX_SEARCH, error_handling_script, argv, + N_("error handling script"), + NULL /* Send stdout to random, temp file. */, + NULL /* Write to stderr. */, + &status, &err); + if (res != NULL) + { + einfo (_("%P: Failed to run error handling script '%s', reason: "), + error_handling_script); + /* FIXME: We assume here that errrno == err. */ + perror (res); + } + else /* We ignore the return status of the script + and always print the error message. */ + einfo (_("%P: cannot find %s\n"), entry->local_sym_name); + } +#endif else einfo (_("%P: cannot find %s\n"), entry->local_sym_name); @@ -479,6 +512,7 @@ ldfile_open_file (lang_input_statement_type *entry) break; } } + entry->flags.missing_file = TRUE; input_flags.missing_file = TRUE; } diff --git a/ld/ldlex.h b/ld/ldlex.h index 6eac75cef5..bb38cca4d6 100644 --- a/ld/ldlex.h +++ b/ld/ldlex.h @@ -116,6 +116,9 @@ enum option_values OPTION_ALLOW_SHLIB_UNDEFINED, OPTION_NO_ALLOW_SHLIB_UNDEFINED, OPTION_ALLOW_MULTIPLE_DEFINITION, +#if SUPPORT_ERROR_HANDLING_SCRIPT + OPTION_ERROR_HANDLING_SCRIPT, +#endif OPTION_NO_UNDEFINED_VERSION, OPTION_DEFAULT_SYMVER, OPTION_DEFAULT_IMPORTED_SYMVER, diff --git a/ld/ldmain.c b/ld/ldmain.c index 08be9030cb..cdb4fe58d9 100644 --- a/ld/ldmain.c +++ b/ld/ldmain.c @@ -1382,6 +1382,10 @@ warning_find_reloc (bfd *abfd, asection *sec, void *iarg) free (relpp); } +#if SUPPORT_ERROR_HANDLING_SCRIPT +char * error_handling_script = NULL; +#endif + /* This is called when an undefined symbol is found. */ static void @@ -1419,6 +1423,40 @@ undefined_symbol (struct bfd_link_info *info, error_name = xstrdup (name); } +#if SUPPORT_ERROR_HANDLING_SCRIPT + if (error_handling_script != NULL + && error_count < MAX_ERRORS_IN_A_ROW) + { + char * argv[4]; + const char * res; + int status, err; + + argv[0] = error_handling_script; + argv[1] = "missing-symbol"; + argv[2] = (char *) name; + argv[3] = NULL; + + if (verbose) + einfo (_("%P: About to run error handling script '%s' with arguments: '%s' '%s'\n"), + argv[0], argv[1], argv[2]); + + res = pex_one (PEX_SEARCH, error_handling_script, argv, + N_("error handling script"), + NULL /* Send stdout to random, temp file. */, + NULL /* Write to stderr. */, + &status, &err); + if (res != NULL) + { + einfo (_("%P: Failed to run error handling script '%s', reason: "), + error_handling_script); + /* FIXME: We assume here that errrno == err. */ + perror (res); + } + /* We ignore the return status of the script and + carry on to issue the normal error message. */ + } +#endif /* SUPPORT_ERROR_HANDLING_SCRIPT */ + if (section != NULL) { if (error_count < MAX_ERRORS_IN_A_ROW) diff --git a/ld/ldmain.h b/ld/ldmain.h index ac7db5720d..6863727473 100644 --- a/ld/ldmain.h +++ b/ld/ldmain.h @@ -37,6 +37,9 @@ extern int g_switch_value; extern const char *output_filename; extern struct bfd_link_info link_info; extern int overflow_cutoff_limit; +#if SUPPORT_ERROR_HANDLING_SCRIPT +extern char *error_handling_script; +#endif #define RELAXATION_DISABLED_BY_DEFAULT \ (link_info.disable_target_specific_optimizations < 0) diff --git a/ld/lexsup.c b/ld/lexsup.c index 6894399484..eae64932df 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -386,6 +386,11 @@ static const struct ld_option ld_options[] = { {"allow-multiple-definition", no_argument, NULL, OPTION_ALLOW_MULTIPLE_DEFINITION}, '\0', NULL, N_("Allow multiple definitions"), TWO_DASHES }, +#if SUPPORT_ERROR_HANDLING_SCRIPT + { {"error-handling-script", required_argument, NULL, + OPTION_ERROR_HANDLING_SCRIPT}, + '\0', N_("SCRIPT"), N_("Provide a script to help with undefined symbol errors"), TWO_DASHES}, +#endif { {"no-undefined-version", no_argument, NULL, OPTION_NO_UNDEFINED_VERSION}, '\0', NULL, N_("Disallow undefined version"), TWO_DASHES }, { {"default-symver", no_argument, NULL, OPTION_DEFAULT_SYMVER}, @@ -1043,6 +1048,15 @@ parse_args (unsigned argc, char **argv) case OPTION_ALLOW_MULTIPLE_DEFINITION: link_info.allow_multiple_definition = TRUE; break; + +#if SUPPORT_ERROR_HANDLING_SCRIPT + case OPTION_ERROR_HANDLING_SCRIPT: + /* FIXME: Should we warn if the script is being overridden by another ? + Or maybe they should be chained together ? */ + error_handling_script = optarg; + break; +#endif + case OPTION_NO_UNDEFINED_VERSION: link_info.allow_undefined_version = FALSE; break; -- 2.34.1