xtensa: add dynconfig option for ld/gas

This needs to build xtensa multilib. Multilib can not operate with
environment variables but with compile options.

bfd/
        * bfd/xtensa-dynconfig.c: Add xtensa_dynconfig_file variable.

gas/
        * gas/config/tc-xtensa.c: Add dynconfig option.

ld/
        * ld/emultempl/xtensaelf.em: Add dynconfig option.
This commit is contained in:
Alexey Lapshin
2023-07-03 17:14:52 +04:00
parent 6113153c23
commit 12cbbaeb40
5 changed files with 99 additions and 4 deletions

View File

@@ -20,6 +20,7 @@
#include "sysdep.h" #include "sysdep.h"
#include "bfd.h" #include "bfd.h"
#include "libbfd.h" #include "libbfd.h"
#include "libiberty.h"
#define XTENSA_CONFIG_DEFINITION #define XTENSA_CONFIG_DEFINITION
#include "xtensa-config.h" #include "xtensa-config.h"
@@ -64,6 +65,70 @@ dlerror (void)
#define CONFIG_ENV_NAME "XTENSA_GNU_CONFIG" #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 *xtensa_load_config (const char *name ATTRIBUTE_UNUSED,
const void *no_plugin_def, const void *no_plugin_def,
const void *no_name_def ATTRIBUTE_UNUSED) const void *no_name_def ATTRIBUTE_UNUSED)
@@ -75,12 +140,13 @@ const void *xtensa_load_config (const char *name ATTRIBUTE_UNUSED,
if (!init) if (!init)
{ {
const char *path = getenv (CONFIG_ENV_NAME); char *path = get_xtensa_dynconfig_file();
init = 1; init = 1;
if (!path) if (!path)
return no_plugin_def; return no_plugin_def;
handle = dlopen (path, RTLD_LAZY); handle = dlopen (path, RTLD_LAZY);
free (path);
if (!handle) if (!handle)
{ {
_bfd_error_handler (_("%s is defined but could not be loaded: %s"), _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 #else
if (!init) 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; init = 1;
if (path) if (path)

View File

@@ -733,6 +733,8 @@ enum
option_abi_windowed, option_abi_windowed,
option_abi_call0, option_abi_call0,
option_dynconfig,
}; };
const char *md_shortopts = ""; const char *md_shortopts = "";
@@ -817,6 +819,7 @@ struct option md_longopts[] =
{ "abi-windowed", no_argument, NULL, option_abi_windowed }, { "abi-windowed", no_argument, NULL, option_abi_windowed },
{ "abi-call0", no_argument, NULL, option_abi_call0 }, { "abi-call0", no_argument, NULL, option_abi_call0 },
{ "dynconfig=", required_argument, NULL, option_dynconfig },
{ NULL, no_argument, NULL, 0 } { NULL, no_argument, NULL, 0 }
}; };
@@ -1053,6 +1056,12 @@ md_parse_option (int c, const char *arg)
elf32xtensa_abi = XTHAL_ABI_CALL0; elf32xtensa_abi = XTHAL_ABI_CALL0;
return 1; return 1;
case option_dynconfig:
{
/* Applied in xtensa_init() */
return 1;
}
default: default:
return 0; return 0;
} }
@@ -1087,7 +1096,9 @@ Xtensa options:\n\
--[no-]separate-prop-tables\n\ --[no-]separate-prop-tables\n\
[Do not] place Xtensa property records into\n\ [Do not] place Xtensa property records into\n\
individual property sections for each section.\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=<file>\n\
Use xtensa dynconfig options\n", stream);
} }
@@ -5268,8 +5279,12 @@ xg_init_global_config (void)
} }
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 (); xg_init_global_config ();
} }

View File

@@ -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_v3 *xtensa_get_config_v3 (void);
extern const struct xtensa_config_v4 *xtensa_get_config_v4 (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 #ifdef XTENSA_CONFIG_DEFINITION
#ifndef XCHAL_HAVE_MUL32_HIGH #ifndef XCHAL_HAVE_MUL32_HIGH

View File

@@ -61,6 +61,10 @@ static char *
elf_xtensa_choose_target (int argc ATTRIBUTE_UNUSED, elf_xtensa_choose_target (int argc ATTRIBUTE_UNUSED,
char **argv 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) if (XCHAL_HAVE_BE)
return "${BIG_OUTPUT_FORMAT}"; return "${BIG_OUTPUT_FORMAT}";
else else
@@ -1931,6 +1935,7 @@ PARSE_AND_LIST_LONGOPTS='
{ "no-literal-movement", no_argument, NULL, OPTION_NO_LITERAL_MOVEMENT}, { "no-literal-movement", no_argument, NULL, OPTION_NO_LITERAL_MOVEMENT},
{ "abi-windowed", no_argument, NULL, OPTION_ABI_WINDOWED}, { "abi-windowed", no_argument, NULL, OPTION_ABI_WINDOWED},
{ "abi-call0", no_argument, NULL, OPTION_ABI_CALL0}, { "abi-call0", no_argument, NULL, OPTION_ABI_CALL0},
{ "dynconfig=", required_argument, NULL, OPTION_DYNCONFIG},
' '
PARSE_AND_LIST_OPTIONS=' PARSE_AND_LIST_OPTIONS='
@@ -1941,6 +1946,8 @@ PARSE_AND_LIST_OPTIONS='
--abi-windowed Choose windowed ABI for the output object\n")); --abi-windowed Choose windowed ABI for the output object\n"));
fprintf (file, _("\ fprintf (file, _("\
--abi-call0 Choose call0 ABI for the output object\n")); --abi-call0 Choose call0 ABI for the output object\n"));
fprintf (file, _("\
--dynconfig=FILE Choose xtensa dynconfig file\n"));
' '
PARSE_AND_LIST_ARGS_CASES=' PARSE_AND_LIST_ARGS_CASES='
@@ -1959,6 +1966,9 @@ PARSE_AND_LIST_ARGS_CASES='
case OPTION_ABI_CALL0: case OPTION_ABI_CALL0:
elf32xtensa_abi = XTHAL_ABI_CALL0; elf32xtensa_abi = XTHAL_ABI_CALL0;
break; break;
case OPTION_DYNCONFIG:
/* Applied in elf_xtensa_choose_target() */
break;
' '
# Replace some of the standard ELF functions with our own versions. # Replace some of the standard ELF functions with our own versions.

View File

@@ -471,6 +471,7 @@ enum option_values
OPTION_NO_LITERAL_MOVEMENT, OPTION_NO_LITERAL_MOVEMENT,
OPTION_ABI_WINDOWED, OPTION_ABI_WINDOWED,
OPTION_ABI_CALL0, OPTION_ABI_CALL0,
OPTION_DYNCONFIG,
}; };
/* The initial parser states. */ /* The initial parser states. */