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