]> git.sur5r.net Git - cc65/blob - src/co65/o65.c
aa000f307720d8f8b15b2363ea5417684a038a36
[cc65] / src / co65 / o65.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                   o65.h                                   */
4 /*                                                                           */
5 /*               Definitions and code for the o65 file format                */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <errno.h>
39
40 /* common */
41 #include "xmalloc.h"
42
43 /* co65 */
44 #include "error.h"
45 #include "fileio.h"
46 #include "o65.h"
47
48
49
50 /*****************************************************************************/
51 /*                              struct O65Data                               */
52 /*****************************************************************************/
53
54
55
56 static O65Data* NewO65Data (void)
57 /* Create, initialize and return a new O65Data struct */
58 {
59     /* Allocate memory */
60     O65Data* D = xmalloc (sizeof (O65Data));
61
62     /* Initialize the fields as needed */
63     D->Options      = AUTO_COLLECTION_INITIALIZER;
64     D->Text         = 0;
65     D->Data         = 0;
66     D->TextReloc    = AUTO_COLLECTION_INITIALIZER;
67     D->DataReloc    = AUTO_COLLECTION_INITIALIZER;
68     D->Imports      = AUTO_COLLECTION_INITIALIZER;
69     D->Exports      = AUTO_COLLECTION_INITIALIZER;
70
71     /* Return the new struct */
72     return D;
73 }
74
75
76
77 /*****************************************************************************/
78 /*                                   Code                                    */
79 /*****************************************************************************/
80
81
82
83 static unsigned long ReadO65Size (FILE* F, const O65Header* H)
84 /* Read a size variable (16 or 32 bit, depending on the mode word in the
85  * header) from the o65 file.
86  */
87 {
88     switch (H->mode & O65_SIZE_MASK) {
89         case O65_SIZE_32BIT:    return Read32 (F);
90         case O65_SIZE_16BIT:    return Read16 (F);
91         default:                Internal ("Invalid size field value in o65 header");
92     }
93 }
94
95
96
97 static void ReadO65Header (FILE* F, O65Header* H)
98 /* Read an o65 header from the given file. The function will call Error if
99  * something is wrong.
100  */
101 {
102     static const char Magic[3] = {
103         O65_MAGIC_0, O65_MAGIC_1, O65_MAGIC_2   /* "o65" */
104     };
105
106     /* Read the marker and check it */
107     ReadData (F, H->marker, sizeof (H->marker));
108     if (H->marker[0] != O65_MARKER_0 || H->marker[1] != O65_MARKER_1) {
109         Error ("Not an o65 object file: Invalid marker %02X %02X",
110                H->marker[0], H->marker[1]);
111     }
112
113     /* Read the magic and check it */
114     ReadData (F, H->magic, sizeof (H->magic));
115     if (memcmp (H->magic, Magic, sizeof (H->magic)) != 0) {
116         Error ("Not an o65 object file: Invalid magic %02X %02X %02X",
117                H->magic[0], H->magic[1], H->magic[2]);
118     }
119
120     /* Read the version number and check it */
121     H->version = Read8 (F);
122     if (H->version != O65_VERSION) {
123         Error ("Invalid o65 version number: %02X", H->version);
124     }
125
126     /* Read the mode word */
127     H->mode = Read16 (F);
128
129     /* Read the remainder of the header */
130     H->tbase = ReadO65Size (F, H);
131     H->tlen  = ReadO65Size (F, H);
132     H->dbase = ReadO65Size (F, H);
133     H->dlen  = ReadO65Size (F, H);
134     H->bbase = ReadO65Size (F, H);
135     H->blen  = ReadO65Size (F, H);
136     H->zbase = ReadO65Size (F, H);
137     H->zlen  = ReadO65Size (F, H);
138     H->stack = ReadO65Size (F, H);
139 }
140
141
142
143 static O65Option* ReadO65Option (FILE* F)
144 /* Read the next O65 option from the given file. The option is stored into a
145  * dynamically allocated O65Option struct which is returned. On end of options,
146  * NULL is returned. On error, Error is called which terminates the program.
147  */
148 {
149     O65Option* O;
150
151     /* Read the length of the option and bail out on end of options */
152     unsigned char Len = Read8 (F);
153     if (Len == 0) {
154         return 0;
155     }
156
157     /* Allocate a new O65Option structure of the needed size */
158     O = xmalloc (sizeof (*O) - sizeof (O->Data) + Len - 2);
159
160     /* Assign the length and read the remaining option data */
161     O->Len  = Len;
162     O->Type = Read8 (F);
163     ReadData (F, O->Data, Len - 2);
164
165     /* Return the new struct */
166     return O;
167 }
168
169
170
171 static O65Import* ReadO65Import (FILE* F)
172 /* Read an o65 import from the file */
173 {
174     O65Import* I;
175
176     /* Allow identifiers up to 511 bytes */
177     char Buf[512];
178
179     /* Read the identifier */
180     unsigned Len = 0;
181     char C;
182     do {
183         C = Read8 (F);
184         if (Len >= sizeof (Buf)) {
185             Error ("Imported identifier exceeds maximum size (%u)", sizeof (Buf));
186         }
187         Buf[Len++] = C;
188     } while (C != '\0');
189
190     /* Allocate an import structure and initialize it */
191     I = xmalloc (sizeof (*I) - sizeof (I->Name) + Len);
192     memcpy (I->Name, Buf, Len);
193
194     /* Return the new struct */
195     return I;
196 }
197
198
199
200 static void ReadO65RelocInfo (FILE* F, const O65Data* D, Collection* Reloc)
201 /* Read relocation data for one segment */
202 {
203     /* Relocation starts at (start address - 1) */
204     unsigned long Offs = (unsigned long) -1L;
205
206     while (1) {
207
208         O65Reloc* R;
209
210         /* Read the next relocation offset */
211         unsigned char C = Read8 (F);
212         if (C == 0) {
213             /* End of relocation table */
214             break;
215         }
216
217         /* Create a new relocation entry */
218         R = xmalloc (sizeof (*R));
219
220         /* Handle overflow bytes */
221         while (C == 0xFF) {
222             Offs += 0xFE;
223             C = Read8 (F);
224         }
225
226         /* Calculate the final offset */
227         R->Offs = (Offs += C);
228
229         /* Read typebyte and segment id */
230         C = Read8 (F);
231         R->Type   = (C & O65_RTYPE_MASK);
232         R->SegID  = (C & O65_SEGID_MASK);
233
234         /* Read an additional relocation value if there is one */
235         R->SymIdx = (R->SegID == O65_SEGID_UNDEF)? ReadO65Size (F, &D->Header) : 0;
236         switch (R->Type) {
237
238             case O65_RTYPE_HIGH:
239                 if ((D->Header.mode & O65_RELOC_MASK) == O65_RELOC_BYTE) {
240                     /* Low byte follows */
241                     R->Val = Read8 (F);
242                 } else {
243                     /* Low byte is zero */
244                     R->Val = 0;
245                 }
246                 break;
247
248             case O65_RTYPE_SEG:
249                 /* Low 16 byte of the segment address follow */
250                 R->Val = Read16 (F);
251                 break;
252
253             default:
254                 R->Val = 0;
255                 break;
256         }
257
258         /* Insert this relocation entry into the collection */
259         CollAppend (Reloc, R);
260     }
261 }
262
263
264
265 static O65Export* ReadO65Export (FILE* F, const O65Header* H)
266 /* Read an o65 export from the file */
267 {
268     O65Export* E;
269
270     /* Allow identifiers up to 511 bytes */
271     char Buf[512];
272
273     /* Read the identifier */
274     unsigned Len = 0;
275     char C;
276     do {
277         C = Read8 (F);
278         if (Len >= sizeof (Buf)) {
279             Error ("Exported identifier exceeds maximum size (%u)", sizeof (Buf));
280         }
281         Buf[Len++] = C;
282     } while (C != '\0');
283
284     /* Allocate an export structure and initialize it */
285     E = xmalloc (sizeof (*E) - sizeof (E->Name) + Len);
286     memcpy (E->Name, Buf, Len);
287     E->SegID = Read8 (F);
288     E->Val   = ReadO65Size (F, H);
289
290     /* Return the new struct */
291     return E;
292 }
293
294
295
296 static O65Data* ReadO65Data (FILE* F)
297 /* Read a complete o65 file into dynamically allocated memory and return the
298  * created O65Data struct.
299  */
300 {
301     unsigned long Count;
302     O65Option* O;
303
304     /* Create the struct we're going to return */
305     O65Data* D = NewO65Data ();
306
307     /* Read the header */
308     ReadO65Header (F, &D->Header);
309
310     /* Read the options */
311     while ((O = ReadO65Option (F)) != 0) {
312         CollAppend (&D->Options, O);
313     }
314
315     /* Allocate space for the text segment and read it */
316     D->Text = xmalloc (D->Header.tlen);
317     ReadData (F, D->Text, D->Header.tlen);
318
319     /* Allocate space for the data segment and read it */
320     D->Data = xmalloc (D->Header.dlen);
321     ReadData (F, D->Data, D->Header.dlen);
322
323     /* Read the undefined references list */
324     Count = ReadO65Size (F, &D->Header);
325     while (Count--) {
326         CollAppend (&D->Imports, ReadO65Import (F));
327     }
328
329     /* Read the relocation tables for text and data segment */
330     ReadO65RelocInfo (F, D, &D->TextReloc);
331     ReadO65RelocInfo (F, D, &D->DataReloc);
332
333     /* Read the exported globals list */
334     Count = ReadO65Size (F, &D->Header);
335     while (Count--) {
336         CollAppend (&D->Exports, ReadO65Export (F, &D->Header));
337     }
338
339     /* Return the o65 data read from the file */
340     return D;
341 }
342
343
344
345 O65Data* ReadO65File (const char* Name)
346 /* Read a complete o65 file into dynamically allocated memory and return the
347  * created O65Data struct.
348  */
349 {
350     O65Data* D;
351
352     /* Open the o65 input file */
353     FILE* F = fopen (Name, "rb");
354     if (F == 0) {
355         Error ("Cannot open `%s': %s", Name, strerror (errno));
356     }
357
358     /* Read the file data */
359     D = ReadO65Data (F);
360
361     /* Close the input file. Ignore errors since we were only reading */
362     fclose (F);
363
364     /* Return the data read */
365     return D;
366 }
367
368
369