4 * (C) Copyright 1989-1995
18 * The module lkarea.c contains the functions which
19 * create and link together all area definitions read
20 * from the .rel file(s).
22 * lkarea.c contains the following functions:
28 * lkarea.c contains no global variables.
31 /*)Function VOID newarea()
33 * The function newarea() creates and/or modifies area
34 * and areax structures for each A directive read from
35 * the .rel file(s). The function lkparea() is called
36 * to find the area structure associated with this name.
37 * If the area does not yet exist then a new area
38 * structure is created and linked to any existing
39 * linked area structures. The area flags are copied
40 * into the area flag variable. For each occurence of
41 * an A directive an areax structure is created and
42 * linked to the areax structures associated with this
43 * area. The size of this area section is placed into
44 * the areax structure. The flag value for all subsequent
45 * area definitions for the same area are compared and
46 * flagged as an error if they are not identical.
47 * The areax structure created for every occurence of
48 * an A directive is loaded with a pointer to the base
49 * area structure and a pointer to the associated
50 * head structure. And finally, a pointer to this
51 * areax structure is loaded into the list of areax
52 * structures in the head structure. Refer to lkdata.c
53 * for details of the structures and their linkage.
56 * areax **halp pointer to an array of pointers
57 * int i counter, loop variable, value
59 * int narea number of areas in this head structure
60 * areax * taxp pointer to an areax structure
64 * area *ap Pointer to the current
66 * areax *axp Pointer to the current
68 * head *hp Pointer to the current
70 * int lkerr error flag
73 * Addr_T eval() lkeval.c
74 * VOID exit() c_library
75 * int fprintf() c_library
76 * VOID getid() lklex.c
77 * VOID lkparea() lkarea.c
81 * The area and areax structures are created and
82 * linked with the appropriate head structures.
83 * Failure to allocate area or areax structure
84 * space will terminate the linker. Other internal
85 * errors most likely caused by corrupted .rel
86 * files will also terminate the linker.
90 * Create an area entry.
92 * A xxxxxx size nnnn flags mm
95 * | `------------- axp->a_size
96 * `------------------------- ap->a_id
102 register int i, narea;
116 axp->a_size = eval();
123 while (taxp->a_axp) {
131 if (i && (ap->a_flag != i)) {
132 fprintf(stderr, "Conflicting flags in area %.8s\n", id);
137 * Place pointer in header area list
140 fprintf(stderr, "No header defined\n");
145 for (i=0; i < narea ;++i) {
146 if (halp[i] == NULL) {
151 fprintf(stderr, "Header area list overflow\n");
155 /*)Function VOID lkparea(id)
157 * char * id pointer to the area name string
159 * The function lkparea() searches the linked area structures
160 * for a name match. If the name is not found then an area
161 * structure is created. An areax structure is created and
162 * appended to the areax structures linked to the area structure.
163 * The associated base area and head structure pointers are
164 * loaded into the areax structure.
167 * area * tap pointer to an area structure
168 * areax * taxp pointer to an areax structure
171 * area *ap Pointer to the current
173 * area *areap The pointer to the first
174 * area structure of a linked list
175 * areax *axp Pointer to the current
179 * VOID * new() lksym()
180 * char * strcpy() c_library
181 * int symeq() lksym.c
184 * Area and/or areax structures are created.
185 * Failure to allocate space for created structures
186 * will terminate the linker.
192 register struct area *tap;
193 register struct areax *taxp;
196 axp = (struct areax *) new (sizeof(struct areax));
198 if (symeq(id, ap->a_id)) {
209 ap = (struct area *) new (sizeof(struct area));
221 strncpy(ap->a_id, id, NCPS);
225 /*)Function VOID lnkarea()
227 * The function lnkarea() resolves all area addresses.
228 * The function evaluates each area structure (and all
229 * the associated areax structures) in sequence. The
230 * linking process supports four (4) possible area types:
232 * ABS/OVR - All sections (each individual areax
233 * section) starts at the identical base
234 * area address overlaying all other
235 * areax sections for this area. The
236 * size of the area is largest of the area
239 * ABS/CON - All sections (each individual areax
240 * section) are concatenated with the
241 * first section starting at the base
242 * area address. The size of the area
243 * is the sum of the section sizes.
245 * NOTE: Multiple absolute (ABS) areas are
246 * never concatenated with each other,
247 * thus absolute area A and absolute area
248 * B will overlay each other if they begin
249 * at the same location (the default is
250 * always address 0 for absolute areas).
252 * REL/OVR - All sections (each individual areax
253 * section) starts at the identical base
254 * area address overlaying all other
255 * areax sections for this area. The
256 * size of the area is largest of the area
259 * REL/CON - All sections (each individual areax
260 * section) are concatenated with the
261 * first section starting at the base
262 * area address. The size of the area
263 * is the sum of the section sizes.
265 * NOTE: Relocatable (REL) areas are always concatenated
266 * with each other, thus relocatable area B
267 * (defined after area A) will follow
268 * relocatable area A independent of the
269 * starting address of area A. Within a
270 * specific area each areax section may be
271 * overlayed or concatenated with other
275 * If a base address for an area is specified then the
276 * area will start at that address. Any relocatable
277 * areas defined subsequently will be concatenated to the
278 * previous relocatable area if it does not have a base
281 * The names s_<areaname> and l_<areaname> are created to
282 * define the starting address and length of each area.
285 * Addr_T rloc ;current relocation address
286 * char temp[] ;temporary string
287 * struct symbol *sp ;symbol structure
290 * area *ap Pointer to the current
292 * area *areap The pointer to the first
293 * area structure of a linked list
296 * int fprintf() c_library
297 * VOID lnksect() lkarea.c
298 * symbol *lkpsym() lksym.c
299 * char * strncpy() c_library
300 * int symeq() lksym.c
303 * All area and areax addresses and sizes are
304 * determined and saved in their respective
308 //unsigned long codemap[2048];
309 //Addr_T lnksect(register struct area *tap);
310 VOID lnksect(register struct area *tap);
312 * Resolve all area addresses.
317 register Addr_T rloc = 0;
318 // Addr_T gs_size = 0;
322 struct area *abs_ap = NULL;
323 struct area *gs0_ap = NULL;
325 memset(codemap, 0, sizeof(codemap));
327 /* first sort all absolute areas to the front */
329 /* no need to check first area, it's in front anyway */
330 while (ap && ap->a_ap)
332 if (ap->a_ap->a_flag & A_ABS)
333 {/* next area is absolute, move it to front,
334 reversed sequence is no problem for absolutes */
336 ap->a_ap = abs_ap->a_ap;
337 abs_ap->a_ap = areap;
346 /* next accumulate all GSINITx/GSFINAL area sizes
347 into GSINIT so they stay together */
351 if (!strncmp(ap->a_id, "GS", 2))
358 ap->a_size += axp->a_size;
362 gs_size += ap->a_size;
363 if (!strcmp(ap->a_id, "GSINIT0"))
371 gs0_ap->a_size = gs_size;
376 if (ap->a_flag & A_ABS) {
383 * Relocatable sections
387 // rloc = lnksect(ap);
389 rloc = ap->a_addr + ap->a_size;
393 * Create symbols called:
394 * s_<areaname> the start address of the area
395 * l_<areaname> the length of the area
398 if (! symeq(ap->a_id, _abs_))
400 strncpy(temp+2,ap->a_id,NCPS-2);
404 sp = lkpsym(temp, 1);
405 sp->s_addr = ap->a_addr;
410 sp = lkpsym(temp, 1);
411 sp->s_addr = ap->a_size;
420 Addr_T find_empty_space(Addr_T start, Addr_T size, unsigned long *map)
423 unsigned long mask, b;
429 j = (start + size) >> 5;
430 mask = -(1 << (start & 0x1F));
437 for (b=0x80000000; b!=0; b>>=1, k--)
452 mask &= (1 << ((start + size) & 0x1F)) - 1;
456 for (b=0x80000000; b!=0; b>>=1, k--)
461 start = (a & ~0x1F) + k;
470 Addr_T allocate_space(Addr_T start, Addr_T size, char* id, unsigned long *map)
476 j = (start + size) >> 5;
477 mask = -(1 << (start & 0x1F));
483 fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
489 mask &= (1 << ((start + size) & 0x1F)) - 1;
492 fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
498 /*)Function VOID lnksect()
500 * area * tap pointer to an area structure
502 * The function lnksect() is the function called by
503 * lnkarea() to resolve the areax addresses. Refer
504 * to the function lnkarea() for more detail. Pageing
505 * boundary and length errors will be reported by this
509 * Addr_T size size of area
510 * Addr_T addr address of area
511 * areax * taxp pointer to an areax structure
514 * int lkerr error flag
520 * All area and areax addresses and sizes area determined
521 * and linked into the structures.
524 VOID lnksect(register struct area *tap)
525 //Addr_T lnksect(register struct area *tap)
527 register Addr_T size, addr;
528 register struct areax *taxp;
532 if ((tap->a_flag&A_PAG) && (addr & 0xFF)) {
534 "\n?ASlink-Warning-Paged Area %.8s Boundary Error\n", tap->a_id);
539 if (tap->a_flag & A_OVR) {
545 if (taxp->a_size > size)
551 else if (tap->a_flag & A_ABS)
558 allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap);
559 taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */
560 size += taxp->a_size;
568 * Concatenated sections
572 addr = find_empty_space(addr, tap->a_size, codemap);
577 //find next unused address now
580 addr = find_empty_space(addr, taxp->a_size, codemap);
581 allocate_space(addr, taxp->a_size, tap->a_id, codemap);
585 addr += taxp->a_size;
586 size += taxp->a_size;
592 if ((tap->a_flag & A_PAG) && (size > 256))
595 "\n?ASlink-Warning-Paged Area %.8s Length Error\n", tap->a_id);