* asranlib/asranlib.c, link/lkar.h, link/lkar.c:
[fw/sdcc] / as / link / z80 / lkarea.c
1 /* lkarea.c
2
3    Copyright (C) 1989-1995 Alan R. Baldwin
4    721 Berkeley St., Kent, Ohio 44240
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
9 later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include "aslink.h"
22
23 /*)Module       lkarea.c
24  *
25  *      The module lkarea.c contains the functions which
26  *      create and link together all area definitions read
27  *      from the .rel file(s).
28  *
29  *      lkarea.c contains the following functions:
30  *              VOID    lnkarea()
31  *              VOID    lnksect()
32  *              VOID    lkparea()
33  *              VOID    newarea()
34  *
35  *      lkarea.c contains no global variables.
36  */
37
38 /*)Function     VOID    newarea()
39  *
40  *      The function newarea() creates and/or modifies area
41  *      and areax structures for each A directive read from
42  *      the .rel file(s).  The function lkparea() is called
43  *      to find the area structure associated with this name.
44  *      If the area does not yet exist then a new area
45  *      structure is created and linked to any existing
46  *      linked area structures. The area flags are copied
47  *      into the area flag variable.  For each occurence of
48  *      an A directive an areax structure is created and
49  *      linked to the areax structures associated with this
50  *      area.  The size of this area section is placed into
51  *      the areax structure.  The flag value for all subsequent
52  *      area definitions for the same area are compared and
53  *      flagged as an error if they are not identical.
54  *      The areax structure created for every occurence of
55  *      an A directive is loaded with a pointer to the base
56  *      area structure and a pointer to the associated
57  *      head structure.  And finally, a pointer to this
58  *      areax structure is loaded into the list of areax
59  *      structures in the head structure.  Refer to lkdata.c
60  *      for details of the structures and their linkage.
61  *
62  *      local variables:
63  *              areax **halp            pointer to an array of pointers
64  *              int     i               counter, loop variable, value
65  *              char    id[]            id string
66  *              int     narea           number of areas in this head structure
67  *              areax * taxp            pointer to an areax structure
68  *                                      to areax structures
69  *
70  *      global variables:
71  *              area    *ap             Pointer to the current
72  *                                      area structure
73  *              areax   *axp            Pointer to the current
74  *                                      areax structure
75  *              head    *hp             Pointer to the current
76  *                                      head structure
77  *              int     lkerr           error flag
78  *
79  *      functions called:
80  *              Addr_T  eval()          lkeval.c
81  *              VOID    exit()          c_library
82  *              int     fprintf()       c_library
83  *              VOID    getid()         lklex.c
84  *              VOID    lkparea()       lkarea.c
85  *              VOID    skip()          lklex.c
86  *
87  *      side effects:
88  *              The area and areax structures are created and
89  *              linked with the appropriate head structures.
90  *              Failure to allocate area or areax structure
91  *              space will terminate the linker.  Other internal
92  *              errors most likely caused by corrupted .rel
93  *              files will also terminate the linker.
94  */
95
96 /*
97  * Create an area entry.
98  *
99  * A xxxxxx size nnnn flags mm
100  *   |           |          |
101  *   |           |          `--  ap->a_flag
102  *   |           `------------- axp->a_size
103  *   `-------------------------  ap->a_id
104  *
105  */
106 VOID
107 newarea()
108 {
109         register int i, narea;
110         struct areax *taxp;
111         struct areax **halp;
112         char id[NCPS];
113
114         /*
115          * Create Area entry
116          */
117         getid(id, -1);
118         lkparea(id);
119         /*
120          * Evaluate area size
121          */
122         skip(-1);
123         axp->a_size = eval();
124         /*
125          * Evaluate flags
126          */
127         skip(-1);
128         i = 0;
129         taxp = ap->a_axp;
130         while (taxp->a_axp) {
131                 ++i;
132                 taxp = taxp->a_axp;
133         }
134         if (i == 0) {
135                 ap->a_flag = eval();
136         } else {
137                 i = eval();
138                 if (i && (ap->a_flag != i)) {
139                     fprintf(stderr, "Conflicting flags in area %.8s\n", id);
140                     lkerr++;
141                 }
142         }
143         /*
144          * Place pointer in header area list
145          */
146         if (headp == NULL) {
147                 fprintf(stderr, "No header defined\n");
148                 lkexit(1);
149         }
150         narea = hp->h_narea;
151         halp = hp->a_list;
152         for (i=0; i < narea ;++i) {
153                 if (halp[i] == NULL) {
154                         halp[i] = taxp;
155                         return;
156                 }
157         }
158         fprintf(stderr, "Header area list overflow\n");
159         lkexit(1);
160 }
161
162 /*)Function     VOID    lkparea(id)
163  *
164  *              char *  id              pointer to the area name string
165  *
166  *      The function lkparea() searches the linked area structures
167  *      for a name match.  If the name is not found then an area
168  *      structure is created.  An areax structure is created and
169  *      appended to the areax structures linked to the area structure.
170  *      The associated base area and head structure pointers are
171  *      loaded into the areax structure.
172  *
173  *      local variables:
174  *              area *  tap             pointer to an area structure
175  *              areax * taxp            pointer to an areax structure
176  *
177  *      global variables:
178  *              area    *ap             Pointer to the current
179  *                                      area structure
180  *              area    *areap          The pointer to the first
181  *                                      area structure of a linked list
182  *              areax   *axp            Pointer to the current
183  *                                      areax structure
184  *
185  *      functions called:
186  *              VOID *  new()           lksym()
187  *              char *  strcpy()        c_library
188  *              int     symeq()         lksym.c
189  *
190  *      side effects:
191  *              Area and/or areax structures are created.
192  *              Failure to allocate space for created structures
193  *              will terminate the linker.
194  */
195
196 VOID
197 lkparea(char *id)
198 {
199         register struct area *tap;
200         register struct areax *taxp;
201
202         ap = areap;
203         axp = (struct areax *) new (sizeof(struct areax));
204         while (ap) {
205                 if (symeq(id, ap->a_id)) {
206                         taxp = ap->a_axp;
207                         while (taxp->a_axp)
208                                 taxp = taxp->a_axp;
209                         taxp->a_axp = axp;
210                         axp->a_bap = ap;
211                         axp->a_bhp = hp;
212                         return;
213                 }
214                 ap = ap->a_ap;
215         }
216         ap = (struct area *) new (sizeof(struct area));
217         if (areap == NULL) {
218                 areap = ap;
219         } else {
220                 tap = areap;
221                 while (tap->a_ap)
222                         tap = tap->a_ap;
223                 tap->a_ap = ap;
224         }
225         ap->a_axp = axp;
226         axp->a_bap = ap;
227         axp->a_bhp = hp;
228         strncpy(ap->a_id, id, NCPS);
229         ap->a_addr = 0;
230 }
231
232 /*)Function     VOID    lnkarea()
233  *
234  *      The function lnkarea() resolves all area addresses.
235  *      The function evaluates each area structure (and all
236  *      the associated areax structures) in sequence.  The
237  *      linking process supports four (4) possible area types:
238  *
239  *      ABS/OVR -       All sections (each individual areax
240  *                      section) starts at the identical base
241  *                      area address overlaying all other
242  *                      areax sections for this area.  The
243  *                      size of the area is largest of the area
244  *                      sections.
245  *
246  *      ABS/CON -       All sections (each individual areax
247  *                      section) are concatenated with the
248  *                      first section starting at the base
249  *                      area address.  The size of the area
250  *                      is the sum of the section sizes.
251  *
252  *              NOTE:   Multiple absolute (ABS) areas are
253  *                      never concatenated with each other,
254  *                      thus absolute area A and absolute area
255  *                      B will overlay each other if they begin
256  *                      at the same location (the default is
257  *                      always address 0 for absolute areas).
258  *
259  *      REL/OVR -       All sections (each individual areax
260  *                      section) starts at the identical base
261  *                      area address overlaying all other
262  *                      areax sections for this area.  The
263  *                      size of the area is largest of the area
264  *                      sections.
265  *
266  *      REL/CON -       All sections (each individual areax
267  *                      section) are concatenated with the
268  *                      first section starting at the base
269  *                      area address.  The size of the area
270  *                      is the sum of the section sizes.
271  *
272  *              NOTE:   Relocatable (REL) areas are always concatenated
273  *                      with each other, thus relocatable area B
274  *                      (defined after area A) will follow
275  *                      relocatable area A independent of the
276  *                      starting address of area A.  Within a
277  *                      specific area each areax section may be
278  *                      overlayed or concatenated with other
279  *                      areax sections.
280  *
281  *
282  *      If a base address for an area is specified then the
283  *      area will start at that address.  Any relocatable
284  *      areas defined subsequently will be concatenated to the
285  *      previous relocatable area if it does not have a base
286  *      address specified.
287  *
288  *      The names s_<areaname> and l_<areaname> are created to
289  *      define the starting address and length of each area.
290  *
291  *      local variables:
292  *              Addr_T  rloc            ;current relocation address
293  *              char    temp[]          ;temporary string
294  *              struct symbol   *sp     ;symbol structure
295  *
296  *      global variables:
297  *              area    *ap             Pointer to the current
298  *                                      area structure
299  *              area    *areap          The pointer to the first
300  *                                      area structure of a linked list
301  *
302  *      functions called:
303  *              int     fprintf()       c_library
304  *              VOID    lnksect()       lkarea.c
305  *              symbol *lkpsym()        lksym.c
306  *              char *  strncpy()       c_library
307  *              int     symeq()         lksym.c
308  *
309  *      side effects:
310  *              All area and areax addresses and sizes are
311  *              determined and saved in their respective
312  *              structures.
313  */
314
315 //unsigned long codemap[2048];
316 //Addr_T lnksect(register struct area *tap);
317 VOID lnksect(register struct area *tap);
318 /*
319  * Resolve all area addresses.
320  */
321 VOID
322 lnkarea()
323 {
324         register Addr_T rloc = 0;
325 //        Addr_T gs_size = 0;
326         char temp[NCPS];
327         struct sym *sp;
328 #if 0
329         struct area *abs_ap = NULL;
330         struct area *gs0_ap = NULL;
331
332         memset(codemap, 0, sizeof(codemap));
333
334         /* first sort all absolute areas to the front */
335         ap = areap;
336         /* no need to check first area, it's in front anyway */
337         while (ap && ap->a_ap)
338         {
339                 if (ap->a_ap->a_flag & A_ABS)
340                 {/* next area is absolute, move it to front,
341                     reversed sequence is no problem for absolutes */
342                         abs_ap = ap->a_ap;
343                         ap->a_ap = abs_ap->a_ap;
344                         abs_ap->a_ap = areap;
345                         areap = abs_ap;
346                 }
347                 else
348                 {
349                         ap = ap->a_ap;
350                 }
351         }
352
353         /* next accumulate all GSINITx/GSFINAL area sizes
354            into GSINIT so they stay together */
355         ap = areap;
356         while (ap)
357         {
358                 if (!strncmp(ap->a_id, "GS", 2))
359                 {/* GSxxxxx area */
360                         if (ap->a_size == 0)
361                         {
362                                 axp = ap->a_axp;
363                                 while (axp)
364                                 {
365                                         ap->a_size += axp->a_size;
366                                         axp = axp->a_axp;
367                                 }
368                         }
369                         gs_size += ap->a_size;
370                         if (!strcmp(ap->a_id, "GSINIT0"))
371                         {/* GSINIT0 area */
372                                 gs0_ap = ap;
373                         }
374                 }
375                 ap = ap->a_ap;
376         }
377         if (gs0_ap)
378                 gs0_ap->a_size = gs_size;
379 #endif
380         ap = areap;
381         while (ap)
382         {
383                 if (ap->a_flag & A_ABS) {
384                         /*
385                          * Absolute sections
386                          */
387                         lnksect(ap);
388                 } else {
389                         /*
390                          * Relocatable sections
391                          */
392                         if (ap->a_addr == 0)
393                                 ap->a_addr = rloc;
394 //                        rloc = lnksect(ap);
395                         lnksect(ap);
396                         rloc = ap->a_addr + ap->a_size;
397                 }
398
399                 /*
400                  * Create symbols called:
401                  *      s_<areaname>    the start address of the area
402                  *      l_<areaname>    the length of the area
403                  */
404
405                 if (! symeq(ap->a_id, _abs_))
406                 {
407                         strncpy(temp+2,ap->a_id,NCPS-2);
408                         *(temp+1) = '_';
409
410                         *temp = 's';
411                         sp = lkpsym(temp, 1);
412                         sp->s_addr = ap->a_addr;
413                         sp->s_axp = NULL;
414                         sp->s_type |= S_DEF;
415
416                         *temp = 'l';
417                         sp = lkpsym(temp, 1);
418                         sp->s_addr = ap->a_size;
419                         sp->s_axp = NULL;
420                         sp->s_type |= S_DEF;
421                 }
422                 ap = ap->a_ap;
423         }
424 }
425 #if 0
426 static
427 Addr_T find_empty_space(Addr_T start, Addr_T size, unsigned long *map)
428 {
429     int i, j, k;
430     unsigned long mask, b;
431
432     while (1)
433     {
434         Addr_T a = start;
435         i = start >> 5;
436         j = (start + size) >> 5;
437         mask = -(1 << (start & 0x1F));
438
439         while (i < j)
440         {
441             if (map[i] & mask)
442             {
443                 k = 32;
444                 for (b=0x80000000; b!=0; b>>=1, k--)
445                 {
446                     if (map[i] & b)
447                       break;
448                 }
449                 start = a + k;
450                 break;
451             }
452             i++;
453             mask = 0xFFFFFFFF;
454             a += 32;
455         }
456         if (start > a)
457           continue;
458
459         mask &= (1 << ((start + size) & 0x1F)) - 1;
460         if (map[i] & mask)
461         {
462             k = 32;
463             for (b=0x80000000; b!=0; b>>=1, k--)
464             {
465                 if (map[i] & b)
466                   break;
467             }
468             start = (a & ~0x1F) + k;
469         }
470         if (start <= a)
471           break;
472     }
473     return start;
474 }
475
476 static
477 Addr_T allocate_space(Addr_T start, Addr_T size, char* id, unsigned long *map)
478 {
479     int i, j;
480     unsigned long mask;
481     Addr_T a = start;
482     i = start >> 5;
483     j = (start + size) >> 5;
484     mask = -(1 << (start & 0x1F));
485
486     while (i < j)
487     {
488         if (map[i] & mask)
489         {
490             fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
491         }
492         map[i++] |= mask;
493         mask = 0xFFFFFFFF;
494         a += 32;
495     }
496     mask &= (1 << ((start + size) & 0x1F)) - 1;
497     if (map[i] & mask)
498     {
499         fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
500     }
501     map[i] |= mask;
502     return start;
503 }
504 #endif
505 /*)Function     VOID    lnksect()
506  *
507  *              area *  tap             pointer to an area structure
508  *
509  *      The function lnksect() is the function called by
510  *      lnkarea() to resolve the areax addresses.  Refer
511  *      to the function lnkarea() for more detail. Pageing
512  *      boundary and length errors will be reported by this
513  *      function.
514  *
515  *      local variables:
516  *              Addr_T  size            size of area
517  *              Addr_T  addr            address of area
518  *              areax * taxp            pointer to an areax structure
519  *
520  *      global variables:
521  *              int     lkerr           error flag
522  *
523  *      functions called:
524  *              none
525  *
526  *      side effects:
527  *              All area and areax addresses and sizes area determined
528  *              and linked into the structures.
529  */
530
531 VOID lnksect(register struct area *tap)
532 //Addr_T lnksect(register struct area *tap)
533 {
534         register Addr_T size, addr;
535         register struct areax *taxp;
536
537         size = 0;
538         addr = tap->a_addr;
539         if ((tap->a_flag&A_PAG) && (addr & 0xFF)) {
540             fprintf(stderr,
541             "\n?ASlink-Warning-Paged Area %.8s Boundary Error\n", tap->a_id);
542             lkerr++;
543         }
544
545         taxp = tap->a_axp;
546         if (tap->a_flag & A_OVR) {
547                 /*
548                  * Overlayed sections
549                  */
550                 while (taxp) {
551                         taxp->a_addr = addr;
552                         if (taxp->a_size > size)
553                                 size = taxp->a_size;
554                         taxp = taxp->a_axp;
555                 }
556         }
557 #if 0
558         else if (tap->a_flag & A_ABS)
559         {
560                 /*
561                  * Absolute sections
562                  */
563                 while (taxp)
564                 {
565                         allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap);
566                         taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */
567                         size += taxp->a_size;
568                         taxp = taxp->a_axp;
569                 }
570         }
571 #endif
572         else
573         {
574                 /*
575                  * Concatenated sections
576                  */
577 /*
578                 if (tap->a_size) {
579                         addr = find_empty_space(addr, tap->a_size, codemap);
580                 }
581 */
582                 while (taxp) {
583 /*
584                         //find next unused address now
585                         if (taxp->a_size)
586                         {
587                                 addr = find_empty_space(addr, taxp->a_size, codemap);
588                                 allocate_space(addr, taxp->a_size, tap->a_id, codemap);
589                         }
590 */
591                         taxp->a_addr = addr;
592                         addr += taxp->a_size;
593                         size += taxp->a_size;
594                         taxp = taxp->a_axp;
595                 }
596         }
597         tap->a_size = size;
598
599         if ((tap->a_flag & A_PAG) && (size > 256))
600         {
601             fprintf(stderr,
602             "\n?ASlink-Warning-Paged Area %.8s Length Error\n", tap->a_id);
603             lkerr++;
604         }
605 //        return addr;
606 }