diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..201f04c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "3rdparty/libfort"] + path = 3rdparty/libfort + url = https://git.shimatta.de/3rd-party/libfort diff --git a/3rdparty/libfort b/3rdparty/libfort new file mode 160000 index 0000000..4123716 --- /dev/null +++ b/3rdparty/libfort @@ -0,0 +1 @@ +Subproject commit 41237162a9bd34a30a88069ee4e230584ae8d674 diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ae1a57..31299e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") diff --git a/include/patchelfcrc/named_crcs.h b/include/patchelfcrc/named_crcs.h new file mode 100644 index 0000000..33c52a2 --- /dev/null +++ b/include/patchelfcrc/named_crcs.h @@ -0,0 +1,23 @@ +#ifndef _NAMED_CRCS_H_ +#define _NAMED_CRCS_H_ + +#include +#include + +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_ */ diff --git a/main.c b/main.c index 3b9b89c..dc8578c 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include #include #define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__); @@ -14,23 +17,63 @@ const char *argp_program_bug_address = ""; 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; } diff --git a/named_crcs.c b/named_crcs.c new file mode 100644 index 0000000..253a4f3 --- /dev/null +++ b/named_crcs.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#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; +}