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