diff --git a/gcc/gcc.c b/gcc/gcc.c
index effc384f3ef..9f790db0daf 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -5242,6 +5242,34 @@ do_specs_vec (vec<char_p> vec)
     }
 }
 
+/* Add options passed via -Xassembler or -Wa to COLLECT_AS_OPTIONS.  */
+
+static void
+putenv_COLLECT_AS_OPTIONS (vec<char_p> vec)
+{
+  if (vec.is_empty ())
+     return;
+
+  obstack_init (&collect_obstack);
+  obstack_grow (&collect_obstack, "COLLECT_AS_OPTIONS=",
+		strlen ("COLLECT_AS_OPTIONS="));
+
+  char *opt;
+  unsigned ix;
+
+  FOR_EACH_VEC_ELT (vec, ix, opt)
+    {
+      obstack_1grow (&collect_obstack, '\'');
+      obstack_grow (&collect_obstack, opt, strlen (opt));
+      obstack_1grow (&collect_obstack, '\'');
+      if (ix < vec.length () - 1)
+	obstack_1grow(&collect_obstack, ' ');
+    }
+
+  obstack_1grow (&collect_obstack, '\0');
+  xputenv (XOBFINISH (&collect_obstack, char *));
+}
+
 /* Process the sub-spec SPEC as a portion of a larger spec.
    This is like processing a whole spec except that we do
    not initialize at the beginning and we do not supply a
@@ -7363,6 +7391,7 @@ driver::main (int argc, char **argv)
   global_initializations ();
   build_multilib_strings ();
   set_up_specs ();
+  putenv_COLLECT_AS_OPTIONS (assembler_options);
   putenv_COLLECT_GCC (argv[0]);
   maybe_putenv_COLLECT_LTO_WRAPPER ();
   maybe_putenv_OFFLOAD_TARGETS ();
diff --git a/gcc/lto-opts.c b/gcc/lto-opts.c
index 90bfde5a8fd..595be137ba9 100644
--- a/gcc/lto-opts.c
+++ b/gcc/lto-opts.c
@@ -163,6 +163,22 @@ lto_write_options (void)
 	append_to_collect_gcc_options (&temporary_obstack, &first_p,
 				       option->canonical_option[j]);
     }
+
+  char *collect_as_options = getenv ("COLLECT_AS_OPTIONS");
+  if (collect_as_options)
+    {
+      char *saveptr;
+      char *tok = strtok_r (collect_as_options, " ", &saveptr);
+
+      while (tok)
+	{
+	  obstack_grow (&temporary_obstack, " '-Xassembler' ",
+			strlen (" '-Xassembler' "));
+	  obstack_grow (&temporary_obstack, tok, strlen (tok));
+	  tok = strtok_r (NULL, " ", &saveptr);
+	}
+    }
+
   obstack_grow (&temporary_obstack, "\0", 1);
   args = XOBFINISH (&temporary_obstack, char *);
   lto_write_data (args, strlen (args) + 1);
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index fe8f292f877..624ad096441 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "simple-object.h"
 #include "lto-section-names.h"
 #include "collect-utils.h"
+#include <algorithm>
 
 /* Environment variable, used for passing the names of offload targets from GCC
    driver to lto-wrapper.  */
@@ -624,6 +625,7 @@ append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
 	case OPT_Ofast:
 	case OPT_Og:
 	case OPT_Os:
+	case OPT_Xassembler:
 	  break;
 
 	default:
@@ -967,6 +969,10 @@ find_crtoffloadtable (void)
   free_array_of_ptrs ((void **) paths, n_paths);
 }
 
+/* Used for storing Xassembler opts passed to first TU.  */
+static struct cl_decoded_option *xassembler_opts = NULL;
+static unsigned xassembler_opts_count = 0;
+
 /* A subroutine of run_gcc.  Examine the open file FD for lto sections with
    name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS
    and OPT_COUNT.  Return true if we found a matchingn section, false
@@ -976,7 +982,8 @@ find_crtoffloadtable (void)
 static bool
 find_and_merge_options (int fd, off_t file_offset, const char *prefix,
 			struct cl_decoded_option **opts,
-			unsigned int *opt_count, const char *collect_gcc)
+			unsigned int *opt_count, const char *collect_gcc,
+			bool first_tu = false)
 {
   off_t offset, length;
   char *data;
@@ -986,6 +993,10 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
   struct cl_decoded_option *fdecoded_options = *opts;
   unsigned int fdecoded_options_count = *opt_count;
 
+  /* Store Xassembler opts passed to current TU.  */
+  struct cl_decoded_option *curr_xopts;
+  unsigned curr_xopts_count = 0;
+
   simple_object_read *sobj;
   sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO",
 				   &errmsg, &err);
@@ -1023,10 +1034,42 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
 			    &fdecoded_options_count,
 			    f2decoded_options, f2decoded_options_count);
 
+      /* Collect -Xassembler options of current TU in curr_xopts.  */
+      for (unsigned i = 0; i < f2decoded_options_count; i++)
+	if (f2decoded_options[i].opt_index == OPT_Xassembler)
+	  append_option (&curr_xopts, &curr_xopts_count, &f2decoded_options[i]);
+
       fopts += strlen (fopts) + 1;
     }
   while (fopts - data < length);
 
