| 1 | #include <stdio.h>\r |
| 2 | #include <stdlib.h>\r |
| 3 | #include <string.h>\r |
| 4 | \r |
| 5 | \r |
| 6 | typedef struct {\r |
| 7 | unsigned long _dontcare1[4];\r |
| 8 | char signature[4]; // 'EPOC'\r |
| 9 | unsigned long iCpu; // 0x1000 = X86, 0x2000 = ARM, 0x4000 = M*Core\r |
| 10 | unsigned long iCheckSumCode; // sum of all 32 bit words in .text\r |
| 11 | unsigned long _dontcare3[5];\r |
| 12 | unsigned long iCodeSize; // size of code, import address table, constant data and export dir |+30\r |
| 13 | unsigned long _dontcare4[12];\r |
| 14 | unsigned long iCodeOffset; // file offset to code section |+64\r |
| 15 | unsigned long _dontcare5[2];\r |
| 16 | unsigned long iCodeRelocOffset; // relocations for code and const |+70\r |
| 17 | unsigned long iDataRelocOffset; // relocations for data\r |
| 18 | unsigned long iPriority; // priority of this process (EPriorityHigh=450)\r |
| 19 | } E32ImageHeader;\r |
| 20 | \r |
| 21 | \r |
| 22 | typedef struct {\r |
| 23 | unsigned long iSize; // size of this relocation section\r |
| 24 | unsigned long iNumberOfRelocs; // number of relocations in this section\r |
| 25 | } E32RelocSection;\r |
| 26 | \r |
| 27 | \r |
| 28 | typedef struct {\r |
| 29 | unsigned long base;\r |
| 30 | unsigned long size;\r |
| 31 | } reloc_page_header;\r |
| 32 | \r |
| 33 | \r |
| 34 | // E32Image relocation section consists of a number of pages\r |
| 35 | // every page has 8 byte header and a number or 16bit relocation entries\r |
| 36 | // entry format:\r |
| 37 | // 0x3000 | <12bit_reloc_offset>\r |
| 38 | //\r |
| 39 | // if we have page_header.base == 0x1000 and a reloc entry 0x3110,\r |
| 40 | // it means that 32bit value at offset 0x1110 of .text section\r |
| 41 | // is relocatable\r |
| 42 | \r |
| 43 | int main(int argc, char *argv[])\r |
| 44 | {\r |
| 45 | FILE *f = 0;\r |
| 46 | unsigned char pattern[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56 };\r |
| 47 | unsigned char *buff, *p;\r |
| 48 | unsigned long patt_offset; // pattern offset in .text section\r |
| 49 | unsigned long size = 0, i, symbols, insert_pos, *handler;\r |
| 50 | unsigned short reloc_entry;\r |
| 51 | E32ImageHeader *header;\r |
| 52 | E32RelocSection *reloc_section;\r |
| 53 | reloc_page_header *reloc_page;\r |
| 54 | \r |
| 55 | if(argc != 3) {\r |
| 56 | printf("usage: %s <e32_exe> <nsymbols>\n\n", argv[0]);\r |
| 57 | printf("note: this was written to fix a problem caused by as v.2.9-psion-98r2 and shouldn't be used for anything else.\n", argv[0]);\r |
| 58 | return 1;\r |
| 59 | }\r |
| 60 | \r |
| 61 | f = fopen(argv[1], "rb+");\r |
| 62 | if(!f) {\r |
| 63 | printf("%s: couldn't open %s\n", argv[0], argv[1]);\r |
| 64 | return 2;\r |
| 65 | }\r |
| 66 | \r |
| 67 | symbols = atoi(argv[2]);\r |
| 68 | \r |
| 69 | // read the file\r |
| 70 | fseek(f,0,SEEK_END); size=ftell(f); fseek(f,0,SEEK_SET);\r |
| 71 | buff = (unsigned char *) malloc(size);\r |
| 72 | fread(buff,1,size,f);\r |
| 73 | \r |
| 74 | header = (E32ImageHeader *) buff;\r |
| 75 | \r |
| 76 | if(strncmp(header->signature, "EPOC", 4) || header->iCpu != 0x2000) {\r |
| 77 | printf("%s: not a E32 executable image for ARM target.\n", argv[0]);\r |
| 78 | fclose(f);\r |
| 79 | free(buff);\r |
| 80 | return 2;\r |
| 81 | }\r |
| 82 | \r |
| 83 | // find the pattern\r |
| 84 | for(i = 0; i < size-8; i++)\r |
| 85 | if(memcmp(buff+i, pattern, 8) == 0) break;\r |
| 86 | if(i == size-8 || i < 4) {\r |
| 87 | printf("%s: failed to find the pattern.\n", argv[0]);\r |
| 88 | fclose(f);\r |
| 89 | free(buff);\r |
| 90 | return 3;\r |
| 91 | }\r |
| 92 | patt_offset = i - header->iCodeOffset;\r |
| 93 | \r |
| 94 | // find suitable reloc section\r |
| 95 | reloc_section = (E32RelocSection *) (buff + header->iCodeRelocOffset);\r |
| 96 | for(i = 0, p = buff+header->iCodeRelocOffset+8; i < reloc_section->iSize; ) {\r |
| 97 | reloc_page = (reloc_page_header *) p;\r |
| 98 | if(patt_offset - reloc_page->base >= 0 && patt_offset - reloc_page->base < 0x1000 - symbols*4) break;\r |
| 99 | i += reloc_page->size;\r |
| 100 | p += reloc_page->size;\r |
| 101 | }\r |
| 102 | \r |
| 103 | if(i >= reloc_section->iSize) {\r |
| 104 | printf("%s: suitable reloc section not found.\n", argv[0]);\r |
| 105 | fclose(f);\r |
| 106 | free(buff);\r |
| 107 | return 4;\r |
| 108 | }\r |
| 109 | \r |
| 110 | // now find the insert pos and update everything\r |
| 111 | insert_pos = p + reloc_page->size - buff;\r |
| 112 | reloc_page->size += symbols*2;\r |
| 113 | reloc_section->iSize += symbols*2;\r |
| 114 | reloc_section->iNumberOfRelocs += symbols;\r |
| 115 | header->iDataRelocOffset += symbols*2; // data reloc section is now also pushed a little\r |
| 116 | header->iPriority = 450; // let's boost our priority :)\r |
| 117 | \r |
| 118 | // replace the placeholders themselves\r |
| 119 | handler = (unsigned long *) (buff + patt_offset + header->iCodeOffset - 4);\r |
| 120 | for(i = 1; i <= symbols; i++)\r |
| 121 | *(handler+i) = *handler;\r |
| 122 | \r |
| 123 | // recalculate checksum\r |
| 124 | header->iCheckSumCode = 0;\r |
| 125 | for(i = 0, p = buff+header->iCodeOffset; i < header->iCodeSize; i+=4, p+=4)\r |
| 126 | header->iCheckSumCode += *(unsigned long *) p;\r |
| 127 | \r |
| 128 | // check for possible padding\r |
| 129 | if(!*(buff+insert_pos-1)) insert_pos -= 2;\r |
| 130 | \r |
| 131 | // write all this joy\r |
| 132 | fseek(f,0,SEEK_SET);\r |
| 133 | fwrite(buff, 1, insert_pos, f);\r |
| 134 | \r |
| 135 | // write new reloc entries\r |
| 136 | for(i = 0; i < symbols; i++) {\r |
| 137 | handler++;\r |
| 138 | reloc_entry = ((unsigned char *) handler - buff - reloc_page->base - header->iCodeOffset) | 0x3000;\r |
| 139 | fwrite(&reloc_entry, 1, 2, f);\r |
| 140 | }\r |
| 141 | \r |
| 142 | // write the remaining data\r |
| 143 | fwrite(buff+insert_pos, 1, size-insert_pos, f);\r |
| 144 | \r |
| 145 | // done at last!\r |
| 146 | fclose(f);\r |
| 147 | free(buff);\r |
| 148 | \r |
| 149 | return 0;\r |
| 150 | }\r |