You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
234 lines
6.9 KiB
C
234 lines
6.9 KiB
C
/* elf2mzip - convert a single LOADable segment ELF file to an MZIP image.
|
|
*
|
|
* (c) 2008 Philippe Vachoon <philippe@cowpig.ca>
|
|
*
|
|
* Licensed under the GNU General Public License v2. See COPYING
|
|
* in the distribution source directory for more information.
|
|
*
|
|
*/
|
|
#include <stdio.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include <types.h>
|
|
|
|
#include <mzip.h>
|
|
#include <elf.h>
|
|
|
|
void usage(const char *name)
|
|
{
|
|
printf("Usage: %s [file in] [file out]\n", name);
|
|
printf("\t[file in] is the file to be converted to MZIP format\n");
|
|
printf("\t[file out] is the name of the output MZIP file\n");
|
|
printf("\nNote: the input ELF file needs a single LOADable section and \n");
|
|
printf(" must be a 32-bit ELF file.\n");
|
|
}
|
|
|
|
int main(const int argc, const char *argv[])
|
|
{
|
|
struct elf32_header elf_hdr;
|
|
struct mzip_header mzip_hdr;
|
|
FILE *fp_in, *fp_out;
|
|
struct stat f_stat;
|
|
bool endian_swap = FALSE;
|
|
int i;
|
|
|
|
printf("elf2mzip version 0.1 - convert ELF files to MZIP files.\n");
|
|
|
|
if (argc < 2) {
|
|
printf("Error: no file arguments specified.\n");
|
|
usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
if ((fp_in = fopen(argv[1], "rb")) == NULL) {
|
|
printf("Error: unable to open specified input file %s.\n",
|
|
argv[1]);
|
|
usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
/* check if the input file exists. If it does, delete it. */
|
|
if (stat(argv[2], &f_stat) != -1) {
|
|
if (unlink(argv[2]) == -1) {
|
|
/* check errno */
|
|
switch (errno) {
|
|
case EACCES:
|
|
printf("Error: insufficient privileges to access the "
|
|
"specified output file %s. Aborting.\n", argv[2]);
|
|
break;
|
|
case EBUSY:
|
|
printf("Error: the specified file %s is currently in use.\n",
|
|
argv[2]);
|
|
break;
|
|
case EPERM:
|
|
printf("Error: the specified file %s is on a read-only file"
|
|
"system.\n", argv[2]);
|
|
break;
|
|
default:
|
|
printf("An unspecified error occurred. Aborting.\n");
|
|
}
|
|
|
|
usage(argv[0]);
|
|
fclose(fp_in);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
if ((fp_out = fopen(argv[2], "wb+")) == NULL) {
|
|
printf("Error: unable to open or create output file %s.\n",
|
|
argv[2]);
|
|
fclose(fp_in);
|
|
usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
mzip_initialize(&mzip_hdr);
|
|
|
|
fseek(fp_in, 0, SEEK_SET);
|
|
|
|
/* read in ELF header */
|
|
fread(&elf_hdr, sizeof(elf_hdr), 1, fp_in);
|
|
|
|
if (elf_hdr.ident[0] != ELF_MAGIC_1 || elf_hdr.ident[1] != ELF_MAGIC_2 ||
|
|
elf_hdr.ident[2] != ELF_MAGIC_3 || elf_hdr.ident[3] != ELF_MAGIC_4)
|
|
{
|
|
printf("The specified input file is not an ELF file. Aborting.\n");
|
|
fclose(fp_in);
|
|
fclose(fp_out);
|
|
usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
if (elf_hdr.ident[ELF_INDEX_CLASS] != ELF_CLASS_32) {
|
|
printf("The specified input file is a 64-bit ELF file. MZIP does not "
|
|
"support 64-bit files for input.");
|
|
fclose(fp_in);
|
|
fclose(fp_out);
|
|
usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
/* determine endianess of the target machine */
|
|
if (elf_hdr.ident[ELF_INDEX_DATA] == ELF_DATA_MSB) endian_swap = TRUE;
|
|
|
|
printf("DEBUG: endian_swap = %d\n", endian_swap);
|
|
|
|
printf("elf_hdr.phnum = %08x\n", elf_hdr.phnum);
|
|
printf("elf_hdr.phoff = %08x\n", elf_hdr.phoff);
|
|
|
|
uint32_t ph_count = endian_swap ? SWAP_16(elf_hdr.phnum) : elf_hdr.phnum;
|
|
uint32_t ph_offset = endian_swap ? SWAP_32(elf_hdr.phoff) : elf_hdr.phoff;
|
|
|
|
printf("DEBUG: segments: 0x%08x; segments offset: 0x%08x\n", ph_count,
|
|
ph_offset);
|
|
|
|
fseek(fp_in, ph_offset, SEEK_SET);
|
|
|
|
int ph_loadable_count = 0;
|
|
uint32_t ph_loc = 0;
|
|
|
|
struct elf32_phdr phdr;
|
|
|
|
for (i = 0; i < ph_count; i++) {
|
|
fread(&phdr, 1, sizeof(struct elf32_phdr), fp_in);
|
|
|
|
uint32_t type = endian_swap ? SWAP_32(phdr.type) : phdr.type;
|
|
|
|
|
|
if (type == ELF_PT_LOAD) {
|
|
ph_loadable_count++;
|
|
ph_loc = ftell(fp_in) - sizeof(struct elf32_phdr);
|
|
}
|
|
}
|
|
|
|
if (ph_loadable_count < 1) {
|
|
printf("No loadable ELF sections were found in the input file.\n"
|
|
"Are you sure this is a loadable image?\n");
|
|
fclose(fp_in);
|
|
fclose(fp_out);
|
|
usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
if (ph_loadable_count > 1) {
|
|
printf("Too many loadable ELF sections were found in the input file. "
|
|
"Found %d sections.\n", ph_loadable_count);
|
|
fclose(fp_in);
|
|
fclose(fp_out);
|
|
usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
/* create an in-memory image of the single section header */
|
|
fseek(fp_in, ph_loc, SEEK_SET);
|
|
fread(&phdr, sizeof(struct elf32_phdr), 1, fp_in);
|
|
|
|
uint32_t im_offset = endian_swap ? SWAP_32(phdr.offset) : phdr.offset;
|
|
uint32_t im_file_size = endian_swap ? SWAP_32(phdr.filesz) :
|
|
phdr.filesz;
|
|
void *image = malloc(im_file_size);
|
|
|
|
printf("DEBUG: allocated %08x byte image\n", im_file_size);
|
|
printf("DEBUG: offset in file: %08x\n", im_offset);
|
|
|
|
|
|
/* seek to offset of data within ELF image, read it in */
|
|
fseek(fp_in, im_offset, SEEK_SET);
|
|
fread(image, 1, im_file_size, fp_in);
|
|
|
|
mzip_hdr.hdr_flags1 = endian_swap ? SWAP_32(0x1u) : 0x1u;
|
|
mzip_hdr.hdr_flags2 = endian_swap ? SWAP_32(0x1u) : 0x1u;
|
|
|
|
mzip_hdr.hdr_version = endian_swap ? SWAP_32(0x1u) : 0x1u;
|
|
mzip_hdr.hdr_entrypt = elf_hdr.entry;
|
|
|
|
mzip_hdr.hdr_header_size = endian_swap ? SWAP_32(0x70u) : 0x70u;
|
|
mzip_hdr.hdr_loader_addr = phdr.paddr;
|
|
mzip_hdr.hdr_code_unpacked_size = phdr.filesz;
|
|
mzip_hdr.hdr_memory_image_size = phdr.memsz;
|
|
|
|
printf("DEBUG: phdr.paddr = %08x\n", phdr.paddr);
|
|
printf("DEBUG: phdr.filesz = %08x\n", phdr.filesz);
|
|
|
|
/* populate the CRCs of the inputs: */
|
|
uint16_t mzip_hdr_crc = 0;
|
|
|
|
void *mzip_code_seg;
|
|
uint32_t mzip_code_seg_size = 0;
|
|
|
|
/* build code segment in buffer */
|
|
mzip_codeseg_build(image, im_file_size, &mzip_code_seg,
|
|
&mzip_code_seg_size);
|
|
|
|
mzip_hdr.hdr_code_packed_size = endian_swap ?
|
|
SWAP_32(mzip_code_seg_size) : mzip_code_seg_size;
|
|
|
|
uint16_t mzip_body_crc = 0;
|
|
|
|
mzip_calculate_crc(&mzip_hdr, mzip_code_seg, mzip_code_seg_size,
|
|
&mzip_body_crc);
|
|
|
|
mzip_hdr.hdr_crc_code = endian_swap ? SWAP_16(mzip_body_crc) :
|
|
mzip_body_crc;
|
|
|
|
mzip_hdr.hdr_crc_header = endian_swap ? SWAP_16(mzip_hdr.hdr_crc_header) :
|
|
mzip_hdr.hdr_crc_header;
|
|
|
|
mzip_calculate_hdr_crc(&mzip_hdr, &mzip_hdr_crc);
|
|
mzip_hdr.hdr_crc_header = endian_swap ? SWAP_16(mzip_hdr_crc) :
|
|
mzip_hdr_crc;
|
|
|
|
printf("DEBUG: CRCs: header: %04x file: %04x\n", mzip_hdr_crc,
|
|
mzip_body_crc);
|
|
|
|
mzip_print_header(&mzip_hdr);
|
|
|
|
mzip_write_header(fp_out, &mzip_hdr);
|
|
mzip_write_codeseg(fp_out, mzip_code_seg, mzip_code_seg_size);
|
|
return 0;
|
|
}
|