File:  [Research Unix] / researchv10no / cmd / sml / src / runtime / linkdata.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:34 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

/* Copyright 1989 by AT&T Bell Laboratories */
/* linkdata.c -- group files into the text segment of a .o file */

#define SYMBOL	    "_datalist"
#define END_SYMBOL  "_endmo"

#include <stdio.h>
#include <a.out.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "tags.h"

#define LONG	    (sizeof(long))
#define align(x)    (((x) + (LONG - 1)) & ~(LONG - 1))

#ifdef SPARC
#define relocation_info reloc_info_sparc
#endif

#define RELINFO_SZ  (sizeof (struct relocation_info))

struct relocation_info rconst, *rel;
struct nlist nlconst, *nl;

struct str_table {  /* The string table buffer. */
    int	    len;    /* length including this word */
    char    strs[4];
} *str_tbl;
char *str_ptr;	/* the next location in the string table. */

/* add_name:
 * Extract the structure name from the file name and add it to the string table
 * buffer (with an initial "_").
 */
void add_name (file)
    char *file;
{
    register char   *p, *begin;
    int		    len, res;

  /* find the beginning of the file name. */
    for (p = begin = file;  *p;	 p++) {
	if (*p == '/')
	    begin = p+1;
    }

  /* find the ".mo" */
    for (p = begin, len = 0;  *p && (*p != '.');  p++, len++)
	continue;

    *str_ptr++ = '_';
    strncpy(str_ptr, begin, len);
    str_ptr += len;
    *str_ptr++ = '\0';
    str_tbl->len += (len+2);
}

void die(s)
    char *s;
{
    perror(s);
    exit(1);
}

extern long *malloc();	/* wrong but convenient */


/* link:
 * append the code from file to linked code.  pc is the relative starting address,
 * last = 1, if this is the last file to link.
 */
int link (file, pc, last)
    char *file; long pc; int last;
{
    int fd;
    long i, len, n, nbytes;
    char *s;
    struct stat st;
    static int bufsize = 0;
    static long *buf;

    if ((fd = open(file, 0)) == -1) {
	char	buf[64];
	sprintf(buf, "open: %s", file);
	die(buf);
    }
    if (fstat(fd, &st) == -1)
	die("stat");

    n = st.st_size;
    len = strlen(file);
    nbytes = align(n) + align(len) + 6 * LONG;

    if (n + len + 40 > bufsize) {
	bufsize = n + len + 4096;
	if (buf != NULL)
	    free(buf);
	buf = malloc(bufsize);
	if (buf == NULL)
	    die("malloc(buf)");
    }

  /* initialize the header record and add its fields to the list of
   * relocatable addresses.
   */
    buf[0] = mak_desc(3, tag_record);
#ifdef SPARC
#define REL(addr, addend)   \
    (*rel = rconst, rel->r_addend = (addend), (rel++)->r_address = (addr))

    buf[1] = 0;
    REL(pc + LONG, pc + 5 * LONG);
    buf[2] = 0;
    REL(pc + 2 * LONG, pc + 6 * LONG + align(len));
    if (last)
	buf[3] = 1;			   /* either ML 0 */
    else {
	buf[3] = 0;
	REL(pc + 3 * LONG, pc + nbytes + LONG);
    }
#else

#define REL(addr)   (*rel = rconst, (rel++)->r_address = (addr))

    buf[1] = pc + 5 * LONG;		   /* address of file name */
    REL(pc + LONG);
    buf[2] = buf[1] + LONG + align(len);   /* address of code */
    REL(pc + 2 * LONG);
    if (last)
	buf[3] = 1;			   /* either ML 0 */
    else {
	buf[3] = pc + nbytes + LONG;	   /* or the address of next module */
	REL(pc + 3 * LONG);
    }
#endif

    buf[4] = mak_desc(len, tag_string);	   /* tag for file name */
    strcpy(&buf[5], file);
    s = ((char *) &buf[5]) + len;
    for (i = align(len); i > len; i--)
	*s++ = 0;

    *((long *) s) = mak_desc(n, tag_string);  /* tag for code */
    s += LONG;

  /* record this structure in the symbol and string tables */
    *nl = nlconst;
    nl->n_un.n_strx = str_tbl->len;
    nl->n_value = pc + 6*LONG + align(len);  /* relative code address */
    nl++;
    add_name(file);

    if (read(fd, s, n) != n)
	die("read");
    s += n;
    for (i = align(n); i > n; i--)
	*s++ = 0;

    if (close(fd) == -1)
	die("close");

    assert(s - nbytes == (char *) buf);
    write(1, buf, nbytes);
    return nbytes;
}

