elspec.c 4.82 KB
#include <sys/types.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "makedisk.h"


////////////////////////////////////////////////////////////////////////////////
// createElspec()
//
// Create the "elspec" file which is used by the linker.  elspec is a file
//   which contains a series of commands to give more explicit instructions
//   to the linker than can be given on the command line.
//
int createElspec(Wave *wave) {
  FILE *f;
  
  SegmentChain *sc;
  Segment *s;
  Path *p;
  
  if ((f = fopen(wave->elspecFile, "w")) == NULL) {
    fprintf(stderr, "makedisk: %s: cannot create\n",
	    wave->elspecFile);
    return(-1);
  }
  
  fprintf(f, "$ignoreoverlaps = true\n\n");
  for (sc = wave->segmentChain; sc != NULL; sc = sc->next) {
    s = sc->segment;
    
    if ((s->flags & SEGFLAG_OBJECT) == 0)
      continue;
    
    fprintf(f, "beginseg\n");
    fprintf(f, "\tsegtype LOAD\n");
    fprintf(f, "\tsegflags R X\n");
    fprintf(f, "\tvaddr 0x%x\n", s->address);
    fprintf(f, "\tcontents\n");
    
    fprintf(f, "\tbeginscn .%s.text\n", s->name);
    fprintf(f, "\t\tscntype PROGBITS\n");
    if (s->textAlign != 0)
      fprintf(f, "\t\tscnalign %d\n", s->textAlign);
    fprintf(f, "\t\tscnflags ALLOC EXECINSTR\n");
    for (p = s->pathList; p != NULL; p = p->next) {
      fprintf(f, "\t\tsection .text in object %s\n", p->name);
    }
    fprintf(f, "\tendscn\n");
    
    fprintf(f, "\tbeginscn .%s.data\n", s->name);
    fprintf(f, "\t\tscntype PROGBITS\n");
    if (s->dataAlign != 0)
      fprintf(f, "\t\tscnalign %d\n", s->dataAlign);
    fprintf(f, "\t\tscnflags ALLOC WRITE\n");
    for (p = s->pathList; p != NULL; p = p->next) {
      fprintf(f, "\t\tsection .data in object %s\n", p->name);
      fprintf(f, "\t\tsection .rodata in object %s\n", p->name);
    }
    fprintf(f, "\tendscn\n");
    
    fprintf(f, "\tbeginscn .%s.sdata\n", s->name);
    fprintf(f, "\t\tscntype PROGBITS\n");
    if (s->sdataAlign != 0)
      fprintf(f, "\t\tscnalign %d\n", s->sdataAlign);
    fprintf(f, "\t\tscnflags GPREL ALLOC WRITE\n");
    for (p = s->pathList; p != NULL; p = p->next)
      fprintf(f, "\t\tsection .sdata in object %s\n", p->name);
    fprintf(f, "\tendscn\n");
    
    fprintf(f, "\tbeginscn .%s.sbss\n", s->name);
    fprintf(f, "\t\tscntype NOBITS\n");
    if (s->sbssAlign != 0)
      fprintf(f, "\t\tscnalign %d\n", s->sbssAlign);
    fprintf(f, "\t\tscnflags GPREL ALLOC WRITE\n");
    for (p = s->pathList; p != NULL; p = p->next)
      fprintf(f, "\t\tsection .sbss in object %s\n", p->name);
    fprintf(f, "\tendscn\n");
    
    fprintf(f, "\tbeginscn .%s.bss\n", s->name);
    fprintf(f, "\t\tscntype NOBITS\n");
    if (s->bssAlign != 0)
      fprintf(f, "\t\tscnalign %d\n", s->bssAlign);
    fprintf(f, "\t\tscnflags ALLOC WRITE\n");
    for (p = s->pathList; p != NULL; p = p->next)
      fprintf(f, "\t\tsection .bss in object %s\n", p->name);
    fprintf(f, "\tendscn\n");
    fprintf(f, "endseg\n");
  }
  fprintf(f, "beginseg\n");
  fprintf(f, "\tsegtype noload\n");
  fprintf(f, "\tcontents\n");
  fprintf(f, "\tdefault\n");
  fprintf(f, "\tbeginscn .MIPS.options\n");
  fprintf(f, "\t\tscntype 0x7000000d\n");
  fprintf(f, "\t\tsection .MIPS.options in ldobj\n");
  fprintf(f, "\tendscn\n");
  fprintf(f, "\tbeginscn .reginfo\n");
  fprintf(f, "\t\tscntype 0x70000006\n");
  fprintf(f, "\t\tsection .reginfo in ldobj\n");
  fprintf(f, "\tendscn\n");
  fprintf(f, "endseg\n");
  fclose(f);
  
  return(0);
}


////////////////////////////////////////////////////////////////////////////////
// runLinker()
//
// Run the linker, using the elspec file and objectlist file which were 
//   generated previously.
//
int runLinker(Wave *wave, char *symbolFile, char *objListFile) {
  char *cmd;
  SegmentChain *sc;
  Segment *s;
  Path *p;
  FILE *objfd;
  
  if ((cmd = (char *)malloc(sysconf(_SC_ARG_MAX))) == NULL) {
    fprintf(stderr, "malloc failed\n");
    return(-1);
  }

  // We now always use nld.  In earlier releases we used the IDO 7.1
  //   linker, but it has bugs in processing an elspec file.  So we're
  //   back to nld.
  strcpy(cmd, "$ROOT/usr/lib/PR/nld -g -non_shared -G 0 -elspec ");

  strcat(cmd, wave->elspecFile);
  strcat(cmd, " -rom ");
  if (loadMap)
    strcat(cmd, " -m ");
  strcat(cmd, " -o ");
  strcat(cmd, wave->name);
  strcat(cmd, " ");
  strcat(cmd, symbolFile);
  
  strcat(cmd, " -objectlist ");
  strcat(cmd, objListFile);
  
  // Write out the temporary objectList file.
  objfd = fopen(objListFile, "w");
  for (sc = wave->segmentChain; sc != NULL; sc = sc->next) {
    s = sc->segment;
    if ((s->flags & SEGFLAG_OBJECT) == 0)
      continue;
    for (p = s->pathList; p != NULL; p = p->next) {
      fprintf(objfd, "%s\n", p->name);
    }
  }
  fclose(objfd);

  if (debug) {
    printf("Linking to ELF wave file\n");
    printf("  %s\n", cmd);
  }
  return(execCommand(cmd));
}