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 */ |
59 | static FILE* F = 0; |
60 | |
61 | /* Default extension */ |
62 | #define OBJ_EXT ".o" |
63 | |
64 | /* Header structure */ |
65 | static ObjHeader = { |
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 | |
101 | static 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 | |
121 | static void (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 | |
159 | void 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 | |
182 | void 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 | |
206 | unsigned 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 | |
218 | void 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 | |
228 | void 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 | |
238 | void ObjWrite16 (unsigned V) |
239 | /* Write a 16 bit value to the file */ |
240 | { |
241 | ObjWrite8 (V); |
242 | ObjWrite8 (V >> 8); |
243 | } |
244 | |
245 | |
246 | |
247 | void 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 | |
257 | void 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 | |
268 | void 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 | |
288 | void 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 | |
303 | void 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 | |
316 | void 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 | |
326 | void 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 | |
342 | void ObjStartOptions (void) |
343 | /* Mark the start of the option section */ |
344 | { |
345 | Header.OptionOffs = ftell (F); |
346 | } |
347 | |
348 | |
349 | |
350 | void ObjEndOptions (void) |
351 | /* Mark the end of the option section */ |
352 | { |
353 | Header.OptionSize = ftell (F) - Header.OptionOffs; |
354 | } |
355 | |
356 | |
357 | |
358 | void ObjStartFiles (void) |
359 | /* Mark the start of the files section */ |
360 | { |
361 | Header.FileOffs = ftell (F); |
362 | } |
363 | |
364 | |
365 | |
366 | void ObjEndFiles (void) |
367 | /* Mark the end of the files section */ |
368 | { |
369 | Header.FileSize = ftell (F) - Header.FileOffs; |
370 | } |
371 | |
372 | |
373 | |
374 | void ObjStartSegments (void) |
375 | /* Mark the start of the segment section */ |
376 | { |
377 | Header.SegOffs = ftell (F); |
378 | } |
379 | |
380 | |
381 | |
382 | void ObjEndSegments (void) |
383 | /* Mark the end of the segment section */ |
384 | { |
385 | Header.SegSize = ftell (F) - Header.SegOffs; |
386 | } |
387 | |
388 | |
389 | |
390 | void ObjStartImports (void) |
391 | /* Mark the start of the import section */ |
392 | { |
393 | Header.ImportOffs = ftell (F); |
394 | } |
395 | |
396 | |
397 | |
398 | void ObjEndImports (void) |
399 | /* Mark the end of the import section */ |
400 | { |
401 | Header.ImportSize = ftell (F) - Header.ImportOffs; |
402 | } |
403 | |
404 | |
405 | |
406 | void ObjStartExports (void) |
407 | /* Mark the start of the export section */ |
408 | { |
409 | Header.ExportOffs = ftell (F); |
410 | } |
411 | |
412 | |
413 | |
414 | void ObjEndExports (void) |
415 | /* Mark the end of the export section */ |
416 | { |
417 | Header.ExportSize = ftell (F) - Header.ExportOffs; |
418 | } |
419 | |
420 | |
421 | |
422 | void ObjStartDbgSyms (void) |
423 | /* Mark the start of the debug symbol section */ |
424 | { |
425 | Header.DbgSymOffs = ftell (F); |
426 | } |
427 | |
428 | |
429 | |
430 | void ObjEndDbgSyms (void) |
431 | /* Mark the end of the debug symbol section */ |
432 | { |
433 | Header.DbgSymSize = ftell (F) - Header.DbgSymOffs; |
434 | } |
435 | |
436 | |
437 | |
438 | void ObjStartLineInfos (void) |
439 | /* Mark the start of the line info section */ |
440 | { |
441 | Header.LineInfoOffs = ftell (F); |
442 | } |
443 | |
444 | |
445 | |
446 | void ObjEndLineInfos (void) |
447 | /* Mark the end of the line info section */ |
448 | { |
449 | Header.LineInfoSize = ftell (F) - Header.LineInfoOffs; |
450 | } |
451 | |
452 | |
453 | |
454 | void ObjStartStrPool (void) |
455 | /* Mark the start of the string pool section */ |
456 | { |
457 | Header.StrPoolOffs = ftell (F); |
458 | } |
459 | |
460 | |
461 | |
462 | void ObjEndStrPool (void) |
463 | /* Mark the end of the string pool section */ |
464 | { |
465 | Header.StrPoolSize = ftell (F) - Header.StrPoolOffs; |
466 | } |
467 | |
468 | |
469 | |
470 | void ObjStartAssertions (void) |
471 | /* Mark the start of the assertion table */ |
472 | { |
473 | Header.AssertOffs = ftell (F); |
474 | } |
475 | |
476 | |
477 | |
478 | void ObjEndAssertions (void) |
479 | /* Mark the end of the assertion table */ |
480 | { |
481 | Header.AssertSize = ftell (F) - Header.AssertOffs; |
482 | } |
483 | |
484 | |
485 | |
486 | void ObjStartScopes (void) |
487 | /* Mark the start of the scope table */ |
488 | { |
489 | Header.ScopeOffs = ftell (F); |
490 | } |
491 | |
492 | |
493 | |
494 | void ObjEndScopes (void) |
495 | /* Mark the end of the scope table */ |
496 | { |
497 | Header.ScopeSize = ftell (F) - Header.ScopeOffs; |
498 | } |
499 | |
500 | |
501 | |
502 | void ObjStartSpans (void) |
503 | /* Mark the start of the span table */ |
504 | { |
505 | Header.SpanOffs = ftell (F); |
506 | } |
507 | |
508 | |
509 | |
510 | void ObjEndSpans (void) |
511 | /* Mark the end of the span table */ |
512 | { |
513 | Header.SpanSize = ftell (F) - Header.SpanOffs; |
514 | } |
515 | |