diff --git a/bfd/xtensa-dynconfig.c b/bfd/xtensa-dynconfig.c index 843f376326b..2124893eb8e 100644 --- a/bfd/xtensa-dynconfig.c +++ b/bfd/xtensa-dynconfig.c @@ -20,6 +20,7 @@ #include "sysdep.h" #include "bfd.h" #include "libbfd.h" +#include "libiberty.h" #define XTENSA_CONFIG_DEFINITION #include "xtensa-config.h" @@ -64,6 +65,70 @@ dlerror (void) #define CONFIG_ENV_NAME "XTENSA_GNU_CONFIG" +/* this variable can be changed with input option for gas/ld */ +const char *xtensa_dynconfig_file = ""; + +#ifdef BFD_SUPPORTS_PLUGINS + +void xtensa_set_dynconfig_from_argv(int argc, char **argv) +{ + const char * const dynconfig_opt = "--dynconfig="; + for (int i = 1; i < argc; i++) + { + if (!strncmp (dynconfig_opt, argv[i], strlen(dynconfig_opt))) + { + xtensa_dynconfig_file = &argv[i][strlen(dynconfig_opt)]; + break; + } + } +} + +static char *get_xtensa_dynconfig_file (void) +{ + const char *xtensa_dynconfig_env = getenv (CONFIG_ENV_NAME); + if (!strlen (xtensa_dynconfig_file)) + { + if (xtensa_dynconfig_env && !strlen (lbasename (xtensa_dynconfig_env))) + { + /* XTENSA_GNU_CONFIG has directory path, but dynconfig file is not set */ + return NULL; + } + else if (xtensa_dynconfig_env) + { + /* XTENSA_GNU_CONFIG has filepath */ + return xstrdup (xtensa_dynconfig_env); + } + /* dynconfig is not set */ + return NULL; + } + if (!xtensa_dynconfig_env) + { + /* XTENSA_GNU_CONFIG has filepath */ + return xstrdup (xtensa_dynconfig_file); + } + if (!strlen (lbasename (xtensa_dynconfig_env))) + { + /* XTENSA_GNU_CONFIG has directory path and dynconfig file is set */ + const size_t len = strlen (xtensa_dynconfig_env) + + strlen (xtensa_dynconfig_file) + 1; + char *path = ( char *) xmalloc (len); + strcpy (path, xtensa_dynconfig_env); + strcat (path, xtensa_dynconfig_file); + return path; + } + if (strcmp (lbasename (xtensa_dynconfig_env), + lbasename (xtensa_dynconfig_file))) + { + _bfd_error_handler (_("Both %s and \"-dynconfig=\" specified but pointed different files: \"%s\" \"%s\""), + CONFIG_ENV_NAME, xtensa_dynconfig_env, xtensa_dynconfig_file); + abort (); + } + /* XTENSA_GNU_CONFIG and mdynconfig option point to the same file */ + return xstrdup (xtensa_dynconfig_env); +} + +#endif /* BFD_SUPPORTS_PLUGINS */ + const void *xtensa_load_config (const char *name ATTRIBUTE_UNUSED, const void *no_plugin_def, const void *no_name_def ATTRIBUTE_UNUSED) @@ -75,12 +140,13 @@ const void *xtensa_load_config (const char *name ATTRIBUTE_UNUSED, if (!init) { - const char *path = getenv (CONFIG_ENV_NAME); + char *path = get_xtensa_dynconfig_file(); init = 1; if (!path) return no_plugin_def; handle = dlopen (path, RTLD_LAZY); + free (path); if (!handle) { _bfd_error_handler (_("%s is defined but could not be loaded: %s"), @@ -107,7 +173,7 @@ const void *xtensa_load_config (const char *name ATTRIBUTE_UNUSED, #else if (!init) { - const char *path = getenv (CONFIG_ENV_NAME); + const char *path = strcmp(xtensa_dynconfig_file, "") ? xtensa_dynconfig_file : getenv (CONFIG_ENV_NAME); init = 1; if (path) diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c index e051bb9265b..c96387e0227 100644 --- a/gas/config/tc-xtensa.c +++ b/gas/config/tc-xtensa.c @@ -733,6 +733,8 @@ enum option_abi_windowed, option_abi_call0, + + option_dynconfig, }; const char *md_shortopts = ""; @@ -817,6 +819,7 @@ struct option md_longopts[] = { "abi-windowed", no_argument, NULL, option_abi_windowed }, { "abi-call0", no_argument, NULL, option_abi_call0 }, + { "dynconfig=", required_argument, NULL, option_dynconfig }, { NULL, no_argument, NULL, 0 } }; @@ -1053,6 +1056,12 @@ md_parse_option (int c, const char *arg) elf32xtensa_abi = XTHAL_ABI_CALL0; return 1; + case option_dynconfig: + { + /* Applied in xtensa_init() */ + return 1; + } + default: return 0; } @@ -1087,7 +1096,9 @@ Xtensa options:\n\ --[no-]separate-prop-tables\n\ [Do not] place Xtensa property records into\n\ individual property sections for each section.\n\ - Default is to generate single property section.\n", stream); + Default is to generate single property section.\n\ + --dynconfig=\n\ + Use xtensa dynconfig options\n", stream); } @@ -5268,8 +5279,12 @@ xg_init_global_config (void) } void -xtensa_init (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +xtensa_init (int argc, char **argv) { + /* This function is called before AS arguments parsed. + * So, dynconfig file must be set first. */ + xtensa_set_dynconfig_from_argv(argc, argv); + xg_init_global_config (); } diff --git a/include/xtensa-dynconfig.h b/include/xtensa-dynconfig.h index a0acffea236..a8556498254 100644 --- a/include/xtensa-dynconfig.h +++ b/include/xtensa-dynconfig.h @@ -129,6 +129,9 @@ extern const struct xtensa_config_v2 *xtensa_get_config_v2 (void); extern const struct xtensa_config_v3 *xtensa_get_config_v3 (void); extern const struct xtensa_config_v4 *xtensa_get_config_v4 (void); + +void xtensa_set_dynconfig_from_argv(int argc, char **argv); + #ifdef XTENSA_CONFIG_DEFINITION #ifndef XCHAL_HAVE_MUL32_HIGH diff --git a/ld/emultempl/xtensaelf.em b/ld/emultempl/xtensaelf.em index 3508eb7f503..99eab9389a7 100644 --- a/ld/emultempl/xtensaelf.em +++ b/ld/emultempl/xtensaelf.em @@ -61,6 +61,10 @@ static char * elf_xtensa_choose_target (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + /* This function is called before LD arguments parsed. + * So, dynconfig file must be set first. */ + xtensa_set_dynconfig_from_argv(argc, argv); + if (XCHAL_HAVE_BE) return "${BIG_OUTPUT_FORMAT}"; else @@ -1931,6 +1935,7 @@ PARSE_AND_LIST_LONGOPTS=' { "no-literal-movement", no_argument, NULL, OPTION_NO_LITERAL_MOVEMENT}, { "abi-windowed", no_argument, NULL, OPTION_ABI_WINDOWED}, { "abi-call0", no_argument, NULL, OPTION_ABI_CALL0}, + { "dynconfig=", required_argument, NULL, OPTION_DYNCONFIG}, ' PARSE_AND_LIST_OPTIONS=' @@ -1941,6 +1946,8 @@ PARSE_AND_LIST_OPTIONS=' --abi-windowed Choose windowed ABI for the output object\n")); fprintf (file, _("\ --abi-call0 Choose call0 ABI for the output object\n")); + fprintf (file, _("\ + --dynconfig=FILE Choose xtensa dynconfig file\n")); ' PARSE_AND_LIST_ARGS_CASES=' @@ -1959,6 +1966,9 @@ PARSE_AND_LIST_ARGS_CASES=' case OPTION_ABI_CALL0: elf32xtensa_abi = XTHAL_ABI_CALL0; break; + case OPTION_DYNCONFIG: + /* Applied in elf_xtensa_choose_target() */ + break; ' # Replace some of the standard ELF functions with our own versions. diff --git a/ld/ldlex.h b/ld/ldlex.h index defe3fcbbb9..6153f273bea 100644 --- a/ld/ldlex.h +++ b/ld/ldlex.h @@ -471,6 +471,7 @@ enum option_values OPTION_NO_LITERAL_MOVEMENT, OPTION_ABI_WINDOWED, OPTION_ABI_CALL0, + OPTION_DYNCONFIG, }; /* The initial parser states. */