memhandlers slightly improved
[picodrive.git] / cpu / Cyclone / epoc / patchtable_symb.c
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