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