1/*****************************************************************************/
2/* */
3/* library.c */
4/* */
5/* Library data structures and helpers for the ld65 linker */
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 "coll.h"
42#include "exprdefs.h"
43#include "libdefs.h"
44#include "objdefs.h"
45#include "symdefs.h"
46#include "xmalloc.h"
47
48/* ld65 */
49#include "error.h"
50#include "exports.h"
51#include "fileio.h"
52#include "library.h"
53#include "objdata.h"
54#include "objfile.h"
55#include "spool.h"
56
57
58
59/*****************************************************************************/
60/* Data */
61/*****************************************************************************/
62
63
64
65/* Library data structure */
66typedef struct Library Library;
67struct Library {
68 unsigned Id; /* Id of library */
69 unsigned Name; /* String id of the name */
70 FILE* F; /* Open file stream */
71 LibHeader Header; /* Library header */
72 Collection Modules; /* Modules */
73};
74
75/* List of open libraries */
76static Collection OpenLibs = STATIC_COLLECTION_INITIALIZER;
77
78/* List of used libraries */
79static Collection LibraryList = STATIC_COLLECTION_INITIALIZER;
80
81/* Flag for library grouping */
82static int Grouping = 0;
83
84
85
86/*****************************************************************************/
87/* struct Library */
88/*****************************************************************************/
89
90
91
92static Library* NewLibrary (FILE* F, const char* Name)
93/* Create a new Library structure and return it */
94{
95 /* Allocate memory */
96 Library* L = xmalloc (sizeof (*L));
97
98 /* Initialize the fields */
99 L->Id = ~0U;
100 L->Name = GetStringId (Name);
101 L->F = F;
102 L->Modules = EmptyCollection;
103
104 /* Return the new struct */
105 return L;
106}
107
108
109
110static void CloseLibrary (Library* L)
111/* Close a library file and remove the list of modules */
112{
113 /* Close the library file */
114 if (fclose (L->F) != 0) {
115 Error ("Error closing '%s': %s", GetString (L->Name), strerror (errno));
116 }
117 L->F = 0;
118}
119
120
121
122static void FreeLibrary (Library* L)
123/* Free a library structure */
124{
125 /* Close the library */
126 CloseLibrary (L);
127
128 /* Free the module index */
129 DoneCollection (&L->Modules);
130
131 /* Free the library structure */
132 xfree (L);
133}
134
135
136
137/*****************************************************************************/
138/* Reading file data structures */
139/*****************************************************************************/
140
141
142
143static void LibSeek (Library* L, unsigned long Offs)
144/* Do a seek in the library checking for errors */
145{
146 if (fseek (L->F, Offs, SEEK_SET) != 0) {
147 Error ("Seek error in '%s' (%lu): %s",
148 GetString (L->Name), Offs, strerror (errno));
149 }
150}
151
152
153
154static void LibReadHeader (Library* L)
155/* Read a library header */
156{
157 /* Read the remaining header fields (magic is already read) */
158 L->Header.Magic = LIB_MAGIC;
159 L->Header.Version = Read16 (L->F);
160 if (L->Header.Version != LIB_VERSION) {
161 Error ("Wrong data version in '%s'", GetString (L->Name));
162 }
163 L->Header.Flags = Read16 (L->F);
164 L->Header.IndexOffs = Read32 (L->F);
165}
166
167
168
169static void LibReadObjHeader (Library* L, ObjData* O)
170/* Read the header of the object file checking the signature */
171{
172 O->Header.Magic = Read32 (L->F);
173 if (O->Header.Magic != OBJ_MAGIC) {
174 Error ("Object file '%s' in library '%s' is invalid",
175 GetObjFileName (O), GetString (L->Name));
176 }
177 O->Header.Version = Read16 (L->F);
178 if (O->Header.Version != OBJ_VERSION) {
179 Error ("Object file '%s' in library '%s' has wrong version",
180 GetObjFileName (O), GetString (L->Name));
181 }
182 O->Header.Flags = Read16 (L->F);
183 O->Header.OptionOffs = Read32 (L->F);
184 O->Header.OptionSize = Read32 (L->F);
185 O->Header.FileOffs = Read32 (L->F);
186 O->Header.FileSize = Read32 (L->F);
187 O->Header.SegOffs = Read32 (L->F);
188 O->Header.SegSize = Read32 (L->F);
189 O->Header.ImportOffs = Read32 (L->F);
190 O->Header.ImportSize = Read32 (L->F);
191 O->Header.ExportOffs = Read32 (L->F);
192 O->Header.ExportSize = Read32 (L->F);
193 O->Header.DbgSymOffs = Read32 (L->F);
194 O->Header.DbgSymSize = Read32 (L->F);
195 O->Header.LineInfoOffs = Read32 (L->F);
196 O->Header.LineInfoSize = Read32 (L->F);
197 O->Header.StrPoolOffs = Read32 (L->F);
198 O->Header.StrPoolSize = Read32 (L->F);
199 O->Header.AssertOffs = Read32 (L->F);
200 O->Header.AssertSize = Read32 (L->F);
201 O->Header.ScopeOffs = Read32 (L->F);
202 O->Header.ScopeSize = Read32 (L->F);
203 O->Header.SpanOffs = Read32 (L->F);
204 O->Header.SpanSize = Read32 (L->F);
205}
206
207
208
209static ObjData* ReadIndexEntry (Library* L)
210/* Read one entry in the index */
211{
212 /* Create a new entry and insert it into the list */
213 ObjData* O = NewObjData ();
214
215 /* Remember from which library this module is */
216 O->Lib = L;
217
218 /* Module name */
219 O->Name = ReadStr (L->F);
220
221 /* Module flags/MTime/Start/Size */
222 O->Flags = Read16 (L->F);
223 O->MTime = Read32 (L->F);
224 O->Start = Read32 (L->F);
225 Read32 (L->F); /* Skip Size */
226
227 /* Done */
228 return O;
229}
230
231
232
233static void ReadBasicData (Library* L, ObjData* O)
234/* Read basic data for an object file that is necessary to resolve external
235** references.
236*/
237{
238 /* Seek to the start of the object file and read the header */
239 LibSeek (L, O->Start);
240 LibReadObjHeader (L, O);
241
242 /* Read the string pool */
243 ObjReadStrPool (L->F, O->Start + O->Header.StrPoolOffs, O);
244
245 /* Read the files list */
246 ObjReadFiles (L->F, O->Start + O->Header.FileOffs, O);
247
248 /* Read the line infos */
249 ObjReadLineInfos (L->F, O->Start + O->Header.LineInfoOffs, O);
250
251 /* Read the imports */
252 ObjReadImports (L->F, O->Start + O->Header.ImportOffs, O);
253
254 /* Read the exports */
255 ObjReadExports (L->F, O->Start + O->Header.ExportOffs, O);
256}
257
258
259
260static void LibReadIndex (Library* L)
261/* Read the index of a library file */
262{
263 unsigned ModuleCount, I;
264
265 /* Seek to the start of the index */
266 LibSeek (L, L->Header.IndexOffs);
267
268 /* Read the object file count and allocate memory */
269 ModuleCount = ReadVar (L->F);
270 CollGrow (&L->Modules, ModuleCount);
271
272 /* Read all entries in the index */
273 while (ModuleCount--) {
274 CollAppend (&L->Modules, ReadIndexEntry (L));
275 }
276
277 /* Walk over the index and read basic data for all object files in the
278 ** library.
279 */
280 for (I = 0; I < CollCount (&L->Modules); ++I) {
281 ReadBasicData (L, CollAtUnchecked (&L->Modules, I));
282 }
283}
284
285
286
287/*****************************************************************************/
288/* High level stuff */
289/*****************************************************************************/
290
291
292
293static void LibCheckExports (ObjData* O)
294/* Check if the exports from this file can satisfy any import requests. If so,
295** insert the imports and exports from this file and mark the file as added.
296*/
297{
298 unsigned I;
299
300 /* Check all exports */
301 for (I = 0; I < CollCount (&O->Exports); ++I) {
302 const Export* E = CollConstAt (&O->Exports, I);
303 if (IsUnresolved (E->Name)) {
304 /* We need this module, insert the imports and exports */
305 O->Flags |= OBJ_REF;
306 InsertObjGlobals (O);
307 break;
308 }
309 }
310}
311
312
313
314static void LibOpen (FILE* F, const char* Name)
315/* Open the library for use */
316{
317 /* Create a new library structure */
318 Library* L = NewLibrary (F, Name);
319
320 /* Read the remaining header fields (magic is already read) */
321 LibReadHeader (L);
322
323 /* Seek to the index position and read the index */
324 LibReadIndex (L);
325
326 /* Add the library to the list of open libraries */
327 CollAppend (&OpenLibs, L);
328}
329
330
331
332static void LibResolve (void)
333/* Resolve all externals from the list of all currently open libraries */
334{
335 unsigned I, J;
336 unsigned Additions;
337
338 /* Walk repeatedly over all open libraries until there's nothing more
339 ** to add.
340 */
341 do {
342
343 Additions = 0;
344
345 /* Walk over all libraries */
346 for (I = 0; I < CollCount (&OpenLibs); ++I) {
347
348 /* Get the next library */
349 Library* L = CollAt (&OpenLibs, I);
350
351 /* Walk through all modules in this library and check for each
352 ** module if there are unresolved externals in existing modules
353 ** that may be resolved by adding the module.
354 */
355 for (J = 0; J < CollCount (&L->Modules); ++J) {
356
357 /* Get the next module */
358 ObjData* O = CollAtUnchecked (&L->Modules, J);
359
360 /* We only need to check this module if it wasn't added before */
361 if ((O->Flags & OBJ_REF) == 0) {
362 LibCheckExports (O);
363 if (O->Flags & OBJ_REF) {
364 /* The routine added the file */
365 ++Additions;
366 }
367 }
368 }
369 }
370
371 } while (Additions > 0);
372
373 /* We do know now which modules must be added, so we can load the data
374 ** for these modues into memory. Since we're walking over all modules
375 ** anyway, we will also remove data for unneeded modules.
376 */
377 for (I = 0; I < CollCount (&OpenLibs); ++I) {
378
379 /* Get the next library */
380 Library* L = CollAt (&OpenLibs, I);
381
382 /* Walk over all modules in this library and add the files list and
383 ** sections for all referenced modules.
384 */
385 J = 0;
386 while (J < CollCount (&L->Modules)) {
387
388 /* Get the object data */
389 ObjData* O = CollAtUnchecked (&L->Modules, J);
390
391 /* Is this object file referenced? */
392 if (O->Flags & OBJ_REF) {
393
394 /* Seek to the start of the debug info and read the debug info */
395 ObjReadDbgSyms (L->F, O->Start + O->Header.DbgSymOffs, O);
396
397 /* Read the assertions from the object file */
398 ObjReadAssertions (L->F, O->Start + O->Header.AssertOffs, O);
399
400 /* Seek to the start of the segment list and read the segments.
401 ** This must be late, since the data here may reference other
402 ** stuff.
403 */
404 ObjReadSections (L->F, O->Start + O->Header.SegOffs, O);
405
406 /* Read the scope table from the object file. Scopes reference
407 ** segments, so we must read them after the sections.
408 */
409 ObjReadScopes (L->F, O->Start + O->Header.ScopeOffs, O);
410
411 /* Read the spans */
412 ObjReadSpans (L->F, O->Start + O->Header.SpanOffs, O);
413
414 /* All references to strings are now resolved, so we can delete
415 ** the module string pool.
416 */
417 FreeObjStrings (O);
418
419 /* Insert the object into the list of all used object files */
420 InsertObjData (O);
421
422 /* Process next object file in library */
423 ++J;
424
425 } else {
426
427 /* Unreferenced object file, remove it */
428 FreeObjData (O);
429 CollDelete (&L->Modules, J);
430
431 }
432 }
433
434 /* If we have referenced modules in this library, assign it an id
435 ** (which is the index in the library collection) and keep it.
436 */
437 if (CollCount (&L->Modules) > 0) {
438 CloseLibrary (L);
439 L->Id = CollCount (&LibraryList);
440 CollAppend (&LibraryList, L);
441 } else {
442 /* Delete the library */
443 FreeLibrary (L);
444 CollDelete (&OpenLibs, I);
445 }
446 }
447
448 /* We're done with all open libraries, clear the OpenLibs collection */
449 CollDeleteAll (&OpenLibs);
450}
451
452
453
454void LibAdd (FILE* F, const char* Name)
455/* Add files from the library to the list if there are references that could
456** be satisfied.
457*/
458{
459 /* Add the library to the list of open libraries */
460 LibOpen (F, Name);
461
462 /* If there is no library group open, just resolve all open symbols and
463 ** close the library. Otherwise we will do nothing because resolving will
464 ** be done when the group is closed.
465 */
466 if (!Grouping) {
467 LibResolve ();
468 }
469}
470
471
472
473void LibStartGroup (void)
474/* Start a library group. Objects within a library group may reference each
475** other, and libraries are searched repeatedly until all references are
476** satisfied.
477*/
478{
479 /* We cannot already have a group open */
480 if (Grouping) {
481 Error ("There's already a library group open");
482 }
483
484 /* Start a new group */
485 Grouping = 1;
486}
487
488
489
490void LibEndGroup (void)
491/* End a library group and resolve all open references. Objects within a
492** library group may reference each other, and libraries are searched
493** repeatedly until all references are satisfied.
494*/
495{
496 /* We must have a library group open */
497 if (!Grouping) {
498 Error ("There's no library group open");
499 }
500
501 /* Resolve symbols, end the group */
502 LibResolve ();
503 Grouping = 0;
504}
505
506
507
508void LibCheckGroup (void)
509/* Check if there are open library groups */
510{
511 if (Grouping) {
512 Error ("Library group was never closed");
513 }
514}
515
516
517
518const char* GetLibFileName (const Library* L)
519/* Get the name of a library */
520{
521 return GetString (L->Name);
522}
523
524
525
526unsigned GetLibId (const Library* L)
527/* Get the id of a library file. */
528{
529 return L->Id;
530}
531
532
533
534unsigned LibraryCount (void)
535/* Return the total number of libraries */
536{
537 return CollCount (&LibraryList);
538}
539
540
541
542void PrintDbgLibraries (FILE* F)
543/* Output the libraries to a debug info file */
544{
545 unsigned I;
546
547 /* Output information about all libraries */
548 for (I = 0; I < CollCount (&LibraryList); ++I) {
549 /* Get the library */
550 const Library* L = CollAtUnchecked (&LibraryList, I);
551
552 /* Output the info */
553 fprintf (F, "lib\tid=%u,name=\"%s\"\n", L->Id, GetString (L->Name));
554 }
555}
556