diff --git a/ld/ldcrc32.c b/ld/ldcrc32.c
new file mode 100644
index 00000000000..8b7de1d6e72
--- /dev/null
+++ b/ld/ldcrc32.c
@@ -0,0 +1,179 @@
+/*
+ * Library: ldlibcrc
+ * Author:  Lammert Bies, Bastian Molkenthin, Ulf Samuelsson
+ *
+ * This file is licensed under the MIT License as stated below
+ *
+ * Copyright (c) 2016 Lammert Bies
+ * Copyright (c) 2013 Ulf Samuelsson (ulf@emagii.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "lddigest.h"
+#include "ldreflect.h"
+
+#define SHIFT(t)   ((sizeof(t)-1)*8)
+/* ============ CRC-32 LIBCRC functions ======================================*/
+
+/*
+ * void _init_crc32_tab (uint32_t *crc_tab,  uint32_t poly);
+ *
+ * For optimal speed, the CRC32 calculation uses a table with pre-calculated
+ * bit patterns which are used in the XOR operations in the program.
+ * _init_crc32_tab is copyright (c) 2016 Lammert Bies
+ */
+static void
+_init_crc32_tab (uint32_t * crc_tab, uint32_t poly)
+{
+  uint32_t crc;
+  uint32_t shift = SHIFT (uint32_t);
+  for (uint32_t i = 0; i < 256; i++)
+    {
+      crc = i << shift;
+      for (uint32_t j = 0; j < 8; j++)
+	{
+	  if ((crc & 0x80000000u) != 0)
+	    {
+	      crc = (crc << 1) ^ poly;
+	    }
+	  else
+	    {
+	      crc = crc << 1;
+	    }
+	}
+      crc_tab[i] = crc;
+    }
+}				/* _init_crc32__tab */
+
+/*
+ * void _init_crc32_reciprocal_tab (uint32_t *crc_tab,  uint32_t poly);
+ *
+ * For optimal speed, the CRC32 calculation uses a table with pre-calculated
+ * bit patterns which are used in the XOR operations in the program.
+ * _init_crc32_reciprocal_tab is copyright (c) 2021 Bastian Molkenthin
+ */
+static void
+_init_crc32_reciprocal_tab (uint32_t * crc_tab, uint32_t poly)
+{
+  uint32_t crc;
+  uint32_t reflected_poly = reflect32 (poly);
+  for (uint32_t i = 0; i < 256; i++)
+    {
+      crc = i;
+      for (uint32_t j = 0; j < 8; j++)
+	{
+	  if (crc & 0x00000001U)
+	    {
+	      crc >>= 1;
+	      crc ^= reflected_poly;
+	    }
+	  else
+	    {
+	      crc = crc >> 1;
+	    }
+	}
+      crc_tab[i] = crc;
+    }
+}				/* _init_crc32_reciprocal_tab */
+
+/*
+ * void init_crc32_tab( void );
+ *
+ * For optimal speed, the CRC32 calculation uses a table with pre-calculated
+ * bit patterns which are used in the XOR operations in the program.
+ * The table can be calculated in a normal or a reciprocal version.
+ * init_crc64_tab is copyright (c) 2023 Ulf Samuelsson
+ */
+uint32_t *
+init_crc32_tab (algorithm_desc_t * dsc)
+{
+  uint32_t *crc_tab = malloc (256 * sizeof (uint32_t));
+
+  if (crc_tab == NULL)
+    return NULL;
+
+  if (dsc->reciprocal)
+    {
+      _init_crc32_reciprocal_tab (crc_tab, dsc->poly.d32._0);
+    }
+  else
+    {
+      _init_crc32_tab (crc_tab, dsc->poly.d32._0);
+    }
+
+  return crc_tab;
+}				/* init_crc32_tab */
+
+/*
+ * uint32_t calc_crc32(algorithm_desc_t *dsc, const unsigned char *input_str, size_t num_bytes);
+ *
+ * The function calc_crc32() calculates in one pass the common 32 bit CRC value for
+ * a byte string that is passed to the function together with a parameter
+ * indicating the length.
+ * calc_crc32 is
+ *   copyright (c) 2016 Lammert Bies
+ *   copyright (c) 2021 Bastian Molkenthin
+ *   copyright (c) 2023 Ulf Samuelsson
+ */
+uint32_t
+calc_crc32 (algorithm_desc_t * dsc, const unsigned char *input_str,
+	    size_t num_bytes)
+{
+  uint32_t crc;
+  const unsigned char *ptr;
+  uint32_t index;
+  uint32_t *crc_tab = dsc->crc_tab;
+
+  if ((ptr = input_str) == NULL)
+    return 0;
+
+  if (crc_tab == NULL)
+    return 0;
+
+  crc = dsc->initial.d32._0;
+
+  if (dsc->reciprocal)
+    {
+      for (uint32_t i = 0; i < num_bytes; i++)
+	{
+	  index = ((crc >> 0) ^ (uint32_t) * ptr++) & 0x000000FFul;
+	  crc = (crc >> 8) ^ crc_tab[index];
+	}
+    }
+  else
+    {
+      uint32_t shift = SHIFT (uint32_t);
+      for (uint32_t i = 0; i < num_bytes; i++)
+	{
+	  const unsigned char c = *ptr++;
+	  uint32_t rc = (uint32_t) (dsc->ireflect ? reflect8 (c) : c);
+	  crc = (crc ^ (rc << shift));
+	  index = (uint32_t) (crc >> shift);
+	  crc = (crc << 8);
+	  crc = (crc ^ (crc_tab[index]));
+	}
+    }
+  crc = (dsc->oreflect ? reflect32 (crc) : crc);
+  crc = crc ^ dsc->xor_val.d32._0;
+  return crc;
+}				/* calc_crc32 */
diff --git a/ld/ldcrc64.c b/ld/ldcrc64.c
new file mode 100644
index 00000000000..c94ff21bdcb
--- /dev/null
+++ b/ld/ldcrc64.c
@@ -0,0 +1,180 @@
+/*
+ * Library: ldlibcrc
+ * Author:  Lammert Bies, Bastian Molkenthin, Ulf Samuelsson
+ *
+ * This file is licensed under the MIT License as stated below
+ *
+ * Copyright (c) 2016 Lammert Bies
+ * Copyright (c) 2021 Bastian Molkenthin
+ * Copyright (c) 2023 Ulf Samuelsson (ulf@emagii.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "lddigest.h"
+#include "ldreflect.h"
+
+#define SHIFT(t)   ((sizeof(t)-1)*8)
+/* ============ CRC-64 LIBCRC functions ======================================*/
+
+/*
+ * uint64_t *init_crc64_tab(algorithm_desc_t *dsc) ;
+ *
+ * For optimal speed, the CRC64 calculation uses a table with pre-calculated
+ * bit patterns which are used in the XOR operations in the program.
+ * init_crc64_tab is copyright (c) 2016 Lammert Bies
+ */
+static void
+_init_crc64_tab (uint64_t * crc_tab, uint64_t poly)
+{
+  uint64_t crc;
+  uint32_t shift = SHIFT (uint64_t);
+  for (uint64_t i = 0; i < 256; i++)
+    {
+      crc = i << shift;
+      for (uint64_t j = 0; j < 8; j++)
+	{
+	  if ((crc & 0x8000000000000000ull) != 0)
+	    {
+	      crc = (crc << 1) ^ poly;
+	    }
+	  else
+	    {
+	      crc = crc << 1;
+	    }
+	}
+      crc_tab[i] = crc;
+    }
+}				/* _init_crc64_tab */
+
+/*
+ * _init_crc64_reciprocal_tab (uint64_t *crc_tab,  uint64_t poly);
+ *
+ * For optimal speed, the CRC64 calculation uses a table with pre-calculated
+ * bit patterns which are used in the XOR operations in the program.
+ * _init_crc64_reciprocal_tab is copyright (c) 2021 Bastian Molkenthin
+ */
+
+static void
+_init_crc64_reciprocal_tab (uint64_t * crc_tab, uint64_t poly)
+{
+  uint64_t crc;
+  uint64_t reflected_poly = reflect64 (poly);
+  for (uint64_t i = 0; i < 256; i++)
+    {
+      crc = i;
+      for (uint64_t j = 0; j < 8; j++)
+	{
+	  if ((crc & 0x0000000000000001ULL) != 0)
+	    {
+	      crc >>= 1;
+	      crc ^= reflected_poly;
+	    }
+	  else
+	    {
+	      crc >>= 1;
+	    }
+	}
+      crc_tab[i] = crc;
+    }
+}				/* _init_crc64_reciprocal_tab */
+
+/*
+ * uint64_t *init_crc64_tab(algorithm_desc_t *dsc) ;
+ *
+ * For optimal speed, the CRC64 calculation uses a table with pre-calculated
+ * bit patterns which are used in the XOR operations in the program.
+ * init_crc64_tab is copyright (c) 2023 Ulf Samuelsson
+ */
+uint64_t *
+init_crc64_tab (algorithm_desc_t * dsc)
+{
+  uint64_t *crc_tab = malloc (256 * sizeof (uint64_t));
+
+  if (crc_tab == NULL)
+    return NULL;
+
+  if (dsc->reciprocal)
+    {
+      _init_crc64_reciprocal_tab (crc_tab, dsc->poly.d64);
+    }
+  else
+    {
+      _init_crc64_tab (crc_tab, dsc->poly.d64);
+    }
+  return crc_tab;
+
+}				/* init_crc64_tab */
+
+/*
+ * uint64_t calc_crc64
+ *   (algorithm_desc_t *dsc, const unsigned char *input_str, size_t num_bytes);
+ *
+ * The function calc_crc64() calculates in one pass the 64 bit CRC value
+ * for a byte string that is passed to the function together with a
+ * parameter indicating the length.
+ * calc_crc64 is
+ *   copyright (c) 2016 Lammert Bies
+ *   copyright (c) 2021 Bastian Molkenthin
+ *   copyright (c) 2023 Ulf Samuelsson
+ */
+uint64_t calc_crc64
+  (algorithm_desc_t * dsc, const unsigned char *input_str, size_t num_bytes)
+{
+  uint64_t crc;
+  const unsigned char *ptr;
+  uint64_t *crc_tab = dsc->crc_tab;
+  uint64_t index;
+
+  if ((ptr = input_str) == NULL)
+    return 0;
+
+  if (crc_tab == NULL)
+    return 0;
+
+
+  crc = dsc->initial.d64;
+  if (dsc->reciprocal)
+    {
+      for (uint32_t i = 0; i < num_bytes; i++)
+	{
+	  index = ((crc >> 0) ^ (uint64_t) * ptr++) & 0x00000000000000FFull;
+	  crc = (crc >> 8) ^ crc_tab[index];
+	}
+    }
+  else
+    {
+      uint32_t shift = SHIFT (uint64_t);
+      for (uint32_t i = 0; i < num_bytes; i++)
+	{
+	  const unsigned char c = *ptr++;
+	  uint64_t rc = (uint64_t) (dsc->ireflect ? reflect8 (c) : c);
+	  crc = (crc ^ (rc << shift));
+	  index = (uint32_t) (crc >> shift);
+	  crc = (crc << 8);
+	  crc = (crc ^ (crc_tab[index]));
+	}
+    }
+  crc = (dsc->oreflect ? reflect64 (crc) : crc);
+  crc = crc ^ dsc->xor_val.d64;
+  return crc;
+}				/* calc_crc64 */
diff --git a/ld/lddigest.c b/ld/lddigest.c
new file mode 100644
index 00000000000..d0bb4db73ab
--- /dev/null
+++ b/ld/lddigest.c
@@ -0,0 +1,903 @@
+/* Linker command language support.
+   Copyright (C) 1991-2023 Ulf Samuelsson <ulf@emagii.com>
+
+   This file is part of the GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#define	DEBUG_CRC	0
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "safe-ctype.h"
+#include "obstack.h"
+#include "bfdlink.h"
+#include "ctf-api.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldexp.h"
+#include "ldlang.h"
+#include <ldgram.h>
+#include "ldlex.h"
+#include "ldmisc.h"
+#include "lddigest.h"
+
+/* CRC calculation on output section */
+asection *text_section;
+unsigned char *text_contents = NULL;
+
+char *CRC_ADDRESS = NULL;
+char *CRC_START = NULL;
+char *CRC_END = NULL;
+char *CRC_TABLE = NULL;
+
+
+
+
+
+const char *digest_section = ".text";
+const char *digest_label = "___CRC_LABEL__";
+bool digest_big_endian = false;
+bool polynome_valid = false;
+
+static bool
+big_endian_host (void)
+{
+  union
+  {
+    uint32_t i;
+    char c[4];
+  } e = { 0x01000000 };
+
+  return e.c[0];
+}
+
+#if     0
+static bool
+swap_endian (void)
+{
+  if (big_endian_host ())
+    {
+      return !link_info.big_endian;
+    }
+  else
+    {
+      return link_info.big_endian;
+    }
+}
+#endif
+
+/* ============ CRC-32 public functions ======================================*/
+
+void
+lang_add_crc32_syndrome (algorithm_desc_t * a)
+{
+  CRC_ADDRESS = CRC32_ADDRESS;
+  CRC_START = CRC32_START;
+  CRC_END = CRC32_END;
+  CRC_TABLE = CRC32_TABLE;
+
+  lang_add_data (LONG, exp_intop (0));	/* Reserve room for the ECC value */
+  a->crc_tab = init_crc32_tab (a);
+  if (a->crc_tab == NULL)
+    {
+      einfo (_("%F%P: can not allocate memory for CRC table: %E\n"));
+      return;
+    }
+}
+
+static void
+lang_add_crc32_table (bool big_endian)
+{
+  uint32_t *crc32_table = algorithm.crc_tab;	/* Use a precomputed, if it exists */
+  bool local_table = false;
+  if (crc32_table == NULL)
+    {				/* No luck, create a table */
+      crc32_table = init_crc32_tab (&algorithm);
+      if (crc32_table == NULL)
+	{
+	  einfo (_("%F%P: can not allocate memory for CRC table: %E\n"));
+	  return;
+	}
+      local_table = true;
+    }
+  for (bfd_vma i = 0; i < 256; i++)
+    {
+      uint32_t elem = crc32_table[i];
+      if (big_endian)
+	{
+	  elem = __builtin_bswap32 (elem);
+	}
+      lang_add_data (LONG, exp_intop (elem));
+    }
+  if (local_table)
+    free (crc32_table);
+}
+
+/* ============ CRC-64 public functions ======================================*/
+
+void
+lang_add_crc64_syndrome (algorithm_desc_t * a)
+{
+  CRC_ADDRESS = CRC64_ADDRESS;
+  CRC_START = CRC64_START;
+  CRC_END = CRC64_END;
+  CRC_TABLE = CRC64_TABLE;
+  lang_add_data (QUAD, exp_intop (0));	/* Reserve room for the ECC value */
+  a->crc_tab = init_crc64_tab (a);
+  if (a->crc_tab == NULL)
+    {
+      einfo (_("%F%P: can not allocate memory for CRC table: %E\n"));
+      return;
+    }
+}
+
+#if (DEBUG_CRC == 1)
+static void
+print_hash64_table (algorithm_desc_t * a)
+{
+  uint64_t *crc_tab = a->crc_tab;
+  uint32_t i;
+  if (crc_tab == NULL)
+    {
+      printf ("%-20ssBad Table\n", a->name);
+      return;
+
+    }
+
+  i = 0;
+  printf ("%03d\t", i);
+  printf ("0x%016lx, ", crc_tab[i + 0]);
+  printf ("0x%016lx, ", crc_tab[i + 1]);
+  printf ("0x%016lx, ", crc_tab[i + 2]);
+  printf ("0x%016lx\n", crc_tab[i + 3]);
+  printf ("\t...\n");
+  i = 252;
+  printf ("%03d\t", i);
+  printf ("0x%016lx, ", crc_tab[i + 0]);
+  printf ("0x%016lx, ", crc_tab[i + 1]);
+  printf ("0x%016lx, ", crc_tab[i + 2]);
+  printf ("0x%016lx\n", crc_tab[i + 3]);
+  printf ("\n");
+}
+#else
+#define print_hash64_table(x)
+#endif
+
+static void
+lang_add_crc64_table (bool big_endian)
+{
+  bfd_vma *crc64_table = algorithm.crc_tab;	/* Use a precomputed, if it exists */
+  bool local_table = false;
+  if (crc64_table == NULL)
+    {				/* No luck, create a table */
+      crc64_table = init_crc64_tab (&algorithm);
+      if (crc64_table == NULL)
+	{
+	  einfo (_("%F%P: can not allocate memory for CRC table: %E\n"));
+	  return;
+	}
+      local_table = true;
+    }
+  print_hash64_table (&algorithm);
+  for (bfd_vma i = 0; i < 256; i++)
+    {
+      bfd_vma elem = crc64_table[i];
+      if (big_endian)
+	{
+	  elem = __builtin_bswap64 (elem);
+	}
+      if (link_info.big_endian)
+	{
+	  elem = __builtin_bswap64 (elem);
+	}
+
+      lang_add_data (QUAD, exp_intop (elem));
+    }
+  if (local_table)
+    free (crc64_table);
+}
+
+/* ============ DIGEST COMMON functions ======================================*/
+
+void
+lang_add_digest (bfd_vma size,
+		 bfd_vma poly,
+		 bfd_vma initial,
+		 bfd_vma xor_val,
+		 bfd_vma ireflect, bfd_vma oreflect, bfd_vma reciprocal)
+{
+  if (algorithm.crc_algo != no_algo)	/* We only allow one CRC <polynom> */
+    {
+      einfo (_("%X%P: Duplicate digest \"%s\"\n"), "in POLY command");
+      return;
+    }
+
+  algorithm.name = "CUSTOM";
+  algorithm.big_endian = digest_big_endian;
+  if (size == 64)
+    {
+      algorithm.crc_algo = crc_algo_64;
+      algorithm.crc_size = size;
+      algorithm.poly.d64 = poly;	/* Set the polynom */
+      algorithm.initial.d64 = initial;	/* Set seed */
+      algorithm.xor_val.d64 = xor_val;	/* final XOR value */
+      algorithm.ireflect = ireflect;
+      algorithm.oreflect = oreflect;
+      algorithm.crc_tab = NULL;
+      algorithm.reciprocal = reciprocal;
+      algorithm.expected.d64 = 0;
+
+      lang_add_crc64_syndrome (&algorithm);
+    }
+  else if (size == 32)
+    {
+      algorithm.crc_algo = crc_algo_32;
+      algorithm.crc_size = size;
+      algorithm.poly.d32._0 = poly;	/* Set the polynom */
+      algorithm.initial.d32._0 = initial;	/* Set seed */
+      algorithm.xor_val.d32._0 = xor_val;	/* final XOR value */
+      algorithm.ireflect = ireflect;
+      algorithm.oreflect = oreflect;
+      algorithm.crc_tab = NULL;
+      algorithm.reciprocal = reciprocal;
+      algorithm.expected.d32._0 = 0;
+      lang_add_crc32_syndrome (&algorithm);
+    }
+  else
+    {
+      einfo (_("%F%P: Illegal Size in DIGEST: %E\n"));
+      return;
+    }
+}
+
+static bool
+id_start_char (char c)
+{
+  bool OK = false;
+  if (('a' <= c) && (c <= 'z'))
+    OK |= true;
+  if (('A' <= c) && (c <= 'Z'))
+    OK |= true;
+  if ('_' == c)
+    OK |= true;
+  if ('-' == c)
+    OK |= true;
+  if ('.' == c)
+    OK |= true;
+  return OK;
+}
+
+static bool
+id_char (char c)
+{
+  bool OK = false;
+  if (('0' <= c) && (c <= '9'))
+    OK |= true;
+  OK |= id_start_char (c);
+  return OK;
+}
+
+const char *
+lang_get_label (const char *label, bool *big_endian)
+{
+  char *newlabel;
+  const char *p = &label[1];
+  char c;
+
+  *big_endian = false;		/* unless told otherwise */
+  if (command_line.endian == ENDIAN_BIG)
+    {
+      *big_endian = true;
+    }
+  if (command_line.endian == ENDIAN_LITTLE)
+    {
+      *big_endian = false;
+    }
+  c = *label;
+
+  if (!id_start_char (c))
+    {
+      einfo (_("%X%P: Illegal label \"%s\" in digest command\n"), label);
+      return "__CRC_LABEL__";
+    }
+
+  for (uint32_t i = 1; *p; i++)	/* ignore '.' in first character */
+    {
+      c = *p;
+      if (c == '#')
+	{
+	  bool bad_endian = false;
+	  newlabel = strndup (label, i);	/* Memory leak */
+	  p++;
+	  if (strlen (p) == 2)
+	    {
+	      char c0 = *p++;
+	      char c1 = *p;
+	      bool be = ((c0 == 'B') || (c0 == 'b')) &
+		((c1 == 'E') || (c1 == 'e'));
+	      bool le = ((c0 == 'L') || (c0 == 'l')) &
+		((c1 == 'E') || (c1 == 'e'));
+	      if (be)
+		{
+		  *big_endian = true;
+		}
+	      else if (le)
+		{
+		  *big_endian = false;
+		}
+	      else
+		{
+		  bad_endian = true;
+		}
+	    }
+	  else
+	    {
+	      bad_endian = true;
+	    }
+	  if (bad_endian)
+	    {
+	      einfo (_("%X%P: bad 'endian' \"%s\" in digest label\n"), label);
+	    }
+	  return newlabel;
+	}
+      else if (!id_char (c))
+	{
+	  einfo (_("%X%P: Illegal label \"%s\" in digest command\n"), label);
+	  return "__CRC_LABEL__";
+	}
+      else
+	{
+	  p++;
+	}
+    }
+  return label;
+}
+
+bool
+lang_set_digest (char *digest)
+{
+  if (algorithm.crc_algo != no_algo)	/* We only allow one CRC <polynom> */
+    {
+      einfo (_("%X%P: Duplicate digest \"%s\"\n"), digest);
+      return false;
+    }
+
+  for (poly_t a = (poly_t) 0; a < MAXALGO; a++)
+    {
+#if (DEBUG_CRC == 1)
+      printf ("Comparing \"%s\" with \"%s\": ", digest, algorithms[a].name);
+#endif
+      if (!strcmp (digest, algorithms[a].name))
+	{
+#if (DEBUG_CRC == 1)
+	  printf ("OK\n");
+#endif
+	  memcpy (&algorithm, &algorithms[a], sizeof (algorithm_desc_t));
+	  algorithm.big_endian = digest_big_endian;
+	  if (algorithm.crc_size == 64)
+	    {
+	      lang_add_crc64_syndrome (&algorithm);
+	    }
+	  else if (algorithm.crc_size == 32)
+	    {
+	      lang_add_crc32_syndrome (&algorithm);
+	    }
+
+	  return true;
+	}
+#if (DEBUG_CRC == 1)
+      else
+	{
+	  printf ("FAIL\n");
+	}
+#endif
+    }
+  einfo (_("%X%P: Unknown digest \"%s\"\n"), digest);
+  return false;
+}
+
+void
+lang_add_digest_table (bool big_endian)
+{
+  if (algorithm.crc_algo == crc_algo_32)
+    {
+      lang_add_crc32_table (big_endian);
+    }
+  else if (algorithm.crc_algo == crc_algo_64)
+    {
+      lang_add_crc64_table (big_endian);
+    }
+}
+
+/* ============ CRC DEBUG functions ==========================================*/
+
+#if (DEBUG_CRC == 1)
+static void
+debug_hex (char *prompt, unsigned char *section, bfd_vma address, bfd_vma sz)
+{
+  bfd_vma *vma_section = (bfd_vma *) section;
+  bfd_vma size = (sz) / sizeof (bfd_vma);
+  printf ("%s:\n", prompt);
+  for (bfd_vma i = 0; i < size; i += 8)
+    {
+      printf ("0x%08lx: 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
+	      address + (i * sizeof (bfd_vma)),
+	      vma_section[i + 0],
+	      vma_section[i + 1], vma_section[i + 2], vma_section[i + 3]);
+    }
+}
+
+static void
+debug_crc_header (char *prompt)
+{
+  debug_hex (prompt, text_contents, text_section->vma, 64);
+}
+
+static void
+debug_crc_update (bfd_vma crc, bfd_vma crc_addr)
+{
+  printf ("CRC [0x%016lx] update at 0x%08lx succeeded\n", crc, crc_addr);
+}
+
+static bool get_text_section_contents (void);
+static void
+debug_full_textsection (void)
+{
+
+  /* In order to see the updated content, we have to fetch it again */
+
+  if (!get_text_section_contents ())
+    {
+      debug_crc_header ("After CRC");
+      debug_hex ("Full Section After CRC",
+		 text_contents, text_section->vma, text_section->size);
+      free (text_contents);
+    }
+}
+
+
+static void
+print_crc64_algorithm (algorithm_desc_t * a, const unsigned char *crc_data,
+		       uint64_t crc)
+{
+  printf ("64:%-16s, data=\"%s\", ", a->name, crc_data);
+  printf ("poly=0x%016lx i=0x%1x xor=0x%1x .ir=%u .or=%u .rp=%u ",
+	  a->poly.d64,
+	  a->initial.d32._0 & 0xF,
+	  a->xor_val.d32._0 & 0xF, a->ireflect, a->oreflect, a->reciprocal);
+  printf ("checksum=0x%016lx, expected=0x%016lx\n", crc, a->expected.d64);
+}
+
+static void
+print_section (asection * a)
+{
+  uint32_t len = strlen (a->name);
+  char *name = malloc (len + 4);
+  char *p = name;
+  if (p != NULL)
+    {
+      *p++ = '"';
+      for (uint32_t i = 0; i < len; i++)
+	{
+	  *p++ = a->name[i];
+	}
+      *p++ = '"';
+      *p++ = ':';
+      *p++ = '\0';
+    }
+  else
+    {
+      p = "\"?\"";
+    }
+  printf ("%-20s [0x%08lx .. 0x%08lx]\n", name, a->lma, a->lma + a->size - 1);
+  free (name);
+}
+
+static void
+print_section_list (void)
+{
+  bfd *list = link_info.output_bfd;
+  asection *elem;
+  if (strcmp (digest_section, ".foo"))
+    return;
+
+  for (elem = list->sections; elem != NULL; elem = elem->next)
+    {
+      if (elem->name != NULL)
+	{
+	  print_section (elem);
+	}
+    }
+}
+
+#else
+#define	debug_hex(p,s,a,sz)
+#define debug_crc_header(p)
+#define debug_crc_update(c, a)
+#define debug_full_textsection()
+#define print_section(a)
+#define print_section_list()
+#endif
+
+/* ============ Access functions for inserting checksum in text section=======*/
+
+static bool
+get_section_by_address (bfd_vma addr)
+{
+  bfd *list = link_info.output_bfd;
+  for (asection * elem = list->sections; elem != NULL; elem = elem->next)
+    {
+      bfd_vma lma = elem->lma;
+      bfd_vma end = lma + elem->size;
+
+      if ((addr >= lma) && (addr < end))
+	{
+	  digest_section = elem->name;
+	  return true;
+	}
+    }
+  return false;
+}
+
+static bool
+get_text_section_contents (void)
+{
+  /*
+   * Get the '.text' section
+   * Is there a risk that CRC needs to be calculated on more than .text?
+   * We do not support that...
+   */
+  print_section_list ();
+
+  text_section =
+    bfd_get_section_by_name (link_info.output_bfd, digest_section);
+  if (text_section == NULL)
+    {
+      einfo (_("%X%P: cannot retrieve '%s' section for CRC calculation\n"),
+	     digest_section);
+      return false;
+    }
+
+  /* Get the contents of the '.text' area so we can calculate the CRC */
+  if (!bfd_malloc_and_get_section (link_info.output_bfd,
+				   text_section->output_section,
+				   (bfd_byte **) & text_contents))
+    {
+      einfo (_("%X%P: '&s' section contents unavailable\n"
+	       "CRC generation aborted\n"), digest_section);
+      return false;
+    }
+
+#if (DEBUG_CRC == 1)
+  print_section (text_section);
+/*
+  printf ("%s: [0x%08lx .. 0x%08lx]\n",
+	  text_section->name,
+	  text_section->lma, text_section->lma + text_section->size - 1);
+ */
+#endif
+  return true;
+}
+
+/* Set variable in the '.text' area */
+static bool
+set_crc32_checksum (uint32_t crc, bfd_vma addr)
+{
+  uint32_t real_crc = crc;
+  if (big_endian_host ())
+    {
+      if (algorithm.big_endian)
+	{
+	  /* We are OK */
+	}
+      else
+	{
+	  real_crc = __builtin_bswap32 (crc);
+	}
+    }
+  else
+    {
+      if (algorithm.big_endian)
+	{
+	  real_crc = __builtin_bswap32 (crc);
+	}
+      else
+	{
+	  /* We are OK */
+	}
+    }
+
+  return (bfd_set_section_contents (link_info.output_bfd,
+				    text_section->output_section,
+				    &real_crc, addr, sizeof (uint32_t)));
+}
+
+static bool
+set_crc64_checksum (uint64_t crc, bfd_vma addr)
+{
+  uint64_t real_crc = crc;
+  if (big_endian_host ())
+    {
+      if (algorithm.big_endian)
+	{
+	  /* We are OK */
+	}
+      else
+	{
+	  real_crc = __builtin_bswap64 (crc);
+	}
+    }
+  else
+    {
+      if (algorithm.big_endian)
+	{
+	  real_crc = __builtin_bswap64 (crc);
+	}
+      else
+	{
+	  /* We are OK */
+	}
+    }
+  /* True if OK */
+  return (bfd_set_section_contents (link_info.output_bfd,
+				    text_section->output_section,
+				    &real_crc, addr, sizeof (uint64_t)));
+}
+
+static bool
+set_crc_checksum (bfd_vma crc, bfd_vma addr, bfd_vma size)
+{
+  bool status;
+  if (size == 64)
+    {
+      status = set_crc64_checksum (crc, addr);
+    }
+  else
+    {
+      status = set_crc32_checksum ((uint32_t) crc, addr);
+    }
+  return status;
+}
+
+static bool
+symbol_lookup (char *name, bfd_vma * val)
+{
+  struct bfd_link_hash_entry *h;
+  *val = 0ull;
+  h = bfd_link_hash_lookup (link_info.hash, name, false, false, true);
+  if (h != NULL)
+    {
+      if (((h->type == bfd_link_hash_defined) ||
+	   (h->type == bfd_link_hash_defweak)) &&
+	  (h->u.def.section->output_section != NULL))
+	{
+	  *val = (h->u.def.value
+		  + bfd_section_vma (h->u.def.section->output_section)
+		  + h->u.def.section->output_offset);
+	  return true;
+	}
+    }
+  return false;
+}
+
+/* ============ CRC common functions =========================================*/
+/*
+ * Multiplexing function for calculating CRC with different algorithms
+ * 'algorithm.crc_algo'
+ */
+static bfd_vma
+calculate_crc (const unsigned char *input_str, size_t num_bytes)
+{
+  if (algorithm.crc_algo == crc_algo_64)
+    {
+      if (algorithm.crc_tab != NULL)
+	{
+	  return calc_crc64 (&algorithm, input_str, num_bytes);
+	}
+    }
+  else if (algorithm.crc_algo == crc_algo_32)
+    {
+      if (algorithm.crc_tab != NULL)
+	{
+	  return calc_crc32 (&algorithm, input_str, num_bytes);
+	}
+    }
+  /* This should never happen */
+  return 0;
+}
+
+static bool
+invalid_crc_parameters (bfd_vma crc_addr,
+			bfd_vma crc_area_start, bfd_vma crc_area_end)
+{
+  bool crc_in_section;
+  bfd_vma crc_size = algorithm.crc_size / 8;
+  /* Get limits of '.text' section */
+  bfd_vma text_start = text_section->lma;
+  bfd_vma text_end = text_section->lma + text_section->size;
+
+  /* All three symbols must be inside the '.text' section */
+  crc_in_section =
+    ((crc_addr >= text_start) && ((crc_addr + crc_size) <= text_end)) &&
+    ((crc_area_start >= text_start) && (crc_area_start <= text_end)) &&
+    ((crc_area_end >= text_start) && (crc_area_end <= text_end));
+
+  if (!crc_in_section)
+    {
+      einfo (_("%X%P: The CRC digest and table should be inside the '%s' "
+	       "section\n"), digest_section);
+      /*
+       * Maybe we should printout the text section start and end
+       * as well as the boundaries of the CRC check area.
+       */
+      return true;
+    }
+
+  /*
+   * CRC checksum must be outside the checked area
+   * We must check that they do not overlap in the beginning
+   */
+  {
+    bool crc_valid = false;
+    if ((crc_addr + crc_size) < crc_area_start)
+      {
+	crc_valid = true;
+      }
+    else if (crc_addr >= crc_area_end)
+      {
+	crc_valid = true;
+      }
+    if (!crc_valid)
+      {
+	einfo (_("%X%P: CRC located inside checked area\n"), NULL);
+	return true;
+      }
+  }
+
+  if (crc_area_start > crc_area_end)
+    {
+      einfo (_("%X%P: CRC area starts after its end location\n"), NULL);
+      return true;
+    }
+
+  return false;
+}
+
+void
+lang_generate_crc (void)
+{
+  bfd_vma crc_addr, crc_area_start, crc_area_end;
+  bfd_vma crc;
+  bool can_do_crc;
+
+  /* Return immediately, if CRC is not requested */
+  if (algorithm.crc_algo == no_algo)
+    return;
+
+  /*
+   * These symbols must be present, for CRC to be generated
+   * They should all have been defined in a CRC## <syndrome> statement
+   * If they are not defined, then there is an internal error.
+   * Should we consider using symbols which cannot be parsed by the linker?
+   * I.E. CRC-64 is never an identifier
+   */
+  can_do_crc = symbol_lookup (CRC_ADDRESS, &crc_addr) &&
+    symbol_lookup (CRC_START, &crc_area_start) &&
+    symbol_lookup (CRC_END, &crc_area_end);
+
+  if (!can_do_crc)
+    {
+      einfo (_("%X%P: Internal Error - __CRC#___ symbols not defined\n"),
+	     NULL);
+      return;
+    }
+
+  if (!get_section_by_address (crc_addr))	/* update digest_section, if needed */
+    {
+      einfo (_("%X%P: The CRC digest and table must be inside the '%s' "
+	       "section\n"), digest_section);
+    }
+
+  if (!get_text_section_contents ())
+    {
+      /* Error messages inside check */
+      return;
+    }
+
+  /* Check that the addresses make sense */
+  if (invalid_crc_parameters (crc_addr, crc_area_start, crc_area_end))
+    {
+      /* Error messages inside check */
+      return;
+    }
+
+  /* Calculate and set the CRC */
+  {
+    /*
+     * The '.text' area does not neccessarily start at 0x00000000,
+     * so we have to shift the indices.
+     */
+    bfd_vma _crc_addr = crc_addr - text_section->vma;
+    bfd_vma _crc_area_start = crc_area_start - text_section->vma;
+    bfd_vma _crc_area_end = crc_area_end - text_section->vma;
+
+
+    /* This is the CRC calculation which we worked so hard for */
+    debug_crc_header ("Before CRC");
+
+    print_hash64_table (&algorithm);
+
+#if (DEBUG_CRC == 1)
+    crc = calculate_crc ((const unsigned char *) "123456789", 9);
+#else
+    crc = calculate_crc (&text_contents[_crc_area_start],
+			 _crc_area_end - _crc_area_start);
+#endif
+
+#if (DEBUG_CRC == 1)
+    printf ("size  = 0x%08u\n", (uint32_t) (_crc_area_end - _crc_area_start));
+    printf ("start = 0x%016lx\n", _crc_area_start);
+    printf ("end   = 0x%016lx\n", _crc_area_end);
+    printf ("crc   = 0x%016lx\n", crc);
+
+    print_crc64_algorithm (&algorithm, &text_contents[_crc_area_start], crc);
+#endif
+
+    /*
+     * The contents of the '.text' section are no longer needed.
+     * It is a copy of the section contents, and will therefore be stale
+     * after we updated the section with the CRC checksum.
+     * Remove it before we set the CRC checksum, to simplify the code logic.
+     */
+    free (text_contents);
+    if (set_crc_checksum (crc, _crc_addr, algorithm.crc_size))
+      {
+	debug_crc_update (crc, crc_addr);
+      }
+    else
+      {
+	einfo (_("%X%P: updating CRC in section '%s' failed\n"),
+	       digest_section);
+      }
+  }
+
+  debug_full_textsection ();
+}
+
+/* ============ END CRC common functions =====================================*/
+
+void
+lang_generate_digest (void)
+{
+  /* Return immediately, if CRC is not requested */
+#if (DEBUG_CRC == 1)
+  printf ("%s: BEGIN\n", __FUNCTION__);
+#endif
+  if (algorithm.crc_algo == no_algo)
+    return;
+
+  /* Handle 32/64-bit CRCs */
+  if ((algorithm.crc_algo == crc_algo_32)
+      || (algorithm.crc_algo == crc_algo_64))
+    {
+      lang_generate_crc ();
+    }
+#if (DEBUG_CRC == 1)
+  printf ("%s: END\n", __FUNCTION__);
+#endif
+}
diff --git a/ld/lddigest.h b/ld/lddigest.h
new file mode 100755
index 00000000000..9f5e5f3fbda
--- /dev/null
+++ b/ld/lddigest.h
@@ -0,0 +1,183 @@
+/*
+ * Library: libcrc
+ * Author:  Lammert Bies, Ulf Samuelsson
+ *
+ * This file is licensed under the MIT License as stated below
+ *
+ * Copyright (c) 2016 Lammert Bies
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef LDDIGEST_H
+#define LDDIGEST_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "bfd.h"
+
+#define	CRC_POLY_64_ECMA	0x42F0E1EBA9EA3693ull	/* Normal */
+#define	CRC_POLY_64_ECMA_EXP	0x6C40DF5F0B497347ull	/* CRC when testing "123456789" */
+#define	CRC_POLY_64_ECMA_R	0xC96C5795D7870F42ull	/* Reversed */
+
+#define	CRC_POLY_64_ISO		0x000000000000001Bull	/* Normal */
+#define	CRC_POLY_64_ISO_EXP	0xB90956C775A41001ull	/* CRC when testing "123456789" */
+#define	CRC_POLY_64_ISO_R	0xD800000000000000ull	/* Reversed */
+
+#define	CRC_POLY_64_WE		0x42F0E1EBA9EA3693ull	/* Normal */
+#define	CRC_POLY_64_WE_EXP	0x62EC59E3F1A4F00Aull	/* CRC when testing "123456789" */
+
+#define	CRC_POLY_64_XZ		0x42F0E1EBA9EA3693ull	/* Normal */
+#define	CRC_POLY_64_XZ_EXP	0x995DC9BBDF1939FAull	/* CRC when testing "123456789" */
+
+#define	CRC_START_64		0x0000000000000000ull
+#define	CRC_START_64_ECMA	0x0000000000000000ull
+#define	CRC_START_64_WE		0xFFFFFFFFFFFFFFFFull
+#define	CRC_START_64_INV	0xFFFFFFFFFFFFFFFFull
+#define	CRC_END_64		0x0000000000000000ull
+#define	CRC_END_64_INV		0xFFFFFFFFFFFFFFFFull
+
+#define	CRC_START_32		0xFFFFFFFFul
+#define	CRC_END_32		0xFFFFFFFFul
+
+#define	CRC64_ADDRESS		"___CRC64___"
+#define	CRC64_START		"___CRC64_START___"
+#define	CRC64_END		"___CRC64_END___"
+#define	CRC64_TABLE		"___CRC64_TABLE___"
+
+#define	CRC_POLY_32		0x04C11DB7ul	/* Normal */
+#define	CRC_POLY_32_R		0xEDB88320ul	/* Reversed */
+
+#define	CRC_START_32_INV	0xFFFFFFFFul
+#define	CRC_END_32_INV    0xFFFFFFFFul
+
+#define	CRC32_ADDRESS		"___CRC32___"
+#define	CRC32_START		"___CRC32_START___"
+#define	CRC32_END		"___CRC32_END___"
+#define	CRC32_TABLE		"___CRC32_TABLE___"
+
+typedef enum algorithm
+{
+  no_algo = 0,
+  sha_algo_1 = 1,
+  crc_algo_32 = 4,
+  crc_algo_64 = 8,
+  sha_algo_256 = 256,
+  sha_algo_512
+} algo_t;
+
+typedef enum
+{
+  CRC64_ECMA,
+  CRC64_WE,
+  CRC64_XZ,
+  CRC64_ISO,
+  CRC64_ISO_R,
+  CRC32,
+  MAXALGO
+} poly_t;
+
+typedef struct
+{
+  uint8_t _0;
+  uint8_t _1;
+  uint8_t _2;
+  uint8_t _3;
+  uint8_t _4;
+  uint8_t _5;
+  uint8_t _6;
+  uint8_t _7;
+} uint8_ut;
+
+typedef struct
+{
+  uint16_t _0;
+  uint16_t _1;
+  uint16_t _2;
+  uint16_t _3;
+} uint16_ut;
+
+typedef struct
+{
+  uint32_t _0;
+  uint32_t _1;
+} uint32_ut;
+
+typedef union
+{
+  uint64_t d64;
+  uint32_ut d32;
+  uint16_ut d16;
+  uint8_ut d8;
+} int_t;
+
+typedef struct
+{
+  algo_t crc_algo;
+  uint32_t crc_size;
+  const char *name;
+  int_t poly;
+  int_t initial;
+  int_t xor_val;
+  bool ireflect;
+  bool oreflect;
+  bool reciprocal;
+  void *crc_tab;
+  int_t expected;
+  bool big_endian;
+} algorithm_desc_t;
+
+extern char *CRC_ADDRESS;
+extern char *CRC_START;
+extern char *CRC_END;
+extern char *CRC_TABLE;
+extern const algorithm_desc_t algorithms[];
+extern algorithm_desc_t algorithm;
+
+extern const char *digest_label;
+extern bool digest_big_endian;
+extern bool polynome_valid;
+
+/* CRC-32 */
+extern uint32_t *init_crc32_tab (algorithm_desc_t * dsc);
+extern uint32_t calc_crc32
+  (algorithm_desc_t * dsc, const unsigned char *input_str, size_t num_bytes);
+extern void lang_add_crc32_syndrome (algorithm_desc_t * a);
+
+/* CR-64 */
+extern bfd_vma *init_crc64_tab (algorithm_desc_t * dsc);
+extern bfd_vma calc_crc64
+  (algorithm_desc_t * dsc, const unsigned char *input_str, size_t num_bytes);
+extern void lang_add_crc64_syndrome (algorithm_desc_t * a);
+
+extern void lang_add_digest (bfd_vma size,
+			     bfd_vma poly,
+			     bfd_vma initial,
+			     bfd_vma xor_val,
+			     bfd_vma ireflect,
+			     bfd_vma oreflect, bfd_vma reciprocal);
+extern bool lang_set_digest (char *digest);
+extern void lang_add_digest_table (bool big_endian);
+extern const char *lang_get_label (const char *label, bool *big_endian);
+extern void lang_generate_crc (void);
+extern void lang_generate_digest (void);
+
+#endif /* LDDIGEST_H */
diff --git a/ld/lddigest_tab.c b/ld/lddigest_tab.c
new file mode 100644
index 00000000000..4f5db10c997
--- /dev/null
+++ b/ld/lddigest_tab.c
@@ -0,0 +1,136 @@
+/* Linker command language support.
+   Copyright (C) 1991-2023 Ulf Samuelsson <ulf@emagii.com>
+
+   This file is part of the GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "safe-ctype.h"
+#include "obstack.h"
+#include "bfdlink.h"
+#include "ctf-api.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldexp.h"
+#include "ldlang.h"
+#include <ldgram.h>
+#include "ldlex.h"
+#include "ldmisc.h"
+#include "lddigest.h"
+
+const algorithm_desc_t algorithms[MAXALGO+1] =
+{
+  [CRC64_ECMA] =
+	{
+		crc_algo_64, 64, "CRC64-ECMA",
+		.poly.d64 = CRC_POLY_64_ECMA,
+		.initial.d64 = CRC_START_64,
+		.xor_val.d64 = CRC_END_64,
+		.ireflect = false,
+		.oreflect = false,
+		.reciprocal = false,
+		.crc_tab = NULL,
+		.expected.d64 = 0x6c40df5f0b497347
+	},
+  [CRC64_WE] =
+	{
+		crc_algo_64, 64, "CRC64-WE",
+		.poly.d64 = CRC_POLY_64_WE,
+		.initial.d64 = CRC_START_64_INV,
+		.xor_val.d64 = CRC_END_64_INV,
+		.ireflect = false,
+		.oreflect = false,
+		.reciprocal = false,
+		.crc_tab = NULL,
+		.expected.d64 = 0x62ec59e3f1a4f00a
+	},
+  [CRC64_XZ] =
+	{
+		crc_algo_64, 64, "CRC64-XZ",
+		.poly.d64 = CRC_POLY_64_XZ,
+		.initial.d64 = CRC_START_64_INV,
+		.xor_val.d64 = CRC_END_64_INV,
+		.ireflect = true,
+		.oreflect = true,
+		.reciprocal = false,
+		.crc_tab = NULL,
+		.expected.d64 = 0x995dc9bbdf1939fa
+	},
+  [CRC64_ISO] =
+	{
+		crc_algo_64, 64, "CRC64-GO-ISO",
+		.poly.d64 = CRC_POLY_64_ISO,
+		.initial.d64 = CRC_START_64_INV,
+		.xor_val.d64 = CRC_END_64_INV,
+		.ireflect = true,
+		.oreflect = true,
+		.reciprocal = false,
+		.crc_tab = NULL,
+		.expected.d64 = 0xb90956c775a41001
+	},
+  [CRC64_ISO_R] =
+	{
+		crc_algo_64, 64, "CRC64-GO-ISO-R",
+		.poly.d64 = CRC_POLY_64_ISO,
+		.initial.d64 = CRC_START_64_INV,
+		.xor_val.d64 = CRC_END_64_INV,
+		.ireflect = false,
+		.oreflect = false,
+		.reciprocal = true,
+		.crc_tab = NULL,
+		.expected.d64 = 0xb90956c775a41001
+	},
+  [CRC32] =
+	{
+		crc_algo_32, 32, "CRC32",
+		.poly.d32._0 = CRC_POLY_32,
+		.initial.d64 = CRC_START_32_INV,
+		.xor_val.d32._0 = CRC_END_32_INV,
+		.ireflect = true,
+		.oreflect = true,
+		.reciprocal = false,
+		.crc_tab = NULL,
+		.expected.d64 = 0xCBF43926
+	},
+  [MAXALGO] =
+	{
+		no_algo, 0, "",
+		.poly.d64 = 0,
+		.initial.d64 = 0,
+		.xor_val.d64 = 0,
+		.ireflect = false,
+		.oreflect = false,
+		.reciprocal = false,
+		.crc_tab = NULL,
+		.expected.d64 = 0
+	}
+};
+
+algorithm_desc_t algorithm =
+{
+		no_algo, 0, "",
+		.poly.d64 = 0,
+		.initial.d64 = 0,
+		.xor_val.d64 = 0,
+		.ireflect = false,
+		.oreflect = false,
+		.reciprocal = false,
+		.crc_tab = NULL,
+		.expected.d64 = 0
+};
diff --git a/ld/ldreflect.c b/ld/ldreflect.c
new file mode 100644
index 00000000000..0601e2a8c1b
--- /dev/null
+++ b/ld/ldreflect.c
@@ -0,0 +1,99 @@
+/* Linker command language support.
+   Copyright (C) 1991-2023 Ulf Samuelsson <ulf@emagii.com>
+
+   This file is part of the GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include "ldreflect.h"
+
+uint8_t reflect_tab[256] = {
+  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+  0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+  0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+  0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+  0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+  0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+  0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+  0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+  0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+  0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+  0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+  0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+  0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+  0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+  0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+  0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+  0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+  0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+  0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+  0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+  0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+  0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+  0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+  0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+  0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+};
+
+uint8_t
+reflect8 (uint8_t val)
+{
+  return reflect_tab[val];
+}
+
+uint16_t
+reflect16 (uint16_t val)
+{
+  uint16_t result;
+  result = ((uint16_t) reflect_tab[(val >> 0) & 0xFF]) << 8;
+  result |= ((uint16_t) reflect_tab[(val >> 8) & 0xFF]) << 0;
+  return result;
+}
+
+uint32_t
+reflect32 (uint32_t val)
+{
+  uint32_t result;
+  result = ((uint32_t) reflect_tab[(val >> 0) & 0xFF]) << 24;
+  result |= ((uint32_t) reflect_tab[(val >> 8) & 0xFF]) << 16;
+  result |= ((uint32_t) reflect_tab[(val >> 16) & 0xFF]) << 8;
+  result |= ((uint32_t) reflect_tab[(val >> 24) & 0xFF]) << 0;
+  return result;
+}
+
+uint64_t
+reflect64 (uint64_t val)
+{
+  uint64_t result;
+  result = ((uint64_t) reflect_tab[(val >> 0) & 0xFF]) << 56;
+  result |= ((uint64_t) reflect_tab[(val >> 8) & 0xFF]) << 48;
+  result |= ((uint64_t) reflect_tab[(val >> 16) & 0xFF]) << 40;
+  result |= ((uint64_t) reflect_tab[(val >> 24) & 0xFF]) << 32;
+  result |= ((uint64_t) reflect_tab[(val >> 32) & 0xFF]) << 24;
+  result |= ((uint64_t) reflect_tab[(val >> 40) & 0xFF]) << 16;
+  result |= ((uint64_t) reflect_tab[(val >> 48) & 0xFF]) << 8;
+  result |= ((uint64_t) reflect_tab[(val >> 56) & 0xFF]) << 0;
+  return result;
+}
diff --git a/ld/ldreflect.h b/ld/ldreflect.h
new file mode 100644
index 00000000000..a3f834d0acc
--- /dev/null
+++ b/ld/ldreflect.h
@@ -0,0 +1,37 @@
+/*
+ * File:    reflect.h
+ * Author:  Ulf Samuelsson <ulf@emagii.com>
+ *
+ * This file is licensed under the MIT License as stated below
+ *
+ * Copyright (c) 2013 Ulf Samuelsson (ulf@emagii.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef REFLECT_H
+#define REFLECT_H
+
+uint8_t reflect8 (uint8_t val);
+uint16_t reflect16 (uint16_t val);
+uint32_t reflect32 (uint32_t val);
+uint64_t reflect64 (uint64_t val);
+
+#endif /* REFLECT_H */
