Implement predefined CRCs and add libfort

This commit is contained in:
Mario Hüttel 2022-08-19 21:58:18 +02:00
parent 199b48d963
commit 3040d8a23f
6 changed files with 217 additions and 11 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "3rdparty/libfort"]
path = 3rdparty/libfort
url = https://git.shimatta.de/3rd-party/libfort

1
3rdparty/libfort vendored Submodule

@ -0,0 +1 @@
Subproject commit 41237162a9bd34a30a88069ee4e230584ae8d674

View File

@ -8,6 +8,7 @@ pkg_check_modules(ELF REQUIRED libelf)
set (CFILES
main.c
version.c
named_crcs.c
)
set(GEN_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated")

View File

@ -0,0 +1,23 @@
#ifndef _NAMED_CRCS_H_
#define _NAMED_CRCS_H_
#include <stdint.h>
#include <stdbool.h>
struct crc_settings {
uint32_t polynomial;
uint32_t xor;
uint32_t start_value;
bool rev;
};
struct named_crc {
const char *name;
struct crc_settings settings;
};
const struct named_crc *reverse_lookup_named_crc(const struct crc_settings *settings);
const struct named_crc *lookup_named_crc(const char *name);
#endif /* _NAMED_CRCS_H_ */

112
main.c
View File

@ -2,6 +2,9 @@
#include <libelf.h>
#include <argp.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <patchelfcrc/named_crcs.h>
#include <patchelfcrc/version.h>
#define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__);
@ -14,23 +17,63 @@
const char *argp_program_bug_address = "<mario.huettel@linux.com>";
enum granularity {
GRANULARITY_BYTE = 1,
GRANULARITY_16BIT,
GRANULARITY_32BIT,
GRANULARITY_BYTE = 8,
GRANULARITY_16BIT = 16,
GRANULARITY_32BIT = 32,
};
enum crc_format {
FORMAT_BARE = 0,
FORMAT_STRUCT,
};
#define ARG_KEY_DRY_RUN (1)
#define ARG_KEY_START_MAGIC (2)
#define ARG_KEY_END_MAGIC (3)
struct command_line_options {
bool little_endian;
bool dry_run;
bool verbose;
enum granularity granularity;
enum crc_format format;
struct crc_settings crc;
bool has_start_magic;
uint32_t start_magic;
bool has_end_magic;
uint32_t end_magic;
};
static error_t parse_opt(int key, char *arg, struct argp_state *state)
{
struct command_line_options *args = (struct command_line_options *)state->input;
switch (key) {
case ARG_KEY_DRY_RUN:
args->dry_run = true;
args->verbose = true;
break;
case ARG_KEY_START_MAGIC:
args->has_start_magic = true;
args->start_magic = strtoul(arg, NULL, 0);
break;
case ARG_KEY_END_MAGIC:
args->has_end_magic = true;
args->end_magic = strtoul(arg, NULL, 0);
break;
case 'l':
args->little_endian = true;
break;
case 'v':
args->verbose = true;
break;
case 'g':
if (!strcmp(arg, "byte"))
args->granularity = GRANULARITY_BYTE;
else if (!strcmp(arg, "halfword"))
args->granularity = GRANULARITY_16BIT;
else if (!strcmp(arg, "word"))
args->granularity = GRANULARITY_32BIT;
break;
default:
return ARGP_ERR_UNKNOWN;
}
@ -41,6 +84,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
static int parse_cmdline_options(int *argc, char ***argv, struct command_line_options *cmd_opts)
{
const int crc_param_group = 1;
error_t err;
if (!argc || !argv)
@ -48,6 +92,18 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op
static struct argp_option options[] = {
{"little-endian", 'l', 0, 0, "Memory image is little endian. Only relevant if granularity is greater than a single byte", 0},
{"granularity", 'g', "GRANULARITY", 0, "Granularity to calculate the CRC for", 0},
{"poly", 'p', "POLYNOMIAL", 0, "Polynomial to use", crc_param_group},
{"start-value", 's', "STARTVALUE", 0, "Start value for CRC calculation", crc_param_group},
{"reversed", 'r', 0, 0, "Bit reversed CRC", crc_param_group},
{"xor-out", 'x', "XORVAL", 0, "XOR the output with XORVAL. Default 0x0", crc_param_group},
{"dry-run", ARG_KEY_DRY_RUN, 0, 0, "Dry run. Caclualate CRCs but do not patch output file. Implicitly activates verbose mode.", 0},
{"verbose", 'v', 0, 0, "Verbose output", 0},
{"section", 'S', "SEC", 0, "Section to calculate CRC for", 2},
{"output-section", 'O', "OUTPUTSEC", 0, "Output section for generated CRCs", 2},
{"crc-format", 'F', "FORMAT", 0, "Output Format for CRCs.", 2},
{"start-magic", ARG_KEY_START_MAGIC, "STARTMAGIC", 0, "Check output section for start magic (uint32)", 2},
{"end-magic", ARG_KEY_END_MAGIC, "STARTMAGIC", 0, "Check output section for start magic (uint32)", 2},
/* Sentinel */
{NULL, 0, 0, 0, NULL, 0}
};
@ -65,18 +121,52 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op
return err ? -1 : 0;
}
int main(int argc, char **argv)
static void prepare_default_opts(struct command_line_options *opts)
{
bool verbose = true;
struct command_line_options cmd_opts;
opts->little_endian = false;
opts->verbose = false;
opts->granularity = GRANULARITY_BYTE;
opts->dry_run = false;
opts->crc.xor = 0UL;
opts->crc.polynomial = 0x04C11DB7UL;
opts->crc.start_value = 0xFFFFFFFFUL;
opts->crc.rev = false;
opts->format = FORMAT_BARE;
opts->has_end_magic = false;
opts->has_start_magic = false;
}
cmd_opts.little_endian = false;
cmd_opts.granularity = GRANULARITY_BYTE;
parse_cmdline_options(&argc, &argv, &cmd_opts);
static void print_verbose_start_info(const struct command_line_options *cmd_opts)
{
bool verbose = cmd_opts->verbose;
const struct named_crc *predef_crc;
print_debug("Start CRC patching\n");
print_debug("Endianess: %s endian\n", (cmd_opts.little_endian ? "little" : "big"));
print_debug("Endianess: %s endian\n", (cmd_opts->little_endian ? "little" : "big"));
print_debug("Granularity: %u bits\n", (unsigned int)cmd_opts->granularity);
if (cmd_opts->has_start_magic)
print_debug("Checking for start magic: 0x%08x\n", (unsigned int)cmd_opts->start_magic);
if (cmd_opts->has_end_magic)
print_debug("Checking for end magic: 0x%08x\n", (unsigned int)cmd_opts->end_magic);
if (cmd_opts->dry_run)
print_debug("Dry run mode selected. Will not touch ELF file.\n");
predef_crc = reverse_lookup_named_crc(&cmd_opts->crc);
if (predef_crc) {
print_debug("Predefined CRC detected: %s\n", predef_crc->name);
}
}
int main(int argc, char **argv)
{
bool verbose;
struct command_line_options cmd_opts;
prepare_default_opts(&cmd_opts);
parse_cmdline_options(&argc, &argv, &cmd_opts);
verbose = cmd_opts.verbose || cmd_opts.dry_run;
print_verbose_start_info(&cmd_opts);
return 0;
}

88
named_crcs.c Normal file
View File

@ -0,0 +1,88 @@
#include <patchelfcrc/named_crcs.h>
#include <stddef.h>
#include <string.h>
#define NAMED_CRC(crc_name, poly, reverse, init, outxor) { \
.name = crc_name, \
.settings = { \
.polynomial = poly, \
.xor = outxor, \
.start_value = init, \
.rev = reverse \
}}
const struct named_crc predefined_crc_table[] = {
NAMED_CRC("crc-8", 0x07, false, 0x00, 0x00),
NAMED_CRC("crc-8-darc", 0x39, true, 0x00, 0x00),
NAMED_CRC("crc-8-i-code", 0x1D, false, 0xFD, 0x00),
NAMED_CRC("crc-8-itu", 0x07, false, 0x55, 0x55),
NAMED_CRC("crc-8-maxim", 0x31, true, 0x00, 0x00),
NAMED_CRC("crc-8-rohc", 0x07, true, 0xFF, 0x00),
NAMED_CRC("crc-8-wcdma", 0x9B, true, 0x00, 0x00),
NAMED_CRC("crc-16", 0x8005, true, 0x0000, 0x0000),
NAMED_CRC("crc-16-buypass", 0x8005, false, 0x0000, 0x0000),
NAMED_CRC("crc-16-dds-110", 0x8005, false, 0x800D, 0x0000),
NAMED_CRC("crc-16-dect", 0x0589, false, 0x0001, 0x0001),
NAMED_CRC("crc-16-dnp", 0x3D65, true, 0xFFFF, 0xFFFF),
NAMED_CRC("crc-16-en-13757", 0x3D65, false, 0xFFFF, 0xFFFF),
NAMED_CRC("crc-16-genibus", 0x1021, false, 0x0000, 0xFFFF),
NAMED_CRC("crc-16-maxim", 0x8005, true, 0xFFFF, 0xFFFF),
NAMED_CRC("crc-16-mcrf4xx", 0x1021, true, 0xFFFF, 0x0000),
NAMED_CRC("crc-16-riello", 0x1021, true, 0x554D, 0x0000),
NAMED_CRC("crc-16-t10-dif", 0x8BB7, false, 0x0000, 0x0000),
NAMED_CRC("crc-16-teledisk", 0xA097, false, 0x0000, 0x0000),
NAMED_CRC("crc-16-usb", 0x8005, true, 0x0000, 0xFFFF),
NAMED_CRC("x-25", 0x1021, true, 0x0000, 0xFFFF),
NAMED_CRC("xmodem", 0x1021, false, 0x0000, 0x0000),
NAMED_CRC("modbus", 0x8005, true, 0xFFFF, 0x0000),
NAMED_CRC("kermit [1]", 0x1021, true, 0x0000, 0x0000),
NAMED_CRC("crc-ccitt-false [1]", 0x1021, false, 0xFFFF, 0x0000),
NAMED_CRC("crc-aug-ccitt [1]", 0x1021, false, 0x1D0F, 0x0000),
NAMED_CRC("crc-24", 0x864CFB, false, 0xB704CE, 0x000000),
NAMED_CRC("crc-24-flexray-a", 0x5D6DCB, false, 0xFEDCBA, 0x000000),
NAMED_CRC("crc-24-flexray-b", 0x5D6DCB, false, 0xABCDEF, 0x000000),
NAMED_CRC("crc-32", 0x04C11DB7, true, 0x00000000, 0xFFFFFFFF),
NAMED_CRC("crc-32-bzip2", 0x04C11DB7, false, 0x00000000, 0xFFFFFFFF),
NAMED_CRC("crc-32c", 0x1EDC6F41, true, 0x00000000, 0xFFFFFFFF),
NAMED_CRC("crc-32d", 0xA833982B, true, 0x00000000, 0xFFFFFFFF),
NAMED_CRC("crc-32-mpeg", 0x04C11DB7, false, 0xFFFFFFFF, 0x00000000),
NAMED_CRC("posix", 0x04C11DB7, false, 0xFFFFFFFF, 0xFFFFFFFF),
NAMED_CRC("crc-32q", 0x814141AB, false, 0x00000000, 0x00000000),
NAMED_CRC("jamcrc", 0x04C11DB7, true, 0xFFFFFFFF, 0x00000000),
NAMED_CRC("xfer", 0x000000AF, false, 0x00000000, 0x00000000),
/* SENTINEL */
{.name = NULL, .settings = {0, 0, 0, false}},
};
const struct named_crc *reverse_lookup_named_crc(const struct crc_settings *settings)
{
const struct named_crc *iter;
const struct named_crc *found = NULL;
for (iter = predefined_crc_table; iter->name; iter++) {
if (iter->settings.polynomial == settings->polynomial &&
iter->settings.rev == settings->rev &&
iter->settings.start_value == settings->start_value &&
iter->settings.xor == settings->xor) {
found = iter;
break;
}
}
return found;
}
const struct named_crc *lookup_named_crc(const char *name)
{
const struct named_crc *iter;
const struct named_crc *found = NULL;
for (iter = predefined_crc_table; iter->name; iter++) {
if (strcmp(iter->name, name)) {
found = iter;
break;
}
}
return found;
}