X-Git-Url: https://git.gag.com/?a=blobdiff_plain;ds=sidebyside;f=as%2Fxa51%2Fxa_link.c;h=f9a81c75625b672db32ec99eff87e7d3fcfb75b3;hb=a9d938a287d14500ee779fc7aa12829013d4e90f;hp=7eace8ddf19fc633afd77821906a3cd6e6a3a802;hpb=887ea512334ee13d5fb343526ec50e8e0eec9d37;p=fw%2Fsdcc diff --git a/as/xa51/xa_link.c b/as/xa51/xa_link.c index 7eace8dd..f9a81c75 100644 --- a/as/xa51/xa_link.c +++ b/as/xa51/xa_link.c @@ -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 - 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. @@ -29,7 +31,7 @@ "T xxxx 0" "R xxxx " 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). @@ -50,26 +52,31 @@ enum { 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, + + // that's all MAX_SEGMENTS }; enum { REL_FF=1, REL_FFFF, + BIT_03FF, + DIR_07FF, + DIR_70FF, + DIR_0700FF, ABS_0F, ABS_FF, - ABS_03FF, - ABS_07FF, - ABS_F0FF, ABS_FFFF, - ABS_0F00FF, + ABS_PC, MAX_REFS }; @@ -77,13 +84,14 @@ char *refModes[]={ "???", "REL_FF", "REL_FFFF", + "BIT_03FF", + "DIR_07FF", + "DIR_70FF", + "DIR_0700FF", "ABS_0F", "ABS_FF", - "ABS_03FF", - "ABS_07FF", - "ABS_F0FF", "ABS_FFFF", - "ABS_0F00FF", + "ABS_PC" }; #define CODESIZE 0x10000 @@ -141,6 +149,7 @@ struct SYMBOL { struct REFERENCE { char *name; struct MODULE *module; + struct SEGMENT *segment; 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; soffset[s]=segments[s]._size; + module->offset[s]=(segments[s]._size+1)&0xfffffe; } 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->segment=currentSegment; 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; @@ -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) { - if (findSymbolByName(reference->name)) { + if ((reference->how==ABS_PC) || findSymbolByName(reference->name)) { reference->resolved=1; } } @@ -448,7 +461,6 @@ void readModule(char *module, int isLib) { } currentLine++; } - // that's all for now, thanks for watching */ fclose (relModule); } @@ -459,30 +471,24 @@ void writeModule(char *outFileName) { 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); } - fprintf (fOut, "Just for now, make it a little bit more readable\n"); 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]; - fprintf (fOut, " %02X", gsfinalImage[address++]); + fprintf (fOut, "%02X", gsfinalImage[address++]); } checksum &= 0xff; if (checksum) { checksum = 0x100 - checksum; } - fprintf (fOut, " < %02X\n", checksum); + fprintf (fOut, "%02X\n", checksum); } fprintf (fOut, ":00000001FF\n"); @@ -516,6 +522,11 @@ int relocate() { } // 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); @@ -525,6 +536,9 @@ int relocate() { 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; @@ -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; + if (segments[GSFINAL]._size & 1) { + segments[GSFINAL]._size++; + } // 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; + if (segments[GSFINAL]._size & 1) { + segments[GSFINAL]._size++; + } // 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; @@ -552,45 +580,70 @@ int relocate() { } // 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 { - 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) { - 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++; } - gsinitImage[reference->address+1]=(rel16/2)>>8; - gsinitImage[reference->address]=rel16/2; + gsfinalImage[reference->address]=rel8/2; 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++; } - gsinitImage[reference->address]=rel8/2; + gsfinalImage[reference->address]=(rel16/2)>>8; + gsfinalImage[reference->address+1]=rel16/2; 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: - 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: - 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", @@ -621,7 +674,6 @@ int scanLibraries(int unresolved) { for (nlp=0; nlp