]> git.sur5r.net Git - cc65/blob - src/ar65/library.c
Add dbginfo module
[cc65] / src / ar65 / library.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 library.c                                 */
4 /*                                                                           */
5 /*         Library data structures and helpers for the ar65 archiver         */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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 "bitops.h"
42 #include "exprdefs.h"
43 #include "filepos.h"
44 #include "libdefs.h"
45 #include "print.h"
46 #include "symdefs.h"
47 #include "xmalloc.h"
48
49 /* ar65 */
50 #include "error.h"
51 #include "global.h"
52 #include "fileio.h"
53 #include "objdata.h"
54 #include "exports.h"
55 #include "library.h"
56
57
58
59 /*****************************************************************************/
60 /*                                   Data                                    */
61 /*****************************************************************************/
62
63
64
65 /* File descriptor for the library file */
66 FILE*                   NewLib = 0;
67 static FILE*            Lib = 0;
68 static const char*      LibName = 0;
69
70 /* The library header */
71 static LibHeader        Header = {
72     LIB_MAGIC,
73     LIB_VERSION
74 };
75
76
77
78 /*****************************************************************************/
79 /*                       Writing file data structures                        */
80 /*****************************************************************************/
81
82
83
84 static void ReadHeader (void)
85 /* Read the header of a library file */
86 {
87     /* Seek to position zero */
88     fseek (Lib, 0, SEEK_SET);
89
90     /* Read the header fields, checking magic and version */
91     Header.Magic   = Read32 (Lib);
92     if (Header.Magic != LIB_MAGIC) {
93         Error ("`%s' is not a valid library file", LibName);
94     }
95     Header.Version = Read16 (Lib);
96     if (Header.Version != LIB_VERSION) {
97         Error ("Wrong data version in `%s'", LibName);
98     }
99     Header.Flags   = Read16 (Lib);
100     Header.IndexOffs = Read32 (Lib);
101 }
102
103
104
105 static void ReadIndexEntry (void)
106 /* Read one entry in the index */
107 {
108     /* Create a new entry and insert it into the list */
109     ObjData* O  = NewObjData ();
110
111     /* Module name/flags/MTime/Start/Size */
112     O->Name     = ReadStr (Lib);
113     O->Flags    = Read16 (Lib);
114     O->MTime    = Read32 (Lib);
115     O->Start    = Read32 (Lib);
116     O->Size     = Read32 (Lib);
117
118     /* Exports */
119     O->ExportSize = Read16 (Lib);
120     O->Exports    = xmalloc (O->ExportSize);
121     ReadData (Lib, O->Exports, O->ExportSize);
122
123     /* Imports */
124     O->ImportSize = Read16 (Lib);
125     O->Imports    = xmalloc (O->ImportSize);
126     ReadData (Lib, O->Imports, O->ImportSize);
127 }
128
129
130
131 static void ReadIndex (void)
132 /* Read the index of a library file */
133 {
134     unsigned Count;
135
136     /* Seek to the start of the index */
137     fseek (Lib, Header.IndexOffs, SEEK_SET);
138
139     /* Read the object file count and calculate the cross ref size */
140     Count = Read16 (Lib);
141
142     /* Read all entries in the index */
143     while (Count--) {
144         ReadIndexEntry ();
145     }
146 }
147
148
149
150 /*****************************************************************************/
151 /*                       Writing file data structures                        */
152 /*****************************************************************************/
153
154
155
156 static void WriteHeader (void)
157 /* Write the header to the library file */
158 {
159     /* Seek to position zero */
160     fseek (NewLib, 0, SEEK_SET);
161
162     /* Write the header fields */
163     Write32 (NewLib, Header.Magic);
164     Write16 (NewLib, Header.Version);
165     Write16 (NewLib, Header.Flags);
166     Write32 (NewLib, Header.IndexOffs);
167 }
168
169
170
171 static void WriteIndexEntry (ObjData* O)
172 /* Write one index entry */
173 {
174     /* Module name/flags/MTime/start/size */
175     WriteStr (NewLib, O->Name);
176     Write16  (NewLib, O->Flags & ~OBJ_HAVEDATA);
177     Write32  (NewLib, O->MTime);
178     Write32  (NewLib, O->Start);
179     Write32  (NewLib, O->Size);
180
181     /* Exports */
182     Write16 (NewLib, O->ExportSize);
183     WriteData (NewLib, O->Exports, O->ExportSize);
184
185     /* Imports */
186     Write16 (NewLib, O->ImportSize);
187     WriteData (NewLib, O->Imports, O->ImportSize);
188 }
189
190
191
192 static void WriteIndex (void)
193 /* Write the index of a library file */
194 {
195     ObjData* O;
196
197     /* Sync I/O in case the last operation was a read */
198     fseek (NewLib, 0, SEEK_CUR);
199
200     /* Remember the current offset in the header */
201     Header.IndexOffs = ftell (NewLib);
202
203     /* Write the object file count */
204     Write16 (NewLib, ObjCount);
205
206     /* Write the object files */
207     O = ObjRoot;
208     while (O) {
209         WriteIndexEntry (O);
210         O = O->Next;
211     }
212 }
213
214
215
216 /*****************************************************************************/
217 /*                             High level stuff                              */
218 /*****************************************************************************/
219
220
221
222 void LibOpen (const char* Name, int MustExist, int NeedTemp)
223 /* Open an existing library and a temporary copy. If MustExist is true, the
224  * old library is expected to exist. If NeedTemp is true, a temporary library
225  * is created.
226  */
227 {
228     /* Remember the name */
229     LibName = xstrdup (Name);
230
231     /* Open the existing library for reading */
232     Lib = fopen (Name, "rb");
233     if (Lib == 0) {
234
235         /* File does not exist */
236         if (MustExist) {
237             Error ("Library `%s' does not exist", Name);
238         } else {
239             Warning ("Library `%s' not found - will be created", Name);
240         }
241
242     } else {
243
244         /* We have an existing file: Read the header */
245         ReadHeader ();
246
247         /* Now read the existing index */
248         ReadIndex ();
249
250     }
251
252     if (NeedTemp) {
253         /* Create the temporary library */
254         NewLib = tmpfile ();
255         if (NewLib == 0) {
256             Error ("Cannot create temporary file: %s", strerror (errno));
257         }
258
259         /* Write a dummy header to the temp file */
260         WriteHeader ();
261     }
262 }
263
264
265
266 unsigned long LibCopyTo (FILE* F, unsigned long Bytes)
267 /* Copy data from F to the temp library file, return the start position in
268  * the temporary library file.
269  */
270 {
271     unsigned char Buf [4096];
272
273     /* Remember the position */
274     unsigned long Pos = ftell (NewLib);
275
276     /* Copy loop */
277     while (Bytes) {
278         unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
279         ReadData (F, Buf, Count);
280         WriteData (NewLib, Buf, Count);
281         Bytes -= Count;
282     }
283
284     /* Return the start position */
285     return Pos;
286 }
287
288
289
290 void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F)
291 /* Copy data from the library file into another file */
292 {
293     unsigned char Buf [4096];
294
295     /* Seek to the correct position */
296     fseek (Lib, Pos, SEEK_SET);
297
298     /* Copy loop */
299     while (Bytes) {
300         unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
301         ReadData (Lib, Buf, Count);
302         WriteData (F, Buf, Count);
303         Bytes -= Count;
304     }
305 }
306
307
308
309 static unsigned long GetVar (unsigned char** Buf)
310 /* Get a variable sized value from Buf */
311 {
312     unsigned char C;
313     unsigned long V = 0;
314     unsigned Shift = 0;
315     do {
316         /* Read one byte */
317         C = **Buf;
318         ++(*Buf);
319         /* Add this char to the value */
320         V |= ((unsigned long)(C & 0x7F)) << Shift;
321         /* Next value */
322         Shift += 7;
323     } while (C & 0x80);
324
325     /* Return the result */
326     return V;
327 }
328
329
330
331 static void SkipExpr (unsigned char** Buf)
332 /* Skip an expression in Buf */
333 {
334     /* Get the operation and skip it */
335     unsigned char Op = **Buf;
336     ++(*Buf);
337
338     /* Filter leaf nodes */
339     switch (Op) {
340
341         case EXPR_NULL:
342             return;
343
344         case EXPR_LITERAL:
345             /* 32 bit literal value */
346             *Buf += 4;
347             return;
348
349         case EXPR_SYMBOL:
350             /* 16 bit symbol index */
351             *Buf += 2;
352             return;
353
354         case EXPR_SEGMENT:
355             /* 8 bit segment number */
356             *Buf += 1;
357             return;
358     }
359
360     /* What's left are unary and binary nodes */
361     SkipExpr (Buf);             /* Skip left */
362     SkipExpr (Buf);             /* Skip right */
363 }
364
365
366
367 static void SkipFilePos (unsigned char** Buf)
368 /* Skip a file position in Buf */
369 {
370     (void) GetVar (Buf);        /* Line */
371     (void) GetVar (Buf);        /* Col */
372     (void) GetVar (Buf);        /* Name */
373 }
374
375
376
377 static void LibCheckExports (ObjData* O)
378 /* Insert all exports from the given object file into the global list
379  * checking for duplicates.
380  */
381 {
382     /* Get a pointer to the buffer */
383     unsigned char* Exports = O->Exports;
384
385     /* Get the export count */
386     unsigned Count = GetVar (&Exports);
387
388     /* Read the exports */
389     Print (stdout, 1, "Module `%s' (%u exports):\n", O->Name, Count);
390     while (Count--) {
391
392         unsigned char   Tag;
393         unsigned        Len;
394         char*           Name;
395
396         /* Get the export tag */
397         Tag = *Exports++;
398
399         /* condes decls may follow */
400         Exports += GET_EXP_CONDES_COUNT (Tag);
401
402         /* Next thing is name of symbol */
403         Len = GetVar (&Exports);
404         Name = xmalloc (Len + 1);
405         memcpy (Name, Exports, Len);
406         Name [Len] = '\0';
407         Exports += Len;
408
409         /* Skip value of symbol */
410         if (Tag & EXP_EXPR) {
411             /* Expression tree */
412             SkipExpr (&Exports);
413         } else {
414             /* Constant 32 bit value */
415             Exports += 4;
416         }
417
418         /* Skip the position */
419         SkipFilePos (&Exports);
420
421         /* Insert the name into the hash table */
422         Print (stdout, 1, "  %s\n", Name);
423         ExpInsert (Name, O->Index);
424
425         /* Free the name */
426         xfree (Name);
427     }
428 }
429
430
431
432 void LibClose (void)
433 /* Write remaining data, close both files and copy the temp file to the old
434  * filename
435  */
436 {
437     /* Do we have a temporary library? */
438     if (NewLib) {
439
440         unsigned I;
441         unsigned char Buf [4096];
442         size_t Count;
443
444         /* Index the object files and make an array containing the objects */
445         MakeObjPool ();
446
447         /* Walk through the object file list, inserting exports into the
448          * export list checking for duplicates. Copy any data that is still
449          * in the old library into the new one.
450          */
451         for (I = 0; I < ObjCount; ++I) {
452
453             /* Get a pointer to the object */
454             ObjData* O = ObjPool [I];
455
456             /* Check exports, make global export table */
457             LibCheckExports (O);
458
459             /* Copy data if needed */
460             if ((O->Flags & OBJ_HAVEDATA) == 0) {
461                 /* Data is still in the old library */
462                 fseek (Lib, O->Start, SEEK_SET);
463                 O->Start = ftell (NewLib);
464                 LibCopyTo (Lib, O->Size);
465                 O->Flags |= OBJ_HAVEDATA;
466             }
467         }
468
469         /* Write the index */
470         WriteIndex ();
471
472         /* Write the updated header */
473         WriteHeader ();
474
475         /* Close the file */
476         if (Lib && fclose (Lib) != 0) {
477             Error ("Error closing library: %s", strerror (errno));
478         }
479
480         /* Reopen the library and truncate it */
481         Lib = fopen (LibName, "wb");
482         if (Lib == 0) {
483             Error ("Cannot open library `%s' for writing: %s",
484                    LibName, strerror (errno));
485         }
486
487         /* Copy the new library to the new one */
488         fseek (NewLib, 0, SEEK_SET);
489         while ((Count = fread (Buf, 1, sizeof (Buf), NewLib)) != 0) {
490             if (fwrite (Buf, 1, Count, Lib) != Count) {
491                 Error ("Cannot write to `%s': %s", LibName, strerror (errno));
492             }
493         }
494     }
495
496     /* Close both files */
497     if (Lib && fclose (Lib) != 0) {
498         Error ("Problem closing `%s': %s", LibName, strerror (errno));
499     }
500     if (NewLib && fclose (NewLib) != 0) {
501         Error ("Problem closing temporary library file: %s", strerror (errno));
502     }
503 }
504
505
506