Implement STRUCT output format
This commit is contained in:
parent
fcbc8890a4
commit
6f0e4d4c8e
127
elfpatch.c
127
elfpatch.c
@ -10,6 +10,8 @@
|
|||||||
#include <gelf.h>
|
#include <gelf.h>
|
||||||
#include <linklist-lib/singly-linked-list.h>
|
#include <linklist-lib/singly-linked-list.h>
|
||||||
#include <fort.h>
|
#include <fort.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <patchelfcrc/crc-output-struct.h>
|
||||||
|
|
||||||
struct elf_section {
|
struct elf_section {
|
||||||
GElf_Shdr section_header;
|
GElf_Shdr section_header;
|
||||||
@ -262,6 +264,9 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly)
|
|||||||
{
|
{
|
||||||
struct elfpatch *ep;
|
struct elfpatch *ep;
|
||||||
|
|
||||||
|
/* This is important to guarantee structure packing behavior */
|
||||||
|
CRC_OUT_CHECK_STRUCT_SIZES;
|
||||||
|
|
||||||
if (!path) {
|
if (!path) {
|
||||||
print_err("Internal error while opeing ELF file. No path specified\n");
|
print_err("Internal error while opeing ELF file. No path specified\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -406,12 +411,48 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t calculate_needed_space_for_crcs(elfpatch_handle_t *ep,
|
||||||
|
enum crc_format format,
|
||||||
|
bool check_start_magic, bool check_end_magic,
|
||||||
|
uint8_t crc_size_bytes, size_t crc_count)
|
||||||
|
{
|
||||||
|
size_t needed_space = 0ull;
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case FORMAT_BARE:
|
||||||
|
needed_space = crc_size_bytes * crc_count;
|
||||||
|
break;
|
||||||
|
case FORMAT_STRUCT:
|
||||||
|
/* Calculate space for CRCs including sentinel struct at the end */
|
||||||
|
needed_space = (crc_count + 1) *
|
||||||
|
(ep->class == ELFCLASS32
|
||||||
|
? sizeof(struct crc_out_struct_32bit)
|
||||||
|
: sizeof(struct crc_out_struct_64bit));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
needed_space = 0;
|
||||||
|
print_err("Unsupported CRC output format\n");
|
||||||
|
}
|
||||||
|
/* Add existing magic numbers to required space */
|
||||||
|
if (check_start_magic) {
|
||||||
|
needed_space += 4u;
|
||||||
|
/* Account for paading after 32 bit magic value in case of structure usage on 64 bit systems */
|
||||||
|
if (ep->class == ELFCLASS64 && format == FORMAT_STRUCT)
|
||||||
|
needed_space += 4u;
|
||||||
|
}
|
||||||
|
if (check_end_magic)
|
||||||
|
needed_space += 4u;
|
||||||
|
|
||||||
|
return needed_space;
|
||||||
|
}
|
||||||
|
|
||||||
int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, const SlList *section_name_list,
|
int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, const SlList *section_name_list,
|
||||||
const uint32_t *crcs, uint8_t crc_size_bits, uint32_t start_magic, uint32_t end_magic,
|
const uint32_t *crcs, uint8_t crc_size_bits, uint32_t start_magic, uint32_t end_magic,
|
||||||
bool check_start_magic, bool check_end_magic, enum crc_format format, bool little_endian)
|
bool check_start_magic, bool check_end_magic, enum crc_format format, bool little_endian)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
struct elf_section *output_section;
|
struct elf_section *output_section;
|
||||||
|
struct elf_section *input_section;
|
||||||
Elf_Data *output_sec_data;
|
Elf_Data *output_sec_data;
|
||||||
const SlList *iter;
|
const SlList *iter;
|
||||||
size_t needed_space;
|
size_t needed_space;
|
||||||
@ -419,6 +460,8 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section,
|
|||||||
uint8_t crc_size_bytes;
|
uint8_t crc_size_bytes;
|
||||||
uint8_t *sec_bytes;
|
uint8_t *sec_bytes;
|
||||||
size_t idx;
|
size_t idx;
|
||||||
|
struct crc_out_struct_32bit crc_32bit;
|
||||||
|
struct crc_out_struct_64bit crc_64bit;
|
||||||
|
|
||||||
ret_val_if_ep_err(ep, -1000);
|
ret_val_if_ep_err(ep, -1000);
|
||||||
|
|
||||||
@ -429,11 +472,6 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format != FORMAT_BARE) {
|
|
||||||
print_err("Currently only bare format is supported!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All pointer parameters are required */
|
/* All pointer parameters are required */
|
||||||
if (!section || !section_name_list || !crcs)
|
if (!section || !section_name_list || !crcs)
|
||||||
return -1000;
|
return -1000;
|
||||||
@ -470,22 +508,17 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section,
|
|||||||
/* Calculate Bytes needed for CRC */
|
/* Calculate Bytes needed for CRC */
|
||||||
crc_size_bytes = (crc_size_bits + 7u) / 8u;
|
crc_size_bytes = (crc_size_bits + 7u) / 8u;
|
||||||
crc_count = sl_list_length(section_name_list);
|
crc_count = sl_list_length(section_name_list);
|
||||||
|
if (crc_count < 1) {
|
||||||
print_debug("CRC requires %u bytes.\n", (unsigned int)crc_size_bytes);
|
/* No CRCs to patch... */
|
||||||
switch (format) {
|
ret = -1;
|
||||||
case FORMAT_BARE:
|
print_err("No CRCs to patch. This is probably an internal error.\n");
|
||||||
needed_space = crc_size_bytes * crc_count;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
needed_space = 0;
|
|
||||||
print_err("Unsupported CRC output format\n");
|
|
||||||
goto ret_err;
|
goto ret_err;
|
||||||
}
|
}
|
||||||
/* Add existing magic numbers to required space */
|
|
||||||
if (check_start_magic)
|
print_debug("Single CRC requires %u bytes.\n", (unsigned int)crc_size_bytes);
|
||||||
needed_space += 4u;
|
|
||||||
if (check_end_magic)
|
needed_space = calculate_needed_space_for_crcs(ep, format, check_start_magic, check_end_magic, crc_size_bytes,
|
||||||
needed_space += 4u;
|
crc_count);
|
||||||
|
|
||||||
print_debug("Required space for %zu CRCs %s: %zu (available: %zu)\n",
|
print_debug("Required space for %zu CRCs %s: %zu (available: %zu)\n",
|
||||||
crc_count,
|
crc_count,
|
||||||
@ -496,13 +529,15 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section,
|
|||||||
if (needed_space > output_sec_data->d_size) {
|
if (needed_space > output_sec_data->d_size) {
|
||||||
print_err("Not enough space in section. %zu bytes available but %zu needed\n",
|
print_err("Not enough space in section. %zu bytes available but %zu needed\n",
|
||||||
output_sec_data->d_size, needed_space);
|
output_sec_data->d_size, needed_space);
|
||||||
|
ret = -1;
|
||||||
|
goto ret_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks finished. Write data to output section */
|
/* Checks finished. Write data to output section */
|
||||||
|
|
||||||
if (format == FORMAT_BARE) {
|
if (format == FORMAT_BARE) {
|
||||||
if (check_start_magic)
|
if (check_start_magic)
|
||||||
sec_bytes += 4;
|
sec_bytes += 4u;
|
||||||
|
|
||||||
for (iter = section_name_list, idx = 0; iter; iter = sl_list_next(iter), idx++) {
|
for (iter = section_name_list, idx = 0; iter; iter = sl_list_next(iter), idx++) {
|
||||||
print_debug("Write CRC 0x%08x (%u bytes) for section %s\n", crcs[idx],
|
print_debug("Write CRC 0x%08x (%u bytes) for section %s\n", crcs[idx],
|
||||||
(unsigned int)crc_size_bytes,
|
(unsigned int)crc_size_bytes,
|
||||||
@ -510,6 +545,56 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section,
|
|||||||
write_crc_to_byte_array(sec_bytes, crcs[idx], crc_size_bytes, little_endian);
|
write_crc_to_byte_array(sec_bytes, crcs[idx], crc_size_bytes, little_endian);
|
||||||
sec_bytes += crc_size_bytes;
|
sec_bytes += crc_size_bytes;
|
||||||
}
|
}
|
||||||
|
} else if (format == FORMAT_STRUCT) {
|
||||||
|
if (check_start_magic)
|
||||||
|
sec_bytes += 4u;
|
||||||
|
if (check_start_magic && ep->class == ELFCLASS64)
|
||||||
|
sec_bytes += 4u;
|
||||||
|
|
||||||
|
for (iter = section_name_list, idx = 0; iter; iter = sl_list_next(iter), idx++) {
|
||||||
|
input_section = find_section_in_list(ep->sections, (const char *)iter->data);
|
||||||
|
if (!input_section) {
|
||||||
|
print_err("Internal error. Please report this. %s:%d ", __FILE__, __LINE__);
|
||||||
|
ret = -2;
|
||||||
|
goto ret_err;
|
||||||
|
}
|
||||||
|
print_debug("Write CRC 0x%08x (%u bytes) for section %s.\n", crcs[idx],
|
||||||
|
(unsigned int)crc_size_bytes,
|
||||||
|
iter->data);
|
||||||
|
print_debug("Corresponding input section at 0x%"PRIx64", length: %"PRIu64"\n",
|
||||||
|
(uint64_t)input_section->section_header.sh_addr,
|
||||||
|
(uint64_t)input_section->section_header.sh_size);
|
||||||
|
if (ep->class == ELFCLASS32) {
|
||||||
|
crc_32bit.crc = crcs[idx];
|
||||||
|
crc_32bit.length = (uint32_t)input_section->section_header.sh_size;
|
||||||
|
crc_32bit.start_address = (uint32_t)input_section->section_header.sh_addr;
|
||||||
|
memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit));
|
||||||
|
sec_bytes += sizeof(crc_32bit);
|
||||||
|
} else {
|
||||||
|
/* 64 bit case */
|
||||||
|
crc_64bit.crc = crcs[idx];
|
||||||
|
crc_64bit._unused_dummy = 0ul;
|
||||||
|
crc_64bit.length = (uint64_t)input_section->section_header.sh_size;
|
||||||
|
crc_64bit.start_address = (uint64_t)input_section->section_header.sh_addr;
|
||||||
|
memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit));
|
||||||
|
sec_bytes += sizeof(crc_64bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append sentinel struct */
|
||||||
|
crc_32bit.crc = 0ul;
|
||||||
|
crc_32bit.length = 0ul;
|
||||||
|
crc_32bit.start_address = 0ul;
|
||||||
|
|
||||||
|
crc_64bit.crc = 0ul;
|
||||||
|
crc_64bit.length = 0ull;
|
||||||
|
crc_64bit.start_address = 0ull;
|
||||||
|
|
||||||
|
if (ep->class == ELFCLASS32) {
|
||||||
|
memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit));
|
||||||
|
} else {
|
||||||
|
memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update ELF file */
|
/* Update ELF file */
|
||||||
|
33
include/patchelfcrc/crc-output-struct.h
Normal file
33
include/patchelfcrc/crc-output-struct.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef _CRC_OUTPUT_STRUCT_H_
|
||||||
|
#define _CRC_OUTPUT_STRUCT_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define CRC_OUT_STRUCT_SIZE_32BIT 12u
|
||||||
|
struct crc_out_struct_32bit {
|
||||||
|
uint32_t start_address; /**< @brief Start address of struct*/
|
||||||
|
uint32_t length; /**< @brief Length of section in bytes */
|
||||||
|
uint32_t crc; /**< @brief LSB aligned CRC */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CRC_OUT_STRUCT_SIZE_64BIT 24u
|
||||||
|
struct crc_out_struct_64bit {
|
||||||
|
uint64_t start_address; /**< @brief Start address of struct*/
|
||||||
|
uint64_t length; /**< @brief Length of section in bytes */
|
||||||
|
uint32_t crc; /**< @brief LSB aligned CRC */
|
||||||
|
uint32_t _unused_dummy; /**< @brief Dummy. Do not use, it prevents misalignments */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BUILD_ASSERT(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Statically check sizes of @ref crc_out_struct_32bit and @ref crc_out_struct_64bit
|
||||||
|
* @note Place this at least once in your code to ensure the packing of the structures is correct
|
||||||
|
*/
|
||||||
|
#define CRC_OUT_CHECK_STRUCT_SIZES do { \
|
||||||
|
BUILD_ASSERT(sizeof(struct crc_out_struct_64bit) != CRC_OUT_STRUCT_SIZE_64BIT); \
|
||||||
|
BUILD_ASSERT(sizeof(struct crc_out_struct_32bit) != CRC_OUT_STRUCT_SIZE_32BIT); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _CRC_OUTPUT_STRUCT_H_ */
|
12
main.c
12
main.c
@ -103,6 +103,16 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
|||||||
args->granularity = GRANULARITY_16BIT;
|
args->granularity = GRANULARITY_16BIT;
|
||||||
else if (!strcmp(arg, "word"))
|
else if (!strcmp(arg, "word"))
|
||||||
args->granularity = GRANULARITY_32BIT;
|
args->granularity = GRANULARITY_32BIT;
|
||||||
|
else
|
||||||
|
argp_error(state, "Error parsing granularity: %s\n", arg);
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
if (!strcmp(arg, "bare"))
|
||||||
|
args->format = FORMAT_BARE;
|
||||||
|
else if (!strcmp(arg, "struct"))
|
||||||
|
args->format = FORMAT_STRUCT;
|
||||||
|
else
|
||||||
|
argp_error(state, "Error parsing output format: %s\n", arg);
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
args->output_section = arg;
|
args->output_section = arg;
|
||||||
@ -389,7 +399,7 @@ int main(int argc, char **argv)
|
|||||||
if (elf_patch_write_crcs_to_section(ep, cmd_opts.output_section, cmd_opts.section_list,
|
if (elf_patch_write_crcs_to_section(ep, cmd_opts.output_section, cmd_opts.section_list,
|
||||||
crcs, 32, cmd_opts.start_magic, cmd_opts.end_magic,
|
crcs, 32, cmd_opts.start_magic, cmd_opts.end_magic,
|
||||||
cmd_opts.has_start_magic, cmd_opts.has_end_magic,
|
cmd_opts.has_start_magic, cmd_opts.has_end_magic,
|
||||||
FORMAT_BARE, cmd_opts.little_endian)) {
|
cmd_opts.format, cmd_opts.little_endian)) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user