431 lines
10 KiB
C
431 lines
10 KiB
C
/* lkarea.c */
|
|
|
|
/*
|
|
* (C) Copyright 1989-1995
|
|
* All Rights Reserved
|
|
*
|
|
* Alan R. Baldwin
|
|
* 721 Berkeley St.
|
|
* Kent, Ohio 44240
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "aslink.h"
|
|
|
|
/*)Module lkarea.c
|
|
*
|
|
* The module lkarea.c contains the functions which
|
|
* create and link together all area definitions read
|
|
* from the .rel file(s).
|
|
*
|
|
* lkarea.c contains the following functions:
|
|
* VOID lnkarea()
|
|
* VOID lnksect()
|
|
* VOID lkparea()
|
|
* VOID newarea()
|
|
*
|
|
* lkarea.c contains no global variables.
|
|
*/
|
|
|
|
/*)Function VOID newarea()
|
|
*
|
|
* The function newarea() creates and/or modifies area
|
|
* and areax structures for each A directive read from
|
|
* the .rel file(s). The function lkparea() is called
|
|
* to find tha area structure associated with this name.
|
|
* If the area does not yet exist then a new area
|
|
* structure is created and linked to any existing
|
|
* linked area structures. The area flags are copied
|
|
* into the area flag variable. For each occurence of
|
|
* an A directive an areax structure is created and
|
|
* linked to the areax structures associated with this
|
|
* area. The size of this area section is placed into
|
|
* the areax structure. The flag value for all subsequent
|
|
* area definitions for the same area are compared and
|
|
* flagged as an error if they are not identical.
|
|
* The areax structure created for every occurence of
|
|
* an A directive is loaded with a pointer to the base
|
|
* area structure and a pointer to the associated
|
|
* head structure. And finally, a pointer to this
|
|
* areax structure is loaded into the list of areax
|
|
* structures in the head structure. Refer to lkdata.c
|
|
* for details of the structures and their linkage.
|
|
*
|
|
* local variables:
|
|
* areax **halp pointer to an array of pointers
|
|
* int i counter, loop variable, value
|
|
* char id[] id string
|
|
* int narea number of areas in this head structure
|
|
* areax * taxp pointer to an areax structure
|
|
* to areax structures
|
|
*
|
|
* global variables:
|
|
* area *ap Pointer to the current
|
|
* area structure
|
|
* areax *axp Pointer to the current
|
|
* areax structure
|
|
* head *hp Pointer to the current
|
|
* head structure
|
|
* int lkerr error flag
|
|
*
|
|
* functions called:
|
|
* Addr_T eval() lkeval.c
|
|
* VOID exit() c_library
|
|
* int fprintf() c_library
|
|
* VOID getid() lklex.c
|
|
* VOID lkparea() lkarea.c
|
|
* VOID skip() lklex.c
|
|
*
|
|
* side effects:
|
|
* The area and areax structures are created and
|
|
* linked with the appropriate head structures.
|
|
* Failure to allocate area or areax structure
|
|
* space will terminate the linker. Other internal
|
|
* errors most likely caused by corrupted .rel
|
|
* files will also terminate the linker.
|
|
*/
|
|
|
|
/*
|
|
* Create an area entry.
|
|
*
|
|
* A xxxxxx size nnnn flags mm
|
|
* | | |
|
|
* | | `-- ap->a_flag
|
|
* | `------------- axp->a_size
|
|
* `------------------------- ap->a_id
|
|
*
|
|
*/
|
|
VOID
|
|
newarea()
|
|
{
|
|
register int i, narea;
|
|
struct areax *taxp;
|
|
struct areax **halp;
|
|
char id[NCPS];
|
|
|
|
/*
|
|
* Create Area entry
|
|
*/
|
|
getid(id, -1);
|
|
lkparea(id);
|
|
/*
|
|
* Evaluate area size
|
|
*/
|
|
skip(-1);
|
|
axp->a_size = eval();
|
|
/*
|
|
* Evaluate flags
|
|
*/
|
|
skip(-1);
|
|
i = 0;
|
|
taxp = ap->a_axp;
|
|
while (taxp->a_axp) {
|
|
++i;
|
|
taxp = taxp->a_axp;
|
|
}
|
|
if (i == 0) {
|
|
ap->a_flag = eval();
|
|
} else {
|
|
i = eval();
|
|
if (i && (ap->a_flag != i)) {
|
|
fprintf(stderr, "Conflicting flags in area %.8s\n", id);
|
|
lkerr++;
|
|
}
|
|
}
|
|
/*
|
|
* Place pointer in header area list
|
|
*/
|
|
if (headp == NULL) {
|
|
fprintf(stderr, "No header defined\n");
|
|
lkexit(1);
|
|
}
|
|
narea = hp->h_narea;
|
|
halp = hp->a_list;
|
|
for (i=0; i < narea ;++i) {
|
|
if (halp[i] == NULL) {
|
|
halp[i] = taxp;
|
|
return;
|
|
}
|
|
}
|
|
fprintf(stderr, "Header area list overflow\n");
|
|
lkexit(1);
|
|
}
|
|
|
|
/*)Function VOID lkparea(id)
|
|
*
|
|
* char * id pointer to the area name string
|
|
*
|
|
* The function lkparea() searches the linked area structures
|
|
* for a name match. If the name is not found then an area
|
|
* structure is created. An areax structure is created and
|
|
* appended to the areax structures linked to the area structure.
|
|
* The associated base area and head structure pointers are
|
|
* loaded into the areax structure.
|
|
*
|
|
* local variables:
|
|
* area * tap pointer to an area structure
|
|
* areax * taxp pointer to an areax structure
|
|
*
|
|
* global variables:
|
|
* area *ap Pointer to the current
|
|
* area structure
|
|
* area *areap The pointer to the first
|
|
* area structure of a linked list
|
|
* areax *axp Pointer to the current
|
|
* areax structure
|
|
*
|
|
* functions called:
|
|
* VOID * new() lksym()
|
|
* char * strcpy() c_library
|
|
* int symeq() lksym.c
|
|
*
|
|
* side effects:
|
|
* Area and/or areax structures are created.
|
|
* Failure to allocate space for created structures
|
|
* will terminate the linker.
|
|
*/
|
|
|
|
VOID
|
|
lkparea(id)
|
|
char *id;
|
|
{
|
|
register struct area *tap;
|
|
register struct areax *taxp;
|
|
|
|
ap = areap;
|
|
axp = (struct areax *) new (sizeof(struct areax));
|
|
while (ap) {
|
|
if (symeq(id, ap->a_id)) {
|
|
taxp = ap->a_axp;
|
|
while (taxp->a_axp)
|
|
taxp = taxp->a_axp;
|
|
taxp->a_axp = axp;
|
|
axp->a_bap = ap;
|
|
axp->a_bhp = hp;
|
|
return;
|
|
}
|
|
ap = ap->a_ap;
|
|
}
|
|
ap = (struct area *) new (sizeof(struct area));
|
|
if (areap == NULL) {
|
|
areap = ap;
|
|
} else {
|
|
tap = areap;
|
|
while (tap->a_ap)
|
|
tap = tap->a_ap;
|
|
tap->a_ap = ap;
|
|
}
|
|
ap->a_axp = axp;
|
|
axp->a_bap = ap;
|
|
axp->a_bhp = hp;
|
|
strncpy(ap->a_id, id, NCPS);
|
|
}
|
|
|
|
/*)Function VOID lnkarea()
|
|
*
|
|
* The function lnkarea() resolves all area addresses.
|
|
* The function evaluates each area structure (and all
|
|
* the associated areax structures) in sequence. The
|
|
* linking process supports four (4) possible area types:
|
|
*
|
|
* ABS/OVR - All sections (each individual areax
|
|
* section) starts at the identical base
|
|
* area address overlaying all other
|
|
* areax sections for this area. The
|
|
* size of the area is largest of the area
|
|
* sections.
|
|
*
|
|
* ABS/CON - All sections (each individual areax
|
|
* section) are concatenated with the
|
|
* first section starting at the base
|
|
* area address. The size of the area
|
|
* is the sum of the section sizes.
|
|
*
|
|
* NOTE: Multiple absolute (ABS) areas are
|
|
* never concatenated with each other,
|
|
* thus absolute area A and absolute area
|
|
* B will overlay each other if they begin
|
|
* at the same location (the default is
|
|
* always address 0 for absolute areas).
|
|
*
|
|
* REL/OVR - All sections (each individual areax
|
|
* section) starts at the identical base
|
|
* area address overlaying all other
|
|
* areax sections for this area. The
|
|
* size of the area is largest of the area
|
|
* sections.
|
|
*
|
|
* REL/CON - All sections (each individual areax
|
|
* section) are concatenated with the
|
|
* first section starting at the base
|
|
* area address. The size of the area
|
|
* is the sum of the section sizes.
|
|
*
|
|
* NOTE: Relocatable (REL) areas ae always concatenated
|
|
* with each other, thus relocatable area B
|
|
* (defined after area A) will follow
|
|
* relocatable area A independent of the
|
|
* starting address of area A. Within a
|
|
* specific area each areax section may be
|
|
* overlayed or concatenated with other
|
|
* areax sections.
|
|
*
|
|
*
|
|
* If a base address for an area is specified then the
|
|
* area will start at that address. Any relocatable
|
|
* areas defined subsequently will be concatenated to the
|
|
* previous relocatable area if it does not have a base
|
|
* address specified.
|
|
*
|
|
* The names s_<areaname> and l_<areaname> are created to
|
|
* define the starting address and length of each area.
|
|
*
|
|
* local variables:
|
|
* Addr_T rloc ;current relocation address
|
|
* char temp[] ;temporary string
|
|
* struct symbol *sp ;symbol structure
|
|
*
|
|
* global variables:
|
|
* area *ap Pointer to the current
|
|
* area structure
|
|
* area *areap The pointer to the first
|
|
* area structure of a linked list
|
|
*
|
|
* functions called:
|
|
* int fprintf() c_library
|
|
* VOID lnksect() lkarea.c
|
|
* symbol *lkpsym() lksysm.c
|
|
* char * strncpy() c_library
|
|
* int symeq() lksysm.c
|
|
*
|
|
* side effects:
|
|
* All area and areax addresses and sizes are
|
|
* determined and saved in their respective
|
|
* structures.
|
|
*/
|
|
|
|
/*
|
|
* Resolve all area addresses.
|
|
*/
|
|
VOID
|
|
lnkarea()
|
|
{
|
|
register int rloc;
|
|
char temp[NCPS];
|
|
struct sym *sp;
|
|
|
|
rloc = 0;
|
|
ap = areap;
|
|
while (ap) {
|
|
if (ap->a_flag&A_ABS) {
|
|
/*
|
|
* Absolute sections
|
|
*/
|
|
lnksect(ap);
|
|
} else {
|
|
/*
|
|
* Relocatable sections
|
|
*/
|
|
if (ap->a_addr == 0)
|
|
ap->a_addr = rloc;
|
|
lnksect(ap);
|
|
rloc = ap->a_addr + ap->a_size;
|
|
}
|
|
|
|
/*
|
|
* Create symbols called:
|
|
* s_<areaname> the start address of the area
|
|
* l_<areaname> the length of the area
|
|
*/
|
|
|
|
if (! symeq(ap->a_id, _abs_)) {
|
|
strncpy(temp+2,ap->a_id,NCPS-2);
|
|
*(temp+1) = '_';
|
|
|
|
*temp = 's';
|
|
sp = lkpsym(temp, 1);
|
|
sp->s_addr = ap->a_addr;
|
|
sp->s_axp = NULL;
|
|
sp->s_type |= S_DEF;
|
|
|
|
*temp = 'l';
|
|
sp = lkpsym(temp, 1);
|
|
sp->s_addr = ap->a_size;
|
|
sp->s_axp = NULL;
|
|
sp->s_type |= S_DEF;
|
|
}
|
|
ap = ap->a_ap;
|
|
}
|
|
}
|
|
|
|
/*)Function VOID lnksect()
|
|
*
|
|
* area * tap pointer to an area structure
|
|
*
|
|
* The function lnksect() is the function called by
|
|
* lnkarea() to resolve the areax addresses. Refer
|
|
* to the function lnkarea() for more detail. Pageing
|
|
* boundary and length errors will be reported by this
|
|
* function.
|
|
*
|
|
* local variables:
|
|
* Addr_T size size of area
|
|
* Addr_T addr address of area
|
|
* areax * taxp pointer to an areax structure
|
|
*
|
|
* global variables:
|
|
* int lkerr error flag
|
|
*
|
|
* functions called:
|
|
* none
|
|
*
|
|
* side effects:
|
|
* All area and areax addresses and sizes area determined
|
|
* and linked into the structures.
|
|
*/
|
|
|
|
VOID
|
|
lnksect(tap)
|
|
register struct area *tap;
|
|
{
|
|
register Addr_T size, addr;
|
|
register struct areax *taxp;
|
|
|
|
size = 0;
|
|
addr = tap->a_addr;
|
|
if ((tap->a_flag&A_PAG) && (addr & 0xFF)) {
|
|
fprintf(stderr,
|
|
"\n?ASlink-Warning-Paged Area %.8s Boundary Error\n", tap->a_id);
|
|
lkerr++;
|
|
}
|
|
taxp = tap->a_axp;
|
|
if (tap->a_flag&A_OVR) {
|
|
/*
|
|
* Overlayed sections
|
|
*/
|
|
while (taxp) {
|
|
taxp->a_addr = addr;
|
|
if (taxp->a_size > size)
|
|
size = taxp->a_size;
|
|
taxp = taxp->a_axp;
|
|
}
|
|
} else {
|
|
/*
|
|
* Concatenated sections
|
|
*/
|
|
while (taxp) {
|
|
taxp->a_addr = addr;
|
|
addr += taxp->a_size;
|
|
size += taxp->a_size;
|
|
taxp = taxp->a_axp;
|
|
}
|
|
}
|
|
tap->a_size = size;
|
|
if ((tap->a_flag&A_PAG) && (size > 256)) {
|
|
fprintf(stderr,
|
|
"\n?ASlink-Warning-Paged Area %.8s Length Error\n", tap->a_id);
|
|
lkerr++;
|
|
}
|
|
}
|