int main(argc, argv)
    int argc;
    char *argv[];
{
    long pc = 0;
    struct exec exec;
    struct nlist *nlbase;
    struct relocation_info *relbase;
    int i, sz;

  /* allocate space for the string table */
    sz = strlen(SYMBOL)+strlen(END_SYMBOL)+LONG+1;
    for (i = 1;	 i < argc;  i++)
	sz += strlen(argv[i])+2;
    str_tbl = (struct str_table *) malloc(align(sz));
    if ((long)str_tbl == NULL)
	die("malloc(str_tbl)");

  /* initialize the string table buffer with the "_datalist" string */
    str_ptr = str_tbl->strs;
    strcpy(str_ptr, SYMBOL);
    str_ptr += strlen(SYMBOL)+1;
    str_tbl->len = LONG + strlen(SYMBOL)+1;

  /* Allocate space for nlist and reloc info buffers */
    nl = nlbase = (struct nlist *) malloc((argc+1) * sizeof(struct nlist));
    if ((long) nl == NULL)
	die("malloc(nl)");
    rel = relbase = (struct relocation_info *) malloc(3 * argc * RELINFO_SZ);
    if ((long) rel == NULL)
	die("malloc(rel)");

  /* build a nlist constant to initialize from, and initialize the datalist entry. */
    nlconst.n_other	= 0;
    nlconst.n_desc	= 0;
    if (argc > 1) {
	nlconst.n_type	= N_EXT | N_TEXT;	/* global in text area */
	nlconst.n_value = 4;			/* for datalist */
    }
    else {
      /* Actually, there is only one symbol (ie., datalist) */
	nlconst.n_type	= N_EXT | N_ABS;
	nlconst.n_value = 1;	/* ML zero */
    }
    *nl = nlconst; (nl++)->n_un.n_strx = 4; /* datalist, first string table entry */

  /* build a relocation constant to assign from */
#ifdef SPARC
    rconst.r_address   = 0;
    rconst.r_index     = N_TEXT;
    rconst.r_extern    = 0;	   /* r_index is the segment (text) */
    rconst.r_type      = RELOC_32;
    rconst.r_addend    = 0;
#else
    rconst.r_address   = 0;
    rconst.r_symbolnum = 4; /* i don't know why this works.  magic? */
    rconst.r_pcrel     = 0;
    rconst.r_length    = 2; /* long */
    rconst.r_extern    = 0;
#endif

  /* initialize the header, we fill in the text size info later */
#ifdef M68
    exec.a_machtype = M_68020;
#endif
#ifdef SPARC
    exec.a_dynamic	= 0;
    exec.a_machtype	= M_SPARC;
    exec.a_toolversion	= 1;
#endif
    exec.a_magic    = OMAGIC;
    exec.a_data	    = 0;
    exec.a_bss	    = 0;
  /* one per mo plus "datalist" and "_endmo" */
    exec.a_syms	    = (argc+1) * sizeof(struct nlist);
    exec.a_entry    = 0;
    exec.a_drsize   = 0;
    if (write(1, &exec, sizeof exec) == -1)
	die("write");

    for (i=1; i<argc; i++)
	pc += link(argv[i], pc, i==argc-1);

    exec.a_text	    = pc;
    exec.a_trsize   = (rel - relbase) * RELINFO_SZ;

    if (write(1, relbase, exec.a_trsize) == -1)
	die("write(rel)");

  /* Add "_endmo" to the name list and string table */
    *nl = nlconst;
    nl->n_un.n_strx = str_tbl->len;
    nl->n_type	    = N_EXT | N_TEXT;
    nl->n_value	    = pc;
    nl++;
    strcpy(str_ptr, END_SYMBOL);
    str_tbl->len += strlen(END_SYMBOL)+1;

  /* write out the symbol table. */
    if (write(1, nlbase, exec.a_syms) == -1)
	die("write(nl)");

  /* write out the string table */
    if (write(1, str_tbl, str_tbl->len) == -1)
	die("write(str_tbl)");
    
  /* update the header to reflect the true text size */
    if (lseek(1, 0, 0L) == -1)
	die("lseek");
    if (write(1, &exec, sizeof exec) == -1)
	die("write(exec)");

    return 0;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.