]> git.sur5r.net Git - cc65/blob - src/ca65/objfile.c
Change the makefiles so that CFLAGS that are special for the application are
[cc65] / src / ca65 / objfile.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 objfile.c                                 */
4 /*                                                                           */
5 /*         Object file writing routines for the ca65 macroassembler          */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstraße 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 <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40
41 /* common */
42 #include "fname.h"
43 #include "objdefs.h"
44
45 /* ca65 */
46 #include "global.h"
47 #include "error.h"
48 #include "objfile.h"
49
50
51
52 /*****************************************************************************/
53 /*                                   Data                                    */
54 /*****************************************************************************/
55
56
57
58 /* File descriptor */
59 static FILE* F = 0;
60
61 /* Default extension */
62 #define OBJ_EXT ".o"
63
64 /* Header structure */
65 static ObjHeader Header = {
66     OBJ_MAGIC,          /* 32: Magic number */
67     OBJ_VERSION,        /* 16: Version number */
68     0,                  /* 16: flags */
69     0,                  /* 32: Offset to option table */
70     0,                  /* 32: Size of options */
71     0,                  /* 32: Offset to file table */
72     0,                  /* 32: Size of files */
73     0,                  /* 32: Offset to segment table */
74     0,                  /* 32: Size of segment table */
75     0,                  /* 32: Offset to import list */
76     0,                  /* 32: Size of import list */
77     0,                  /* 32: Offset to export list */
78     0,                  /* 32: Size of export list */
79     0,                  /* 32: Offset to list of debug symbols */
80     0,                  /* 32: Size of debug symbols */
81     0,                  /* 32: Offset to list of line infos */
82     0,                  /* 32: Size of line infos */
83     0,                  /* 32: Offset to string pool */
84     0,                  /* 32: Size of string pool */
85     0,                  /* 32: Offset to assertion table */
86     0,                  /* 32: Size of assertion table */
87     0,                  /* 32: Offset into scope table */
88     0,                  /* 32: Size of scope table */
89 };
90
91
92
93 /*****************************************************************************/
94 /*                         Internally used functions                         */
95 /*****************************************************************************/
96
97
98
99 static void ObjWriteError (void)
100 /* Called on a write error. Will try to close and remove the file, then
101  * print a fatal error.
102  */
103 {
104     /* Remember the error */
105     int Error = errno;
106
107     /* Force a close of the file, ignoring errors */
108     fclose (F);
109
110     /* Try to remove the file, also ignoring errors */
111     remove (OutFile);
112
113     /* Now abort with a fatal error */
114     Fatal ("Cannot write to output file `%s': %s", OutFile, strerror (Error));
115 }
116
117
118
119 static void ObjWriteHeader (void)
120 /* Write the object file header to the current file position */
121 {
122     ObjWrite32 (Header.Magic);
123     ObjWrite16 (Header.Version);
124     ObjWrite16 (Header.Flags);
125     ObjWrite32 (Header.OptionOffs);
126     ObjWrite32 (Header.OptionSize);
127     ObjWrite32 (Header.FileOffs);
128     ObjWrite32 (Header.FileSize);
129     ObjWrite32 (Header.SegOffs);
130     ObjWrite32 (Header.SegSize);
131     ObjWrite32 (Header.ImportOffs);
132     ObjWrite32 (Header.ImportSize);
133     ObjWrite32 (Header.ExportOffs);
134     ObjWrite32 (Header.ExportSize);
135     ObjWrite32 (Header.DbgSymOffs);
136     ObjWrite32 (Header.DbgSymSize);
137     ObjWrite32 (Header.LineInfoOffs);
138     ObjWrite32 (Header.LineInfoSize);
139     ObjWrite32 (Header.StrPoolOffs);
140     ObjWrite32 (Header.StrPoolSize);
141     ObjWrite32 (Header.AssertOffs);
142     ObjWrite32 (Header.AssertSize);
143     ObjWrite32 (Header.ScopeOffs);
144     ObjWrite32 (Header.ScopeSize);
145 }
146
147
148
149 /*****************************************************************************/
150 /*                                   Code                                    */
151 /*****************************************************************************/
152
153
154
155 void ObjOpen (void)
156 /* Open the object file for writing, write a dummy header */
157 {
158     /* Do we have a name for the output file? */
159     if (OutFile == 0) {
160         /* We don't have an output name explicitly given, construct one from
161          * the name of the input file.
162          */
163         OutFile = MakeFilename (InFile, OBJ_EXT);
164     }
165
166     /* Create the output file */
167     F = fopen (OutFile, "w+b");
168     if (F == 0) {
169         Fatal ("Cannot open output file `%s': %s", OutFile, strerror (errno));
170     }
171
172     /* Write a dummy header */
173     ObjWriteHeader ();
174 }
175
176
177
178 void ObjClose (void)
179 /* Write an update header and close the object file. */
180 {
181     /* Go back to the beginning */
182     if (fseek (F, 0, SEEK_SET) != 0) {
183         ObjWriteError ();
184     }
185
186     /* If we have debug infos, set the flag in the header */
187     if (DbgSyms) {
188         Header.Flags |= OBJ_FLAGS_DBGINFO;
189     }
190
191     /* Write the updated header */
192     ObjWriteHeader ();
193
194     /* Close the file */
195     if (fclose (F) != 0) {
196         ObjWriteError ();
197     }
198 }
199
200
201
202 unsigned long ObjGetFilePos (void)
203 /* Get the current file position */
204 {
205     long Pos = ftell (F);
206     if (Pos < 0) {
207         ObjWriteError ();
208     }
209     return Pos;
210 }
211
212
213
214 void ObjSetFilePos (unsigned long Pos)
215 /* Set the file position */
216 {
217     if (fseek (F, Pos, SEEK_SET) != 0) {
218         ObjWriteError ();
219     }
220 }
221
222
223
224 void ObjWrite8 (unsigned V)
225 /* Write an 8 bit value to the file */
226 {
227     if (putc (V, F) == EOF) {
228         ObjWriteError ();
229     }
230 }
231
232
233
234 void ObjWrite16 (unsigned V)
235 /* Write a 16 bit value to the file */
236 {
237     ObjWrite8 (V);
238     ObjWrite8 (V >> 8);
239 }
240
241
242
243 void ObjWrite24 (unsigned long V)
244 /* Write a 24 bit value to the file */
245 {
246     ObjWrite8 (V);
247     ObjWrite8 (V >> 8);
248     ObjWrite8 (V >> 16);
249 }
250
251
252
253 void ObjWrite32 (unsigned long V)
254 /* Write a 32 bit value to the file */
255 {
256     ObjWrite8 (V);
257     ObjWrite8 (V >> 8);
258     ObjWrite8 (V >> 16);
259     ObjWrite8 (V >> 24);
260 }
261
262
263
264 void ObjWriteVar (unsigned long V)
265 /* Write a variable sized value to the file in special encoding */
266 {
267     /* We will write the value to the file in 7 bit chunks. If the 8th bit
268      * is clear, we're done, if it is set, another chunk follows. This will
269      * allow us to encode smaller values with less bytes, at the expense of
270      * needing 5 bytes if a 32 bit value is written to file.
271      */
272     do {
273         unsigned char C = (V & 0x7F);
274         V >>= 7;
275         if (V) {
276             C |= 0x80;
277         }
278         ObjWrite8 (C);
279     } while (V != 0);
280 }
281
282
283
284 void ObjWriteStr (const char* S)
285 /* Write a string to the object file */
286 {
287     unsigned Len = strlen (S);
288
289     /* Write the string with the length preceeded (this is easier for
290      * the reading routine than the C format since the length is known in
291      * advance).
292      */
293     ObjWriteVar (Len);
294     ObjWriteData (S, Len);
295 }
296
297
298
299 void ObjWriteBuf (const StrBuf* S)
300 /* Write a string to the object file */
301 {
302     /* Write the string with the length preceeded (this is easier for
303      * the reading routine than the C format since the length is known in
304      * advance).
305      */
306     ObjWriteVar (SB_GetLen (S));
307     ObjWriteData (SB_GetConstBuf (S), SB_GetLen (S));    
308 }
309
310
311
312 void ObjWriteData (const void* Data, unsigned Size)
313 /* Write literal data to the file */
314 {
315     if (fwrite (Data, 1, Size, F) != Size) {
316         ObjWriteError ();
317     }
318 }
319
320
321
322 void ObjWritePos (const FilePos* Pos)
323 /* Write a file position to the object file */
324 {
325     /* Write the data entries */
326     ObjWriteVar (Pos->Line);
327     ObjWriteVar (Pos->Col);
328     if (Pos->Name == 0) {
329         /* Position is outside file scope, use the main file instead */
330         ObjWriteVar (0);
331     } else {
332         ObjWriteVar (Pos->Name - 1);
333     }
334 }
335
336
337
338 void ObjStartOptions (void)
339 /* Mark the start of the option section */
340 {
341     Header.OptionOffs = ftell (F);
342 }
343
344
345
346 void ObjEndOptions (void)
347 /* Mark the end of the option section */
348 {
349     Header.OptionSize = ftell (F) - Header.OptionOffs;
350 }
351
352
353
354 void ObjStartFiles (void)
355 /* Mark the start of the files section */
356 {
357     Header.FileOffs = ftell (F);
358 }
359
360
361
362 void ObjEndFiles (void)
363 /* Mark the end of the files section */
364 {
365     Header.FileSize = ftell (F) - Header.FileOffs;
366 }
367
368
369
370 void ObjStartSegments (void)
371 /* Mark the start of the segment section */
372 {
373     Header.SegOffs = ftell (F);
374 }
375
376
377
378 void ObjEndSegments (void)
379 /* Mark the end of the segment section */
380 {
381     Header.SegSize = ftell (F) - Header.SegOffs;
382 }
383
384
385
386 void ObjStartImports (void)
387 /* Mark the start of the import section */
388 {
389     Header.ImportOffs = ftell (F);
390 }
391
392
393
394 void ObjEndImports (void)
395 /* Mark the end of the import section */
396 {
397     Header.ImportSize = ftell (F) - Header.ImportOffs;
398 }
399
400
401
402 void ObjStartExports (void)
403 /* Mark the start of the export section */
404 {
405     Header.ExportOffs = ftell (F);
406 }
407
408
409
410 void ObjEndExports (void)
411 /* Mark the end of the export section */
412 {
413     Header.ExportSize = ftell (F) - Header.ExportOffs;
414 }
415
416
417
418 void ObjStartDbgSyms (void)
419 /* Mark the start of the debug symbol section */
420 {
421     Header.DbgSymOffs = ftell (F);
422 }
423
424
425
426 void ObjEndDbgSyms (void)
427 /* Mark the end of the debug symbol section */
428 {
429     Header.DbgSymSize = ftell (F) - Header.DbgSymOffs;
430 }
431
432
433
434 void ObjStartLineInfos (void)
435 /* Mark the start of the line info section */
436 {
437     Header.LineInfoOffs = ftell (F);
438 }
439
440
441
442 void ObjEndLineInfos (void)
443 /* Mark the end of the line info section */
444 {
445     Header.LineInfoSize = ftell (F) - Header.LineInfoOffs;
446 }
447
448
449
450 void ObjStartStrPool (void)
451 /* Mark the start of the string pool section */
452 {
453     Header.StrPoolOffs = ftell (F);
454 }
455
456
457
458 void ObjEndStrPool (void)
459 /* Mark the end of the string pool section */
460 {
461     Header.StrPoolSize = ftell (F) - Header.StrPoolOffs;
462 }
463
464
465
466 void ObjStartAssertions (void)
467 /* Mark the start of the assertion table */
468 {
469     Header.AssertOffs = ftell (F);
470 }
471
472
473
474 void ObjEndAssertions (void)
475 /* Mark the end of the assertion table */
476 {
477     Header.AssertSize = ftell (F) - Header.AssertOffs;
478 }
479
480
481
482 void ObjStartScopes (void)
483 /* Mark the start of the scope table */
484 {
485     Header.ScopeOffs = ftell (F);
486 }
487
488
489
490 void ObjEndScopes (void)
491 /* Mark the end of the scope table */
492 {
493     Header.ScopeSize = ftell (F) - Header.ScopeOffs;
494 }
495
496
497