3 Copyright (C) 1989-1995 Alan R. Baldwin
4 721 Berkeley St., Kent, Ohio 44240
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
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.
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/>. */
25 * The module lkarea.c contains the functions which
26 * create and link together all area definitions read
27 * from the .rel file(s).
29 * lkarea.c contains the following functions:
35 * lkarea.c contains no global variables.
38 /*)Function VOID newarea()
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.
63 * areax **halp pointer to an array of pointers
64 * int i counter, loop variable, value
66 * int narea number of areas in this head structure
67 * areax * taxp pointer to an areax structure
71 * area *ap Pointer to the current
73 * areax *axp Pointer to the current
75 * head *hp Pointer to the current
77 * int lkerr error flag
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
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.
97 * Create an area entry.
99 * A xxxxxx size nnnn flags mm
102 * | `------------- axp->a_size
103 * `------------------------- ap->a_id
109 register int i, narea;
123 axp->a_size = eval();
130 while (taxp->a_axp) {
138 if (i && (ap->a_flag != i)) {
139 fprintf(stderr, "Conflicting flags in area %.8s\n", id);
144 * Place pointer in header area list
147 fprintf(stderr, "No header defined\n");
152 for (i=0; i < narea ;++i) {
153 if (halp[i] == NULL) {
158 fprintf(stderr, "Header area list overflow\n");
162 /*)Function VOID lkparea(id)
164 * char * id pointer to the area name string
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.
174 * area * tap pointer to an area structure
175 * areax * taxp pointer to an areax structure
178 * area *ap Pointer to the current
180 * area *areap The pointer to the first
181 * area structure of a linked list
182 * areax *axp Pointer to the current
186 * VOID * new() lksym()
187 * char * strcpy() c_library
188 * int symeq() lksym.c
191 * Area and/or areax structures are created.
192 * Failure to allocate space for created structures
193 * will terminate the linker.
199 register struct area *tap;
200 register struct areax *taxp;
203 axp = (struct areax *) new (sizeof(struct areax));
205 if (symeq(id, ap->a_id)) {
216 ap = (struct area *) new (sizeof(struct area));
228 strncpy(ap->a_id, id, NCPS);
232 /*)Function VOID lnkarea()
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:
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
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.
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).
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
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.
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
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
288 * The names s_<areaname> and l_<areaname> are created to
289 * define the starting address and length of each area.
292 * Addr_T rloc ;current relocation address
293 * char temp[] ;temporary string
294 * struct symbol *sp ;symbol structure
297 * area *ap Pointer to the current
299 * area *areap The pointer to the first
300 * area structure of a linked list
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
310 * All area and areax addresses and sizes are
311 * determined and saved in their respective
315 //unsigned long codemap[2048];
316 //Addr_T lnksect(register struct area *tap);
317 VOID lnksect(register struct area *tap);
319 * Resolve all area addresses.
324 register Addr_T rloc = 0;
325 // Addr_T gs_size = 0;
329 struct area *abs_ap = NULL;
330 struct area *gs0_ap = NULL;
332 memset(codemap, 0, sizeof(codemap));
334 /* first sort all absolute areas to the front */
336 /* no need to check first area, it's in front anyway */
337 while (ap && ap->a_ap)
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 */
343 ap->a_ap = abs_ap->a_ap;
344 abs_ap->a_ap = areap;
353 /* next accumulate all GSINITx/GSFINAL area sizes
354 into GSINIT so they stay together */
358 if (!strncmp(ap->a_id, "GS", 2))
365 ap->a_size += axp->a_size;
369 gs_size += ap->a_size;
370 if (!strcmp(ap->a_id, "GSINIT0"))
378 gs0_ap->a_size = gs_size;
383 if (ap->a_flag & A_ABS) {
390 * Relocatable sections
394 // rloc = lnksect(ap);
396 rloc = ap->a_addr + ap->a_size;
400 * Create symbols called:
401 * s_<areaname> the start address of the area
402 * l_<areaname> the length of the area
405 if (! symeq(ap->a_id, _abs_))
407 strncpy(temp+2,ap->a_id,NCPS-2);
411 sp = lkpsym(temp, 1);
412 sp->s_addr = ap->a_addr;
417 sp = lkpsym(temp, 1);
418 sp->s_addr = ap->a_size;
427 Addr_T find_empty_space(Addr_T start, Addr_T size, unsigned long *map)
430 unsigned long mask, b;
436 j = (start + size) >> 5;
437 mask = -(1 << (start & 0x1F));
444 for (b=0x80000000; b!=0; b>>=1, k--)
459 mask &= (1 << ((start + size) & 0x1F)) - 1;
463 for (b=0x80000000; b!=0; b>>=1, k--)
468 start = (a & ~0x1F) + k;
477 Addr_T allocate_space(Addr_T start, Addr_T size, char* id, unsigned long *map)
483 j = (start + size) >> 5;
484 mask = -(1 << (start & 0x1F));
490 fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
496 mask &= (1 << ((start + size) & 0x1F)) - 1;
499 fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
505 /*)Function VOID lnksect()
507 * area * tap pointer to an area structure
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
516 * Addr_T size size of area
517 * Addr_T addr address of area
518 * areax * taxp pointer to an areax structure
521 * int lkerr error flag
527 * All area and areax addresses and sizes area determined
528 * and linked into the structures.
531 VOID lnksect(register struct area *tap)
532 //Addr_T lnksect(register struct area *tap)
534 register Addr_T size, addr;
535 register struct areax *taxp;
539 if ((tap->a_flag&A_PAG) && (addr & 0xFF)) {
541 "\n?ASlink-Warning-Paged Area %.8s Boundary Error\n", tap->a_id);
546 if (tap->a_flag & A_OVR) {
552 if (taxp->a_size > size)
558 else if (tap->a_flag & A_ABS)
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;
575 * Concatenated sections
579 addr = find_empty_space(addr, tap->a_size, codemap);
584 //find next unused address now
587 addr = find_empty_space(addr, taxp->a_size, codemap);
588 allocate_space(addr, taxp->a_size, tap->a_id, codemap);
592 addr += taxp->a_size;
593 size += taxp->a_size;
599 if ((tap->a_flag & A_PAG) && (size > 256))
602 "\n?ASlink-Warning-Paged Area %.8s Length Error\n", tap->a_id);