]> git.sur5r.net Git - cc65/blob - src/ca65/objfile.c
Add co65 utility
[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-2001 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
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,
67     OBJ_VERSION,
68     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
69 };
70
71
72
73 /*****************************************************************************/
74 /*                         Internally used functions                         */
75 /*****************************************************************************/
76
77
78
79 static void ObjWriteError (void)
80 /* Called on a write error. Will try to close and remove the file, then
81  * print a fatal error.
82  */
83 {
84     /* Remember the error */
85     int Error = errno;
86
87     /* Force a close of the file, ignoring errors */
88     fclose (F);
89
90     /* Try to remove the file, also ignoring errors */
91     remove (OutFile);
92
93     /* Now abort with a fatal error */
94     Fatal (FAT_CANNOT_WRITE_OUTPUT, OutFile, strerror (Error));
95 }
96
97
98
99 static void ObjWriteHeader (void)
100 /* Write the object file header to the current file position */
101 {
102     ObjWrite32 (Header.Magic);
103     ObjWrite16 (Header.Version);
104     ObjWrite16 (Header.Flags);
105     ObjWrite32 (Header.OptionOffs);
106     ObjWrite32 (Header.OptionSize);
107     ObjWrite32 (Header.FileOffs);
108     ObjWrite32 (Header.FileSize);
109     ObjWrite32 (Header.SegOffs);
110     ObjWrite32 (Header.SegSize);
111     ObjWrite32 (Header.ImportOffs);
112     ObjWrite32 (Header.ImportSize);
113     ObjWrite32 (Header.ExportOffs);
114     ObjWrite32 (Header.ExportSize);
115     ObjWrite32 (Header.DbgSymOffs);
116     ObjWrite32 (Header.DbgSymSize);
117     ObjWrite32 (Header.LineInfoOffs);
118     ObjWrite32 (Header.LineInfoSize);
119 }
120
121
122
123 /*****************************************************************************/
124 /*                                   Code                                    */
125 /*****************************************************************************/
126
127
128
129 void ObjOpen (void)
130 /* Open the object file for writing, write a dummy header */
131 {
132     /* Do we have a name for the output file? */
133     if (OutFile == 0) {
134         /* We don't have an output name explicitly given, construct one from
135          * the name of the input file.
136          */
137         OutFile = MakeFilename (InFile, OBJ_EXT);
138     }
139
140     /* Create the output file */
141     F = fopen (OutFile, "w+b");
142     if (F == 0) {
143         Fatal (FAT_CANNOT_OPEN_OUTPUT, OutFile, strerror (errno));
144     }
145
146     /* Write a dummy header */
147     ObjWriteHeader ();
148 }
149
150
151
152 void ObjClose (void)
153 /* Write an update header and close the object file. */
154 {
155     /* Go back to the beginning */
156     if (fseek (F, 0, SEEK_SET) != 0) {
157         ObjWriteError ();
158     }
159
160     /* If we have debug infos, set the flag in the header */
161     if (DbgSyms) {
162         Header.Flags |= OBJ_FLAGS_DBGINFO;
163     }
164
165     /* Write the updated header */
166     ObjWriteHeader ();
167
168     /* Close the file */
169     if (fclose (F) != 0) {
170         ObjWriteError ();
171     }
172 }
173
174
175
176 void ObjWrite8 (unsigned V)
177 /* Write an 8 bit value to the file */
178 {
179     if (putc (V, F) == EOF) {
180         ObjWriteError ();
181     }
182 }
183
184
185
186 void ObjWrite16 (unsigned V)
187 /* Write a 16 bit value to the file */
188 {
189     ObjWrite8 (V);
190     ObjWrite8 (V >> 8);
191 }
192
193
194
195 void ObjWrite24 (unsigned long V)
196 /* Write a 24 bit value to the file */
197 {
198     ObjWrite8 (V);
199     ObjWrite8 (V >> 8);
200     ObjWrite8 (V >> 16);
201 }
202
203
204
205 void ObjWrite32 (unsigned long V)
206 /* Write a 32 bit value to the file */
207 {
208     ObjWrite8 (V);
209     ObjWrite8 (V >> 8);
210     ObjWrite8 (V >> 16);
211     ObjWrite8 (V >> 24);
212 }
213
214
215
216 void ObjWriteVar (unsigned long V)
217 /* Write a variable sized value to the file in special encoding */
218 {
219     /* We will write the value to the file in 7 bit chunks. If the 8th bit
220      * is clear, we're done, if it is set, another chunk follows. This will
221      * allow us to encode smaller values with less bytes, at the expense of
222      * needing 5 bytes if a 32 bit value is written to file.
223      */
224     do {
225         unsigned char C = (V & 0x7F);
226         V >>= 7;
227         if (V) {
228             C |= 0x80;
229         }
230         ObjWrite8 (C);
231     } while (V != 0);
232 }
233
234
235
236 void ObjWriteStr (const char* S)
237 /* Write a string to the object file */
238 {
239     unsigned Len = strlen (S);
240
241     /* Write the string with the length preceeded (this is easier for
242      * the reading routine than the C format since the length is known in
243      * advance).
244      */
245     ObjWriteVar (Len);
246     ObjWriteData (S, Len);
247 }
248
249
250
251 void ObjWriteData (const void* Data, unsigned Size)
252 /* Write literal data to the file */
253 {
254     if (fwrite (Data, 1, Size, F) != Size) {
255         ObjWriteError ();
256     }
257 }
258
259
260
261 void ObjWritePos (const FilePos* Pos)
262 /* Write a file position to the object file */
263 {
264     /* Write the data entries */
265     ObjWriteVar (Pos->Line);
266     ObjWriteVar (Pos->Col);
267     if (Pos->Name == 0) {
268         /* Position is outside file scope, use the main file instead */
269         ObjWriteVar (0);
270     } else {
271         ObjWriteVar (Pos->Name - 1);
272     }
273 }
274
275
276
277 void ObjStartOptions (void)
278 /* Mark the start of the option section */
279 {
280     Header.OptionOffs = ftell (F);
281 }
282
283
284
285 void ObjEndOptions (void)
286 /* Mark the end of the option section */
287 {
288     Header.OptionSize = ftell (F) - Header.OptionOffs;
289 }
290
291
292
293 void ObjStartFiles (void)
294 /* Mark the start of the files section */
295 {
296     Header.FileOffs = ftell (F);
297 }
298
299
300
301 void ObjEndFiles (void)
302 /* Mark the end of the files section */
303 {
304     Header.FileSize = ftell (F) - Header.FileOffs;
305 }
306
307
308
309 void ObjStartSegments (void)
310 /* Mark the start of the segment section */
311 {
312     Header.SegOffs = ftell (F);
313 }
314
315
316
317 void ObjEndSegments (void)
318 /* Mark the end of the segment section */
319 {
320     Header.SegSize = ftell (F) - Header.SegOffs;
321 }
322
323
324
325 void ObjStartImports (void)
326 /* Mark the start of the import section */
327 {
328     Header.ImportOffs = ftell (F);
329 }
330
331
332
333 void ObjEndImports (void)
334 /* Mark the end of the import section */
335 {
336     Header.ImportSize = ftell (F) - Header.ImportOffs;
337 }
338
339
340
341 void ObjStartExports (void)
342 /* Mark the start of the export section */
343 {
344     Header.ExportOffs = ftell (F);
345 }
346
347
348
349 void ObjEndExports (void)
350 /* Mark the end of the export section */
351 {
352     Header.ExportSize = ftell (F) - Header.ExportOffs;
353 }
354
355
356
357 void ObjStartDbgSyms (void)
358 /* Mark the start of the debug symbol section */
359 {
360     Header.DbgSymOffs = ftell (F);
361 }
362
363
364
365 void ObjEndDbgSyms (void)
366 /* Mark the end of the debug symbol section */
367 {
368     Header.DbgSymSize = ftell (F) - Header.DbgSymOffs;
369 }
370
371
372
373 void ObjStartLineInfos (void)
374 /* Mark the start of the line info section */
375 {
376     Header.LineInfoOffs = ftell (F);
377 }
378
379
380
381 void ObjEndLineInfos (void)
382 /* Mark the end of the line info section */
383 {
384     Header.LineInfoSize = ftell (F) - Header.LineInfoOffs;
385 }
386
387
388