* as/link/lklibr.c:
[fw/sdcc] / as / xa51 / xa_link.c
index 7eace8ddf19fc633afd77821906a3cd6e6a3a802..f9a81c75625b672db32ec99eff87e7d3fcfb75b3 100644 (file)
@@ -14,7 +14,9 @@
 
 /* This is a cheap hack. The xa51 has a couple of ways to scramble
    relocation info into it's opcode that the standard linker can't
 
 /* This is a cheap hack. The xa51 has a couple of ways to scramble
    relocation info into it's opcode that the standard linker can't
-   handle. No hash or qsort yet.
+   handle, not to mention word allignment. 
+
+   No hash or qsort yet.
 
    The relocatable format looks like the known one, BUT ISN'T.
 
 
    The relocatable format looks like the known one, BUT ISN'T.
 
@@ -29,7 +31,7 @@
    "T xxxx <how> <symbol> 0"
    "R xxxx <how> <symbol> <pc+>" the relocation info. xxxx is the address
      within relative code space. How is something like REL_FF, REL_FFFF, 
    "T xxxx <how> <symbol> 0"
    "R xxxx <how> <symbol> <pc+>" the relocation info. xxxx is the address
      within relative code space. How is something like REL_FF, REL_FFFF, 
-     ABS_F0FF. Symbol is the referenced symbol and pc+ is the program 
+     ABS_70FF. Symbol is the referenced symbol and pc+ is the program 
      counter that will be used to calculate the relative address (that is
      the address of the following instruction).
 
      counter that will be used to calculate the relative address (that is
      the address of the following instruction).
 
@@ -50,26 +52,31 @@ enum {
   GSINIT=1,
   CSEG,
   XINIT,
   GSINIT=1,
   CSEG,
   XINIT,
-  GSFINAL, // here goes the final output
+
+  // here goes the final output and should be used by the assembler
+  GSFINAL,
 
   // these are only for storage
   BSEG,
   DSEG,
   XSEG,
   XISEG,
 
   // these are only for storage
   BSEG,
   DSEG,
   XSEG,
   XISEG,
+
+  // that's all
   MAX_SEGMENTS
 };
 
 enum {
   REL_FF=1,
   REL_FFFF,
   MAX_SEGMENTS
 };
 
 enum {
   REL_FF=1,
   REL_FFFF,
+  BIT_03FF,
+  DIR_07FF,
+  DIR_70FF,
+  DIR_0700FF,
   ABS_0F,
   ABS_FF,
   ABS_0F,
   ABS_FF,
-  ABS_03FF,
-  ABS_07FF,
-  ABS_F0FF,
   ABS_FFFF,
   ABS_FFFF,
-  ABS_0F00FF,
+  ABS_PC,
   MAX_REFS
 };
 
   MAX_REFS
 };
 
@@ -77,13 +84,14 @@ char *refModes[]={
   "???",
   "REL_FF",
   "REL_FFFF",
   "???",
   "REL_FF",
   "REL_FFFF",
+  "BIT_03FF",
+  "DIR_07FF",
+  "DIR_70FF",
+  "DIR_0700FF",
   "ABS_0F",
   "ABS_FF",
   "ABS_0F",
   "ABS_FF",
-  "ABS_03FF",
-  "ABS_07FF",
-  "ABS_F0FF",
   "ABS_FFFF",
   "ABS_FFFF",
-  "ABS_0F00FF",
+  "ABS_PC"
 };
 
 #define CODESIZE 0x10000
 };
 
 #define CODESIZE 0x10000
@@ -141,6 +149,7 @@ struct SYMBOL {
 struct REFERENCE {
   char *name;
   struct MODULE *module;
 struct REFERENCE {
   char *name;
   struct MODULE *module;
+  struct SEGMENT *segment;
   int lineno;
   unsigned address, pc;
   short how;
   int lineno;
   unsigned address, pc;
   short how;
@@ -209,7 +218,7 @@ void addToModules (char *name, int isLib) {
   module=calloc(1, sizeof(struct MODULE));
   module->name=strdup(name);
   for (s=0; s<MAX_SEGMENTS; s++) {
   module=calloc(1, sizeof(struct MODULE));
   module->name=strdup(name);
   for (s=0; s<MAX_SEGMENTS; s++) {
-    module->offset[s]=segments[s]._size;
+    module->offset[s]=(segments[s]._size+1)&0xfffffe;
   }
   module->isLib=isLib;
   if (!modules) {
   }
   module->isLib=isLib;
   if (!modules) {
@@ -226,9 +235,13 @@ void addToRefs(char *ref, int address, char *how, int pc) {
   reference=calloc(1, sizeof(struct REFERENCE));
   reference->name=strdup(ref);
   reference->module=currentModule;
   reference=calloc(1, sizeof(struct REFERENCE));
   reference->name=strdup(ref);
   reference->module=currentModule;
+  reference->segment=currentSegment;
   reference->lineno=currentLine;
   reference->address=address;
   reference->how=howToReference(how);
   reference->lineno=currentLine;
   reference->address=address;
   reference->how=howToReference(how);
+  if (reference->how==ABS_PC) {
+    reference->resolved=1;
+  }
   reference->pc=pc;
   if (!references) {
     references=reference;
   reference->pc=pc;
   if (!references) {
     references=reference;
@@ -241,7 +254,7 @@ void addToRefs(char *ref, int address, char *how, int pc) {
 void resolve() {
   struct REFERENCE *reference;
   for (reference=references; reference; reference=reference->next) {
 void resolve() {
   struct REFERENCE *reference;
   for (reference=references; reference; reference=reference->next) {
-    if (findSymbolByName(reference->name)) {
+    if ((reference->how==ABS_PC) || findSymbolByName(reference->name)) {
       reference->resolved=1;
     }
   }
       reference->resolved=1;
     }
   }
@@ -448,7 +461,6 @@ void readModule(char *module, int isLib) {
       }
     currentLine++;
   }
       }
     currentLine++;
   }
-  // that's all for now, thanks for watching */
   fclose (relModule);
 }
 
   fclose (relModule);
 }
 
