/* elf2img - convert an ELF loadable object to a raw binary image or a Cisco- * specific loadabe image. * * (c) 2008 Philippe Vachoon * * Licensed under the GNU General Public License v2. See COPYING * in the distribution source directory for more information. * */ #include #include #include #include #include #include void usage(const char *s) { printf("usage: %s [-m] [elffile] [outfile] [descrfile]\n", s); printf("\t-m Generates an MZIP image\n"); printf("\t[elffile] Input ELF file\n"); printf("\t[outfile] Output image\n"); printf("\t[descrfile] file containing textual description of image\n"); printf("The parameters of the format to be converted to are determined " "based\non the structure of the input ELF file.\n\n"); } void swap_elf32_program_header(struct elf32_phdr *phdr) { phdr->type = SWAP_32(phdr->type); phdr->offset = SWAP_32(phdr->offset); phdr->vaddr = SWAP_32(phdr->vaddr); phdr->paddr = SWAP_32(phdr->paddr); phdr->filesz = SWAP_32(phdr->filesz); phdr->memsz = SWAP_32(phdr->memsz); phdr->flags = SWAP_32(phdr->flags); phdr->align = SWAP_32(phdr->align); } void swap_elf32_header(struct elf32_header *hdr) { hdr->type = SWAP_16(hdr->type); hdr->machine = SWAP_16(hdr->machine); hdr->version = SWAP_32(hdr->version); hdr->entry = SWAP_32(hdr->entry); hdr->phoff = SWAP_32(hdr->phoff); hdr->shoff = SWAP_32(hdr->shoff); hdr->flags = SWAP_32(hdr->flags); hdr->ehsize = SWAP_16(hdr->ehsize); hdr->phentsize = SWAP_16(hdr->phentsize); hdr->phnum = SWAP_16(hdr->phnum); hdr->shentsize = SWAP_16(hdr->shentsize); hdr->shnum = SWAP_16(hdr->shnum); hdr->shstrndx = SWAP_16(hdr->shstrndx); } #define USAGE usage(argv[0]) int main(const int argc, const char *argv[]) { struct elf32_header hdr; struct elf32_phdr *phdr; int i; char swap = 0; const char *file_in = argv[argc - 3]; const char *file_out = argv[argc - 2]; const char *file_desc = argv[argc - 1]; char mzip = 0; printf("elf2img - Cisco Router Image Generation Utility.\n"); printf("(c) 2009 Philippe Vachon \n\n"); if (argc < 3) { printf("Insufficient arguments.\n"); USAGE; return -1; } /* parse arguments */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-m")) { printf("DEBUG: generating an MZIP image as output.\n"); mzip = 1; if (argc < 3) { printf("Error: must specify input and output files.\n"); USAGE; return -1; } } } FILE *fp_in = fopen(file_in, "rb"); if (fp_in == NULL) { printf("Unable to open input file, %s.\n", file_in); USAGE; return -1; } rewind(fp_in); /* read in header */ fread(&hdr, sizeof(struct elf32_header), 1, fp_in); /* check magic */ if (hdr.ident[0] != ELF_MAGIC_1 || hdr.ident[1] != ELF_MAGIC_2 || hdr.ident[2] != ELF_MAGIC_3 || hdr.ident[3] != ELF_MAGIC_4) { printf("input file is not an ELF file.\n"); fclose(fp_in); USAGE; return -1; } /* check endianess */ if (hdr.ident[ELF_INDEX_DATA] == ELF_DATA_MSB) swap = 1; if (swap) swap_elf32_header(&hdr); if (hdr.phnum == 0) { printf("No program headers found. Aborting.\n"); fclose(fp_in); USAGE; return -1; } /* read in all phdrs */ if ((phdr = (struct elf32_phdr *)malloc(sizeof(struct elf32_phdr) * hdr.phnum)) == NULL) { printf("error while trying to allocate %08x bytes. Aborting.\n", (uint32_t)(sizeof(struct elf32_phdr) * hdr.phnum)); fclose(fp_in); USAGE; return -1; } fseek(fp_in, hdr.phoff, SEEK_SET); fread(phdr, hdr.phnum * sizeof(struct elf32_phdr), 1, fp_in); if (swap) for (i = 0; i < hdr.phnum; i++) swap_elf32_program_header(&phdr[i]); /* determine size of the area we need allocated. */ uint32_t memsz = 0; uint32_t min_addr = 0xffffffff; uint32_t max_addr = 0; for (i = 0; i < hdr.phnum; i++) { if (phdr[i].type != ELF_PT_LOAD) continue; if (phdr[i].paddr + phdr[i].memsz > max_addr) max_addr = phdr[i].paddr + phdr[i].memsz; if (phdr[i].paddr < min_addr) min_addr = phdr[i].paddr; } memsz = max_addr - min_addr; if (memsz == 1) { printf("Allocated area is 0. Does this ELF file have any LOAD-able " "segments?\n"); free(phdr); fclose(fp_in); USAGE; return -1; } void *img = malloc(memsz); if (img == NULL) { printf("Unable to allocate %d bytes for the image. Aborting.\n", memsz); free(phdr); fclose(fp_in); USAGE; return -1; } memset(img, 0x0, memsz); /* read in the code into the memory buffer */ for (i = 0; i < hdr.phnum; i++) { /* ignore non-LOADable segments */ if (phdr[i].type != ELF_PT_LOAD) continue; uint32_t buf_off = phdr[i].paddr - min_addr; fseek(fp_in, phdr[i].offset, SEEK_SET); fread(img + buf_off, phdr[i].filesz, 1, fp_in); } FILE *fp_out = fopen(file_out, "wb+"); if (fp_out == NULL) { printf("Error while opening output file.\n"); fclose(fp_in); USAGE; return -1; } /* construct a raw memory image */ if (!mzip) { fwrite(img, memsz, 1, fp_out); free(phdr); free(img); fclose(fp_in); fclose(fp_out); return 0; } /* construct an mzip image */ struct mzip_header mz; void *zip_buf; uint32_t seg_size = 0; mzip_initialize(&mz); if (mzip_codeseg_build(img, memsz, &zip_buf, &seg_size) < 0) { printf("Error while building MZIP code segment. Aborting.\n"); free(phdr); free(img); fclose(fp_in); fclose(fp_out); } mz.hdr_version = 1; mz.hdr_entrypt = hdr.entry; mz.hdr_flags1 = 1; mz.hdr_flags2 = 1; mz.hdr_header_size = 0x70; mz.hdr_loader_addr = min_addr; mz.hdr_flags3 = 1; mz.hdr_code_packed_size = seg_size; mz.hdr_code_unpacked_size = memsz; mz.hdr_memory_image_size = memsz; if (swap) mzip_swap(&mz); uint16_t crc = 0; mzip_calculate_crc(&mz, zip_buf, seg_size, &crc); mz.hdr_crc_code = swap ? SWAP_16(crc) : crc; mzip_calculate_hdr_crc(&mz, &crc); mz.hdr_crc_header = swap ? SWAP_16(crc) : crc; mzip_print_header(&mz); /* read in the description file */ FILE *fp_desc = fopen(file_desc, "r"); if (!fp_desc) { printf("Unable to open description file.\n"); USAGE; goto quit; } fseek(fp_desc, 0, SEEK_END); uint32_t desc_len = ftell(fp_desc); char *desc_buf = (char *)malloc(desc_len); if (desc_buf == NULL) { printf("Error while allocating memory for description buffer.\n"); goto quit; } rewind(fp_desc); fread(desc_buf, desc_len, 1, fp_desc); fclose(fp_desc); printf("Descriptor:\n%s", desc_buf); /* write out the MZIP file */ mzip_write_header(fp_out, &mz); mzip_write_codeseg(fp_out, zip_buf, seg_size); fseek(fp_out, 0, SEEK_END); fwrite(desc_buf, desc_len, 1, fp_out); quit: if (zip_buf) free(zip_buf); free(phdr); free(desc_buf); fclose(fp_in); fclose(fp_out); return 0; }