d45c0c39e1e8d11d9d20d64de2fecdd66a1d69c6
[fw/sdcc] / as / link / lksdcclib.c
1 /* lksdcclib.c - sdcc library format handling
2
3    Copyright (C) 1989-1995 Alan R. Baldwin
4    721 Berkeley St., Kent, Ohio 44240
5    Copyright (C) 2008 Borut Razem, borut dot razem at siol dot net
6
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 /*
22  * With contributions for the
23  * object libraries from
24  * Ken Hornstein
25  * kenh@cmf.nrl.navy.mil
26  *
27  */
28
29 /*
30  * Extensions: P. Felber
31  */
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "getline.h"
37 #include "aslink.h"
38 #include "lklibr.h"
39 #include "lkrel.h"
40
41 #define EQ(A,B) !strcmp((A),(B))
42 #define MAXLINE 254             /*when using getline */
43
44
45 static int
46 is_sdcclib (FILE * libfp)
47 {
48 #define SDCCLIB_MAGIC "<SDCCLIB>"
49 #define SDCCLIB_MAGIC_LEN (sizeof ("<SDCCLIB>") - 1)
50
51   char buf[SDCCLIB_MAGIC_LEN];
52
53   if (fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, SDCCLIB_MAGIC, SDCCLIB_MAGIC_LEN) == 0)
54     {
55       switch (getc (libfp))
56         {
57         case '\r':
58           if (getc (libfp) == '\n')
59             return 1;
60
61         case '\n':
62           return 1;
63         }
64     }
65   rewind (libfp);
66   return 0;
67 }
68
69 /* Load a .rel file embedded in a sdcclib file */
70 static int
71 LoadRel (char *libfname, FILE * libfp, char *ModName)
72 {
73   char str[NINPUT];
74   int state = 0;
75
76   while (getline (str, sizeof (str), libfp) != NULL)
77     {
78       switch (state)
79         {
80         case 0:
81           if (EQ (str, "<FILE>"))
82             {
83               if (NULL != getline (str, sizeof (str), libfp) && EQ (str, ModName))
84                 state = 1;
85               else
86                 return 0;
87             }
88           else
89             return 0;
90           break;
91
92         case 1:
93           return EQ (str, "<REL>") ? load_rel (libfp, -1) : 0;
94         }
95     }
96
97   return 0;
98 }
99
100 #ifdef INDEXLIB
101 static pmlibraryfile
102 buildlibraryindex_sdcclib (struct lbname *lbnh, FILE * libfp, pmlibraryfile This, int type)
103 {
104   char FLine[MAXLINE];
105   int state = 0;
106   long IndexOffset = 0;
107   pmlibrarysymbol ThisSym = NULL;
108
109   while (getline (FLine, sizeof (FLine), libfp))
110     {
111       switch (state)
112         {
113         case 0:
114           if (EQ (FLine, "<INDEX>"))
115             {
116               /*The next line has the size of the index */
117               getline (FLine, sizeof (FLine), libfp);
118               IndexOffset = atol (FLine);
119               state = 1;
120             }
121           break;
122
123         case 1:
124           if (EQ (FLine, "<MODULE>"))
125             {
126               char buff[PATH_MAX];
127               char ModName[NCPS] = "";
128               long FileOffset;
129
130               /* The next line has the name of the module and the offset
131                  of the corresponding embedded file in the library */
132               getline (FLine, sizeof (FLine), libfp);
133               sscanf (FLine, "%s %ld", ModName, &FileOffset);
134               state = 2;
135
136               /* Create a new libraryfile object for this module */
137               if (libr == NULL)
138                 {
139                   libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
140                 }
141               else
142                 {
143                   This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
144                   This = This->next;
145                 }
146               This->next = NULL;
147               This->loaded = -1;
148               This->offset = FileOffset + IndexOffset;
149               This->libspc = lbnh->libspc;
150               This->relfil = strdup (ModName);
151               sprintf (buff, "%s%s%c%s", lbnh->path, ModName, FSEPX, LKOBJEXT);
152               This->filspc = strdup (buff);
153               This->type = type;
154
155               This->symbols = ThisSym = NULL;   /* Start a new linked list of symbols */
156             }
157           else if (EQ (FLine, "</INDEX>"))
158             {
159               return This;      /* Finish, get out of here */
160             }
161           break;
162
163         case 2:
164           if (EQ (FLine, "</MODULE>"))
165             {
166               This->loaded = 0;
167               /* Create the index for the next module */
168               state = 1;
169             }
170           else
171             {
172               /* Add the symbols */
173               if (ThisSym == NULL)      /* First symbol of the current module */
174                 {
175                   ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
176                 }
177               else
178                 {
179                   ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
180                   ThisSym = ThisSym->next;
181                 }
182               ThisSym->next = NULL;
183               ThisSym->name = strdup (FLine);
184             }
185           break;
186
187         default:
188           return This;          /* State machine should never reach this point, but just in case... */
189           break;
190         }
191     }
192
193   return This;                  /* State machine should never reach this point, but just in case... */
194 }
195
196 #else
197
198 /* Load an .adb file embedded in a sdcclib file. If there is
199 something between <ADB> and </ADB> returns 1, otherwise returns 0.
200 This way the aomf51 will not have useless empty modules. */
201
202 static int
203 LoadAdb (FILE * libfp)
204 {
205   char str[MAXLINE];
206   int state = 0;
207   int ret = 0;
208
209   while (getline (str, sizeof (str), libfp) != NULL)
210     {
211       switch (state)
212         {
213         case 0:
214           if (EQ (str, "<ADB>"))
215             state = 1;
216           break;
217
218         case 1:
219           if (EQ (str, "</ADB>"))
220             return ret;
221           fprintf (dfp, "%s\n", str);
222           ret = 1;
223           break;
224         }
225     }
226   return ret;
227 }
228
229 /* Check for a symbol in a SDCC library. If found, add the embedded .rel and
230    .adb files from the library.  The library must be created with the SDCC
231    librarian 'sdcclib' since the linking process depends on the correct file offsets
232    embedded in the library file. */
233
234 static int
235 findsym_sdcclib (const char *name, struct lbname *lbnh, FILE * libfp, int type)
236 {
237   struct lbfile *lbfh;
238   char ModName[NCPS] = "";
239   char FLine[MAXLINE];
240   int state = 0;
241   long IndexOffset = 0, FileOffset;
242
243   while (getline (FLine, sizeof (FLine), libfp))
244     {
245       char filspc[PATH_MAX];
246
247       if (lbnh->path != NULL)
248         {
249           strcpy (filspc, lbnh->path);
250 #ifdef  OTHERSYSTEM
251           if (*filspc != '\0' && (filspc[strlen (filspc) - 1] != '/') && (filspc[strlen (filspc) - 1] != LKDIRSEP))
252             {
253               strcat (filspc, LKDIRSEPSTR);
254             }
255 #endif
256         }
257
258       switch (state)
259         {
260         case 0:
261           if (EQ (FLine, "<INDEX>"))
262             {
263               /* The next line has the size of the index */
264               getline (FLine, sizeof (FLine), libfp);
265               IndexOffset = atol (FLine);
266               state = 1;
267             }
268           break;
269
270         case 1:
271           if (EQ (FLine, "<MODULE>"))
272             {
273               /* The next line has the name of the module and the offset
274                  of the corresponding embedded file in the library */
275               getline (FLine, sizeof (FLine), libfp);
276               sscanf (FLine, "%s %ld", ModName, &FileOffset);
277               state = 2;
278             }
279           else if (EQ (FLine, "</INDEX>"))
280             {
281               /* Reached the end of the index.  The symbol is not in this library. */
282               return 0;
283             }
284           break;
285
286         case 2:
287           if (EQ (FLine, "</MODULE>"))
288             {
289               /* The symbol is not in this module, try the next one */
290               state = 1;
291             }
292           else
293             {
294               /* Check if this is the symbol we are looking for. */
295               if (strncmp (name, FLine, NCPS) == 0)
296                 {
297                   /* The symbol is in this module. */
298
299                   /* As in the original library format, it is assumed that the .rel
300                      files reside in the same directory as the lib files. */
301                   sprintf (&filspc[strlen (filspc)], "%s%c%s", ModName, FSEPX, LKOBJEXT);
302
303                   /* If this module has been loaded already don't load it again. */
304                   if (is_module_loaded (filspc))
305                     return 1;
306
307                   /* Add the embedded file to the list of files to be loaded in
308                      the second pass.  That is performed latter by the function
309                      library() below. */
310                   lbfh = (struct lbfile *) new (sizeof (struct lbfile));
311                   if (lbfhead == NULL)
312                     {
313                       lbfhead = lbfh;
314                     }
315                   else
316                     {
317                       struct lbfile *lbf;
318
319                       for (lbf = lbfhead; lbf->next; lbf = lbf->next)
320                         ;
321
322                       lbf->next = lbfh;
323                     }
324
325                   lbfh->libspc = lbnh->libspc;
326                   lbfh->filspc = strdup (filspc);
327                   lbfh->relfil = strdup (ModName);
328                   /* Library embedded file, so lbfh->offset must be >=0 */
329                   lbfh->offset = IndexOffset + FileOffset;
330
331                   /* Jump to where the .rel begins and load it. */
332                   fseek (libfp, lbfh->offset, SEEK_SET);
333                   if (!LoadRel (lbnh->libspc, libfp, ModName))
334                     {
335                       fclose (libfp);
336                       fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, ModName);
337                       lkexit (1);
338                     }
339                   /* if cdb information required & .adb file present */
340                   if (dflag && dfp)
341                     {
342                       if (LoadAdb (libfp))
343                         SaveLinkedFilePath (filspc);
344                     }
345                   return 1;     /* Found the symbol, so success! */
346                 }
347             }
348           break;
349
350         default:
351           return 0;             /* It should never reach this point, but just in case... */
352           break;
353         }
354     }
355
356   return 0;                     /* The symbol is not in this library */
357 }
358
359 #endif
360
361 static void
362 loadfile_sdcclib (struct lbfile *lbfh)
363 {
364   FILE *fp;
365   int res;
366
367 #ifdef __CYGWIN__
368   char posix_path[PATH_MAX];
369   void cygwin_conv_to_full_posix_path (char *win_path, char *posix_path);
370   cygwin_conv_to_full_posix_path (lbfh->libspc, posix_path);
371   fp = fopen (posix_path, "rb");
372 #else
373   fp = fopen (lbfh->libspc, "rb");
374 #endif
375
376   if (fp != NULL)
377     {
378       fseek (fp, lbfh->offset, SEEK_SET);
379       res = LoadRel (lbfh->libspc, fp, lbfh->relfil);
380       fclose (fp);
381
382       if (!res)
383         {
384           fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, lbfh->relfil);
385           lkexit (1);
386         }
387     }
388   else
389     {
390       fprintf (stderr, "?ASlink-Error-Opening library '%s'\n", lbfh->libspc);
391       lkexit (1);
392     }
393 }
394
395 struct aslib_target aslib_target_sdcclib = {
396   &is_sdcclib,
397 #ifdef INDEXLIB
398   &buildlibraryindex_sdcclib,
399 #else
400   &findsym_sdcclib,
401 #endif
402   &loadfile_sdcclib,
403 };