@@ -459,30 +471,24 @@ void writeModule(char *outFileName) {
   unsigned int len;
   unsigned int checksum;
 
   unsigned int len;
   unsigned int checksum;
 
-  fprintf (stderr, "writeModule: %s from 0x%04x to 0x%04x\n",
-          outFileName, 
-          address,
-          address+size);
-
   if ((fOut=fopen(outFileName, "w"))==NULL) {
     perror (outFileName);
   }
   if ((fOut=fopen(outFileName, "w"))==NULL) {
     perror (outFileName);
   }
-  fprintf (fOut, "Just for now, make it a little bit more readable\n");
 
   while (size) {
     len = size>16 ? 16 : size;
     size-=len;
 
   while (size) {
     len = size>16 ? 16 : size;
     size-=len;
-    fprintf (fOut, ":%02X.%04X.%02X >", len, address, 0);
+    fprintf (fOut, ":%02X%04X%02X", len, address, 0);
     checksum = len + (address>>8) + (address&0xff);
     while (len--) {
       checksum += gsfinalImage[address];
     checksum = len + (address>>8) + (address&0xff);
     while (len--) {
       checksum += gsfinalImage[address];
-      fprintf (fOut, " %02X", gsfinalImage[address++]);
+      fprintf (fOut, "%02X", gsfinalImage[address++]);
     }
     checksum &= 0xff;
     if (checksum) {
       checksum = 0x100 - checksum;
     }
     }
     checksum &= 0xff;
     if (checksum) {
       checksum = 0x100 - checksum;
     }
-    fprintf (fOut, " < %02X\n", checksum);
+    fprintf (fOut, "%02X\n", checksum);
   }
   fprintf (fOut, ":00000001FF\n");
 
   }
   fprintf (fOut, ":00000001FF\n");
 
@@ -516,6 +522,11 @@ int relocate() {
   }
 
   // GSFINAL starts at --code-loc ( -b CSEG = 0x1234 )
   }
 
   // GSFINAL starts at --code-loc ( -b CSEG = 0x1234 )
+  if (segments[CSEG].start & 1) {
+    fprintf (stderr, "*** error: code doesn't start at "
+            "an even address: %04x\n", segments[CSEG].start);
+    exit (1);
+  }
   segments[GSFINAL].start=segments[CSEG].start;
   memset(gsfinalImage, 0xff, CODESIZE);
 
   segments[GSFINAL].start=segments[CSEG].start;
   memset(gsfinalImage, 0xff, CODESIZE);
 
