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);
311 * Resolve all area addresses.
316 register Addr_T rloc = 0;
320 struct area *abs_ap = NULL;
321 struct area *gs0_ap = NULL;
323 memset(codemap, 0, sizeof(codemap));
325 /* first sort all absolute areas to the front */
327 /* no need to check first area, it's in front anyway */
328 while (ap && ap->a_ap)
330 if (ap->a_ap->a_flag & A_ABS)
331 {/* next area is absolute, move it to front,
332 reversed sequence is no problem for absolutes */
334 ap->a_ap = abs_ap->a_ap;
335 abs_ap->a_ap = areap;
344 /* next accumulate all GSINITx/GSFINAL area sizes
345 into GSINIT so they stay together */
349 if (!strncmp(ap->a_id, "GS", 2))
356 ap->a_size += axp->a_size;
360 gs_size += ap->a_size;
361 if (!strcmp(ap->a_id, "GSINIT0"))
369 gs0_ap->a_size = gs_size;
374 if (ap->a_flag & A_ABS) {
381 * Relocatable sections
389 * Create symbols called:
390 * s_<areaname> the start address of the area
391 * l_<areaname> the length of the area
394 if (! symeq(ap->a_id, _abs_))
396 strncpy(temp+2,ap->a_id,NCPS-2);
400 sp = lkpsym(temp, 1);
401 sp->s_addr = ap->a_addr;
406 sp = lkpsym(temp, 1);
407 sp->s_addr = ap->a_size;
416 Addr_T find_empty_space(Addr_T start, Addr_T size, unsigned long *map)
419 unsigned long mask, b;
425 j = (start + size) >> 5;
426 mask = -(1 << (start & 0x1F));
433 for (b=0x80000000; b!=0; b>>=1, k--)
448 mask &= (1 << ((start + size) & 0x1F)) - 1;
452 for (b=0x80000000; b!=0; b>>=1, k--)
457 start = (a & ~0x1F) + k;
466 Addr_T allocate_space(Addr_T start, Addr_T size, char* id, unsigned long *map)
472 j = (start + size) >> 5;
473 mask = -(1 << (start & 0x1F));
479 fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
485 mask &= (1 << ((start + size) & 0x1F)) - 1;
488 fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
494 /*)Function VOID lnksect()
496 * area * tap pointer to an area structure
498 * The function lnksect() is the function called by
499 * lnkarea() to resolve the areax addresses. Refer
500 * to the function lnkarea() for more detail. Pageing
501 * boundary and length errors will be reported by this
505 * Addr_T size size of area
506 * Addr_T addr address of area
507 * areax * taxp pointer to an areax structure
510 * int lkerr error flag
516 * All area and areax addresses and sizes area determined
517 * and linked into the structures.
520 Addr_T lnksect(register struct area *tap)
522 register Addr_T size, addr;
523 register struct areax *taxp;
527 if ((tap->a_flag&A_PAG) && (addr & 0xFF)) {
529 "\n?ASlink-Warning-Paged Area %.8s Boundary Error\n", tap->a_id);
534 if (tap->a_flag & A_OVR) {
540 if (taxp->a_size > size)
545 else if (tap->a_flag & A_ABS)
552 allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap);
553 taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */
554 size += taxp->a_size;
561 * Concatenated sections
564 addr = find_empty_space(addr, tap->a_size, codemap);
567 //find next unused address now
570 addr = find_empty_space(addr, taxp->a_size, codemap);
571 allocate_space(addr, taxp->a_size, tap->a_id, codemap);
574 addr += taxp->a_size;
575 size += taxp->a_size;
581 if ((tap->a_flag & A_PAG) && (size > 256))
584 "\n?ASlink-Warning-Paged Area %.8s Length Error\n", tap->a_id);