// Copyright 2007,2008 Segher Boessenkool // Copyright 2008 Sven Peter // Licensed under the terms of the GNU GPL, version 2 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt // Converts edoc to elf files, based on dol2elf by Segher Boessenkool. // Entry point is always assumed as zero. #include #include #include #include #include #include struct section { uint32_t addr; uint32_t size; uint32_t offset; uint32_t elf_offset; uint32_t str_offset; }; uint16_t le16(const uint8_t *p) { return (p[1] << 8) | p[0]; } uint32_t le32(const uint8_t *p) { return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; } uint64_t le64(const uint8_t *p) { return ((uint64_t)le32(p + 4) << 32) | le32(p); } uint64_t le34(const uint8_t *p) { return 4 * (uint64_t)le32(p); } void wle16(uint8_t *p, uint16_t x) { p[1] = x >> 8; p[0] = x; } void wle32(uint8_t *p, uint32_t x) { wle16(p + 2, x >> 16); wle16(p, x); } void wle64(uint8_t *p, uint64_t x) { wle32(p + 4, x >> 32); wle32(p, x); } static uint32_t edoc_chksum(uint16_t *data, uint32_t len) { uint32_t sum = 0; while(len > 0) { sum += le16((uint8_t *)data++); len -= 2; } return sum & 0xffff; } void fatal(const char *s, ...) { char message[256]; va_list ap; va_start(ap, s); vsnprintf(message, sizeof message, s, ap); perror(message); exit(1); } static void edoc2elf(char *inname, char *outname) { uint8_t tmpbuffer[16]; uint8_t elfheader[0x400] = {0}; uint8_t segheader[0x400] = {0}; uint8_t secheader[0x400] = {0}; uint8_t strings[0x400] = "\0.strtab"; uint32_t str_offset = 9; struct section *section; FILE *in, *out; uint32_t n_sections; uint32_t size_total; uint32_t entry; uint32_t elf_offset; uint32_t i; uint8_t *p; in = fopen(inname, "rb"); fread(tmpbuffer, 1, sizeof tmpbuffer, in); if(memcmp(tmpbuffer, "EDOC", 4) != 0) { fprintf(stderr, "invalid edoc file.\n"); return; } n_sections = 0; size_total = le32(tmpbuffer + 4); fseek(in, 0xc, SEEK_SET); do { n_sections++; fread(tmpbuffer, 1, sizeof tmpbuffer, in); } while(feof(in) == 0 && fseek(in, le32(tmpbuffer + 4) + 12 - sizeof(tmpbuffer), SEEK_CUR) == 0 && ftell(in) < size_total); printf("%d sections.\n", n_sections); section = calloc(n_sections, sizeof(*section)); if(section == NULL) fatal("section alloc failure"); elf_offset = 0x1000; i = 0; fseek(in, 0xc, SEEK_SET); do { fread(tmpbuffer, 1, sizeof tmpbuffer, in); section[i].offset = ftell(in); section[i].addr = le32(tmpbuffer); section[i].size = le32(tmpbuffer + 4); section[i].elf_offset = elf_offset; elf_offset += section[i].size; sprintf(strings + str_offset, ".text.%d", i); section[i].str_offset = str_offset; str_offset += i > 10 ? 9 : 8; fseek(in, section[i].size + 12 - sizeof(tmpbuffer), SEEK_CUR); i++; } while(i < n_sections); entry = 0; printf("entry point = %08x\n", entry); memset(elfheader, 0, sizeof elfheader); elfheader[0] = 0x7f; elfheader[1] = 0x45; elfheader[2] = 0x4c; elfheader[3] = 0x46; elfheader[4] = 0x01; // file class, 32bit executable elfheader[5] = 0x01; // little-endian elfheader[6] = 0x01; wle16(elfheader + 0x10, 2); // executable file wle16(elfheader + 0x12, 40); // ARM wle32(elfheader + 0x14, 1); // ELF version wle32(elfheader + 0x18, entry); wle32(elfheader + 0x1c, 0x400); wle32(elfheader + 0x20, 0x800); wle32(elfheader + 0x24, 0); // no flags wle16(elfheader + 0x28, 0x34); // header size wle16(elfheader + 0x2a, 0x20); // header table entry size wle16(elfheader + 0x2c, n_sections); // count wle16(elfheader + 0x2e, 0x28); // section header table entry size wle16(elfheader + 0x30, n_sections + 2); // count wle16(elfheader + 0x32, 1); // string table index p = segheader; for (i = 0; i < n_sections; i++) if (section[i].size) { wle32(p + 0x00, 1); wle32(p + 0x04, section[i].elf_offset); wle32(p + 0x08, section[i].addr); wle32(p + 0x0c, section[i].addr); wle32(p + 0x10, section[i].size); wle32(p + 0x14, section[i].size); wle32(p + 0x18, 5); wle32(p + 0x1c, 0x20); p += 0x20; } p = secheader + 0x28; wle32(p + 0x00, 1); wle32(p + 0x04, 3); wle32(p + 0x08, 0); wle32(p + 0x0c, 0); wle32(p + 0x10, 0xc00); wle32(p + 0x14, 0x400); wle32(p + 0x18, 0); wle32(p + 0x1c, 0); wle32(p + 0x20, 1); wle32(p + 0x24, 0); p += 0x28; for (i = 0; i < n_sections; i++) if (section[i].size) { wle32(p + 0x00, section[i].str_offset); wle32(p + 0x04, i == 18 ? 8 : 1); wle32(p + 0x08, i < 7 ? 6 : 3); wle32(p + 0x0c, section[i].addr); wle32(p + 0x10, section[i].elf_offset); wle32(p + 0x14, section[i].size); wle32(p + 0x18, 0); wle32(p + 0x1c, 0); wle32(p + 0x20, 0x20); wle32(p + 0x24, 0); p += 0x28; } out = fopen(outname, "wb"); fwrite(elfheader, 1, sizeof elfheader, out); fwrite(segheader, 1, sizeof segheader, out); fwrite(secheader, 1, sizeof secheader, out); fwrite(strings, 1, sizeof strings, out); for (i = 0; i < n_sections; i++) if (section[i].size) { p = malloc(section[i].size); fseek(in, section[i].offset, SEEK_SET); fread(p, 1, section[i].size, in); fseek(out, section[i].elf_offset, SEEK_SET); fwrite(p, 1, section[i].size, out); free(p); } fclose(out); fclose(in); } int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } edoc2elf(argv[1], argv[2]); return 0; }