920 lines
21 KiB
C
920 lines
21 KiB
C
/* 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 (int 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;
|
|
|
|
/* Reserve room for the ECC value. */
|
|
lang_add_data (QUAD, exp_intop (0));
|
|
|
|
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)
|
|
{
|
|
/* Use a precomputed table, if one exists. */
|
|
uint64_t *crc64_table = algorithm.crc_tab;
|
|
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 (int i = 0; i < 256; i++)
|
|
{
|
|
uint64_t elem = crc64_table[i];
|
|
|
|
if (big_endian)
|
|
elem = __builtin_bswap64 (elem);
|
|
|
|
if (link_info.big_endian)
|
|
elem = __builtin_bswap64 (elem);
|
|
|
|
if (sizeof (bfd_vma) >= QUAD_SIZE)
|
|
lang_add_data (QUAD, exp_intop (elem));
|
|
else
|
|
{
|
|
lang_add_data (LONG, exp_intop (elem >> 32));
|
|
lang_add_data (LONG, 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 (uint64_t 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 uint64_t
|
|
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;
|
|
uint64_t 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
|
|
}
|