From: Ulf Samuelsson Date: Mon, 6 Mar 2023 13:31:56 +0000 (+0100) Subject: DIGEST: calculation X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5243990191e683d5066d3dd622c76deaba0bf15c;p=binutils-gdb.git DIGEST: calculation Signed-off-by: Ulf Samuelsson --- 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 + + 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 +#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 */ + { + 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 */ + { + 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## 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 +#include +#include +#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 + + 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 +#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 + + 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 +#include +#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 + * + * 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 */