@@ -525,6 +536,9 @@ int relocate() {
   memcpy(to, from, segments[GSINIT]._size);
   segments[GSINIT].start=segments[GSFINAL].start;
   segments[GSFINAL]._size += segments[GSINIT]._size;
   memcpy(to, from, segments[GSINIT]._size);
   segments[GSINIT].start=segments[GSFINAL].start;
   segments[GSFINAL]._size += segments[GSINIT]._size;
+  if (segments[GSFINAL]._size & 1) {
+    segments[GSFINAL]._size++;
+  }
     
   // append cseg to gsfinal
   from=csegImage;
     
   // append cseg to gsfinal
   from=csegImage;
@@ -532,6 +546,9 @@ int relocate() {
   memcpy(to, from, segments[CSEG]._size);
   segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
   segments[GSFINAL]._size += segments[CSEG]._size;
   memcpy(to, from, segments[CSEG]._size);
   segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
   segments[GSFINAL]._size += segments[CSEG]._size;
+  if (segments[GSFINAL]._size & 1) {
+    segments[GSFINAL]._size++;
+  }
 
   // append xinit to gsfinal
   from=xinitImage;
 
   // append xinit to gsfinal
   from=xinitImage;
@@ -539,8 +556,19 @@ int relocate() {
   memcpy(to, from, segments[XINIT]._size);
   segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
   segments[GSFINAL]._size += segments[XINIT]._size;
   memcpy(to, from, segments[XINIT]._size);
   segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
   segments[GSFINAL]._size += segments[XINIT]._size;
+  if (segments[GSFINAL]._size & 1) {
+    segments[GSFINAL]._size++;
+  }
 
   // XISEG is located after XSEG
 
   // XISEG is located after XSEG
+  if (segments[XSEG].start & 1) {
+    fprintf (stderr, "*** warning: xdata doesn't start at "
+            "an even address: %04x\n", segments[XSEG].start);
+  }
+  if (segments[XSEG]._size & 1) {
+    segments[XSEG]._size++;
+  }
+  
   segments[XISEG].start=segments[XSEG].start + 
     segments[XSEG]._size;  
 
   segments[XISEG].start=segments[XSEG].start + 
     segments[XSEG]._size;  
 
@@ -552,45 +580,70 @@ int relocate() {
   }
   // and the references
   for (reference=references; reference; reference=reference->next) {
   }
   // and the references
   for (reference=references; reference; reference=reference->next) {
-    if (!(symbol=findSymbolByName(reference->name))) {
-      // this reference isn't defined after all
+    symbol=findSymbolByName(reference->name);
+    if (!reference->resolved && !symbol && reference->how!=ABS_PC) {
+      // this reference isn't resolved after all
       fprintf (stderr, "*** %s:%d undefined symbol %s\n",
               reference->module->name, reference->lineno,
               reference->name);
       fatalErrors++;
     } else {
       fprintf (stderr, "*** %s:%d undefined symbol %s\n",
               reference->module->name, reference->lineno,
               reference->name);
       fatalErrors++;
     } else {
-      reference->address += symbol->segment->start;
-      reference->pc += symbol->segment->start;
+      reference->address += 
+       reference->module->offset[reference->segment->id]+
+       reference->segment->start;
+      reference->pc += 
+       reference->module->offset[reference->segment->id]+
+       reference->segment->start;
       switch (reference->how) 
        {
       switch (reference->how) 
        {
-       case REL_FFFF: {
-         int rel16 = symbol->address-reference->pc;
-         if (rel16<-65536 || rel16>65534) {
-           fprintf (stderr, 
-                    "rel16 target for %s is out of range in module %s\n",
-                    reference->name, reference->module->name);
+       case REL_FF: {
+         int rel8 = symbol->address-(reference->pc & ~1);
+         if (rel8<-256 || rel8>256) {
+           fprintf (stderr,
+                    "rel8 target for %s is out of range in module %s:%d\n",
+                    reference->name, reference->module->name, 
+                    reference->lineno);
            fatalErrors++;
          }
            fatalErrors++;
          }
-         gsinitImage[reference->address+1]=(rel16/2)>>8;
-         gsinitImage[reference->address]=rel16/2;
+         gsfinalImage[reference->address]=rel8/2;
          break;
        }
          break;
        }
-       case REL_FF: {
-         int rel8 = symbol->address-reference->pc;
-         if (rel8<-256 || rel8>256) {
-           fprintf (stderr,
-                    "rel8 target for %s is out of range in module %s\n",
-                    reference->name, reference->module->name);
+       case REL_FFFF: {
+         int rel16 = symbol->address-(reference->pc & ~1);
+         if (rel16<-65536 || rel16>65534) {
+           fprintf (stderr, 
+                    "rel16 target for %s is out of range in module %s:%d\n",
+                    reference->name, reference->module->name,
+                    reference->lineno);
            fatalErrors++;
          }
            fatalErrors++;
          }
-         gsinitImage[reference->address]=rel8/2;
+         gsfinalImage[reference->address]=(rel16/2)>>8;
+         gsfinalImage[reference->address+1]=rel16/2;
          break;
        }
          break;
        }
+       case DIR_70FF:
+         gsfinalImage[reference->address] = 
+           (gsfinalImage[reference->address]&~0x70) + 
+           ((symbol->address>>4)&0x70);
+         gsfinalImage[reference->address+1] = symbol->address;
+         break;
        case ABS_FFFF:
        case ABS_FFFF:
-         gsinitImage[reference->address+1] = symbol->address>>8;
-         // fall through
+         gsfinalImage[reference->address] = symbol->address>>8;
+         gsfinalImage[reference->address+1] = symbol->address;
+         break;
        case ABS_FF:
        case ABS_FF:
-         gsinitImage[reference->address] = symbol->address;
+         gsfinalImage[reference->address] = symbol->address;
+         break;
+       case ABS_PC: 
+         {
+           unsigned int address=
+             (gsfinalImage[reference->address]<<8) +
+             gsfinalImage[reference->address+1];
+           address += reference->module->offset[reference->segment->id];
+           address += segments[reference->segment->id].start;
+           gsfinalImage[reference->address] = address>>8;
+           gsfinalImage[reference->address+1] = address;
+         };
          break;
        default:
          fprintf (stderr, "unsupported reference mode %d.\n",
          break;
        default:
          fprintf (stderr, "unsupported reference mode %d.\n",
@@ -621,7 +674,6 @@ int scanLibraries(int unresolved) {
   for (nlp=0; nlp<nlibPaths; nlp++) {
     for (nlf=0; nlf<nlibFiles; nlf++) {
       sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
   for (nlp=0; nlp<nlibPaths; nlp++) {
     for (nlf=0; nlf<nlibFiles; nlf++) {
       sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
-      //fprintf (stderr, "  %s\n", libFiles);
       if ((lfs=fopen(libFiles,"r"))==NULL) {
        continue;
       }
       if ((lfs=fopen(libFiles,"r"))==NULL) {
        continue;
       }
@@ -629,15 +681,13 @@ int scanLibraries(int unresolved) {
        // remove trailing \n
        line[strlen(line)-1]='\0';
        sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
        // remove trailing \n
        line[strlen(line)-1]='\0';
        sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
-       //fprintf (stderr, "    %s\n", libFile);
-       if ((lf=fopen(libFile,"r"))==0) {
+       if ((lf=fopen(libFile,"r"))==NULL) {
          continue;
        }
        while (fgets(line, 132, lf)) {
          int dummy; // we need this to get the right count of the next sscanf
          if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
            if (isUnresolved(symName, 1)) {
          continue;
        }
        while (fgets(line, 132, lf)) {
          int dummy; // we need this to get the right count of the next sscanf
          if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
            if (isUnresolved(symName, 1)) {
-             //fprintf (stderr, "%s:%s\n", libFile, symName);
              readModule(libFile,1);
              if (resolved++ == unresolved) {
                // we are done
              readModule(libFile,1);
              if (resolved++ == unresolved) {
                // we are done
@@ -746,7 +796,6 @@ int main(int argc, char **argv) {
   addToDefs("s_XISEG", 0, 0);
   addToDefs("l_XISEG", segments[XISEG]._size, 1);
 
   addToDefs("s_XISEG", 0, 0);
   addToDefs("l_XISEG", segments[XISEG]._size, 1);
 
-#if 1
   // mark the resolved references
   resolve();
 
   // mark the resolved references
   resolve();
 
@@ -770,7 +819,6 @@ int main(int argc, char **argv) {
   if (unresolved==0) {
     writeModule(outFileName);
   }
   if (unresolved==0) {
     writeModule(outFileName);
   }
-#endif
 
   // the modules
   fprintf (mapOut, "Modules:\n");
 
   // the modules
   fprintf (mapOut, "Modules:\n");