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