+  /* xassembler_opts might be non-null for first TU
+     if -Xassembler is passed as cmdline option during link time.  */
+  if (first_tu && !xassembler_opts)
+    {
+      xassembler_opts = curr_xopts;
+      xassembler_opts_count = curr_xopts_count;
+    }
+  else
+    {
+      unsigned min_opts_count
+	= std::min (xassembler_opts_count, curr_xopts_count);
+      for (unsigned i = 0; i < min_opts_count; i++)
+	if (strcmp (xassembler_opts[i].arg, curr_xopts[i].arg))
+	  fatal_error (input_location,
+		       "Options to Xassembler do not match: %s, %s.",
+		       xassembler_opts[i].arg, curr_xopts[i].arg);
+
+      for (unsigned i = min_opts_count; i < xassembler_opts_count; i++)
+	fatal_error (input_location,
+		     "Extra option to Xassembler: %s.",
+		     xassembler_opts[i].arg);
+
+      for (unsigned i = min_opts_count; i < curr_xopts_count; i++)
+	fatal_error (input_location,
+		     "Extra option %s to Xassembler.", curr_xopts[i].arg);
+    }
+
   free (data);
   simple_object_release_read (sobj);
   *opts = fdecoded_options;
@@ -1251,7 +1294,8 @@ run_gcc (unsigned argc, char *argv[])
   const char **argv_ptr;
   char *list_option_full = NULL;
   const char *linker_output = NULL;
-  const char *collect_gcc, *collect_gcc_options;
+  const char *collect_gcc;
+  char *collect_gcc_options;
   int parallel = 0;
   int jobserver = 0;
   int auto_parallel = 0;
@@ -1281,15 +1325,48 @@ run_gcc (unsigned argc, char *argv[])
   if (!collect_gcc_options)
     fatal_error (input_location,
 		 "environment variable %<COLLECT_GCC_OPTIONS%> must be set");
+
+  char *collect_as_options = getenv ("COLLECT_AS_OPTIONS");
+
+  /* Prepend -Xassembler to each option, and append the string
+     to collect_gcc_options.  */
+  if (collect_as_options)
+    {
+      obstack temporary_obstack;
+      obstack_init (&temporary_obstack);
+
+      char *saveptr;
+      char *tok = strtok_r (collect_as_options, " ", &saveptr);
+
+      while (tok)
+	{
+	  obstack_grow (&temporary_obstack, " '-Xassembler' ",
+			strlen (" '-Xassembler' "));
+	  obstack_grow (&temporary_obstack, tok, strlen (tok));
+	  tok = strtok_r (NULL, " ", &saveptr);
+	}
+
+      obstack_1grow (&temporary_obstack, '\0');
+
+      char *xassembler_opts_string
+	= XOBFINISH (&temporary_obstack, char *);
+      strcat (collect_gcc_options, xassembler_opts_string);
+    }
+
   get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options,
 					&decoded_options,
 					&decoded_options_count);
 
+  for (unsigned i = 0; i < decoded_options_count; i++)
+    if (decoded_options[i].opt_index == OPT_Xassembler)
+      append_option (&xassembler_opts, &xassembler_opts_count,
+		     &decoded_options[i]);
+
   /* Allocate array for input object files with LTO IL,
      and for possible preceding arguments.  */
   lto_argv = XNEWVEC (char *, argc);
   ltoobj_argv = XNEWVEC (char *, argc);
-
+  bool first_tu = true;
   /* Look at saved options in the IL files.  */
   for (i = 1; i < argc; ++i)
     {
@@ -1334,11 +1411,12 @@ run_gcc (unsigned argc, char *argv[])
 
       if (find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX,
 				  &fdecoded_options, &fdecoded_options_count,
-				  collect_gcc))
+				  collect_gcc, first_tu))
 	{
 	  have_lto = true;
 	  ltoobj_argv[ltoobj_argc++] = argv[i];
 	}
+      first_tu = false;
       close (fd);
     }
 
diff --git a/gcc/testsuite/gcc.target/arm/pr78353-1.c b/gcc/testsuite/gcc.target/arm/pr78353-1.c
new file mode 100644
index 00000000000..aec0fb0cbfd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr78353-1.c
@@ -0,0 +1,8 @@
+/* { dg-do link }  */
+/* { dg-options "-march=armv7-a -mthumb -O2 -flto -Wa,-mimplicit-it=always" }  */
+
+int main(int x)
+{
+  asm("teq %0, #0; addne %0, %0, #1" : "=r" (x));
+  return x;
+}
diff --git a/gcc/testsuite/gcc.target/arm/pr78353-2.c b/gcc/testsuite/gcc.target/arm/pr78353-2.c
new file mode 100644
index 00000000000..18a90e8834e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr78353-2.c
@@ -0,0 +1,9 @@
+/* { dg-do link }  */
+/* { dg-options "-march=armv7-a -mthumb -O2 -flto -Wa,-mimplicit-it=always,-mthumb" }  */
+
+int main(int x)
+{
+  asm("teq %0, #0; addne %0, %0, #1" : "=r" (x));
+  return x;
+}
+
