[v2] xtensa: add dynconfig option for ld/gas

Message ID 06c21c191d62b269d6273652f8f025749af6e3a9.camel@espressif.com
State New
Headers
Series [v2] xtensa: add dynconfig option for ld/gas |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Testing passed

Commit Message

Alexey Lapshin April 1, 2024, 1:01 p.m. UTC
  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.
---
 bfd/xtensa-dynconfig.c     | 70 ++++++++++++++++++++++++++++++++++++--
 gas/config/tc-xtensa.c     | 16 ++++++++-
 include/xtensa-dynconfig.h |  3 ++
 ld/emultempl/xtensaelf.em  | 10 ++++++
 ld/ldlex.h                 |  1 +
 5 files changed, 97 insertions(+), 3 deletions(-)

-- 
2.34.1
  

Patch

diff --git a/bfd/xtensa-dynconfig.c b/bfd/xtensa-dynconfig.c
index 843f376326b..bd47798047e 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 = "";
+
+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;
+           }
+    }
+}
+
+#ifdef BFD_SUPPORTS_PLUGINS
+
+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..9debd142fb4 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,8 @@  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 +1057,10 @@  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 +1095,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=<file>\n\
+                          Use xtensa dynconfig library\n", stream);
 }
 
 
@@ -5270,6 +5280,10 @@  xg_init_global_config (void)
 void
 xtensa_init (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
 {
+  /* 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..93277f2773d 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 library\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 d575562a357..f43ba4904c1 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -468,6 +468,7 @@  enum option_values
   OPTION_NO_LITERAL_MOVEMENT,
   OPTION_ABI_WINDOWED,
   OPTION_ABI_CALL0,
+  OPTION_DYNCONFIG,
 };
 
 /* The initial parser states.  */