cc68a136 |
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 |