// Copyright (C) 1999-2003 Core Technologies. // // This file is part of tpasm. // // tpasm is free software; you can redistribute it and/or modify // it under the terms of the tpasm LICENSE AGREEMENT. // // tpasm is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // tpasm LICENSE AGREEMENT for more details. // // You should have received a copy of the tpasm LICENSE AGREEMENT // along with tpasm; see the file "LICENSE.TXT". // Handle creation and manipulation of segments #include "include.h" static SYMTABLE *segmentSymbols; // segment symbol list is kept here static CODE_PAGE *FindCodePage(SEGMENT_RECORD *theSegment,unsigned int address) // find the code page of address, or the one immediately before it in the linked // list of code pages hanging off theSegment // NOTE: if the address is earlier than any code page within theSegment, // NULL will be returned // NOTE: this should probably be made faster { CODE_PAGE *currentPage, *bestPage; bestPage=NULL; currentPage=theSegment->firstPage; if(theSegment->pageCache&&theSegment->pageCache->address<=address) { currentPage=theSegment->firstPage; } while(currentPage&¤tPage->address<=address) { bestPage=currentPage; currentPage=currentPage->next; } theSegment->pageCache=bestPage; return(bestPage); } static void DestroyCodePage(SEGMENT_RECORD *theSegment,CODE_PAGE *thePage) // unlink thePage from theSegment, and destroy it { if(thePage->next) { thePage->next->previous=thePage->previous; } if(thePage->previous) { thePage->previous->next=thePage->next; } else { theSegment->firstPage=thePage->next; } if(theSegment->pageCache==thePage) // update the cache if needed { theSegment->pageCache=thePage->previous; } DisposePtr(thePage); } static CODE_PAGE *CreateCodePage(SEGMENT_RECORD *theSegment,CODE_PAGE *pageBefore) // create a new code page // link it to theSegment after pageBefore // NOTE: pageBefore can be passed in as NULL to link it to the start of the // segment // NOTE: the code page's usage map is initialized to be completely unused // NOTE: if this fails, it will return NULL { CODE_PAGE *thePage; int i; if((thePage=(CODE_PAGE *)NewPtr(sizeof(CODE_PAGE)))) { for(i=0;i<32;i++) { thePage->usageMap[i]=0; } if(pageBefore) { thePage->next=pageBefore->next; thePage->previous=pageBefore; pageBefore->next=thePage; } else { if((thePage->next=theSegment->firstPage)) { thePage->next->previous=thePage; } thePage->previous=NULL; theSegment->firstPage=thePage; } return(thePage); } return(NULL); } bool AddBytesToSegment(SEGMENT_RECORD *theSegment,unsigned int address,unsigned char *theBytes,int numBytes) // add theBytes to theSegment at address // if there is a problem, report it, and return false // NOTE: this manages creating code pages, and linking them to theSegment // in the proper location. { CODE_PAGE *thePage; unsigned int baseAddress; unsigned int index; bool fail; fail=false; while(numBytes&&!fail) { thePage=FindCodePage(theSegment,address); // get the nearest page to the one we want to write into baseAddress=address&~0xFF; // mask off low part of address if(!thePage||(thePage->address!=baseAddress)) // see if a new page needs to be created { if((thePage=CreateCodePage(theSegment,thePage))) { thePage->address=baseAddress; // set up the base address for this page } else { ReportComplaint(true,"Failed to create code page\n"); fail=true; } } if(!fail) // make sure there's a good page to use { index=address&0xFF; while(numBytes&&(index<0x100)) // copy bytes into the page { if(thePage->usageMap[index>>3]&(1<<(index&7))) { AssemblyComplaint(NULL,false,"Overwriting address 0x%08X in segment '%s'\n",address,theSegment->theSymbol->name); } thePage->usageMap[index>>3]|=(1<<(index&7)); // update the usage map thePage->pageData[index]=*theBytes; // drop the bytes into the page theBytes++; index++; address++; numBytes--; } } } return(!fail); } bool AddSpaceToSegment(SEGMENT_RECORD *theSegment,unsigned int address,int numBytes) // add theBytes of empty space to theSegment at address // Call this in response to a DS (define space) command { if(theSegment->sawDS) { if(theSegment->minDS>address) { theSegment->minDS=address; } if(theSegment->maxDSmaxDS=address+numBytes-1; } } else { if(numBytes) { theSegment->sawDS=true; theSegment->minDS=address; theSegment->maxDS=address+numBytes-1; } } return(true); } SEGMENT_RECORD *MatchSegment(char *theSegment) // try to match theSegment against the list of segments which currently exist { void *resultValue; if((resultValue=STFindDataForName(segmentSymbols,theSegment))) { return((SEGMENT_RECORD *)resultValue); } return(NULL); } void DestroySegment(SEGMENT_RECORD *theSegment) // remove theSegment from existence { while(theSegment->firstPage) // get rid of code page list { DestroyCodePage(theSegment,theSegment->firstPage); } STRemoveEntry(segmentSymbols,theSegment->theSymbol); if(theSegment->next) { theSegment->next->previous=theSegment->previous; } if(theSegment->previous) { theSegment->previous->next=theSegment->next; } else { segmentsHead=theSegment->next; } DisposePtr(theSegment); } void DestroySegments() // remove all segments { while(segmentsHead) { DestroySegment(segmentsHead); } } SEGMENT_RECORD *CreateSegment(char *segmentName,bool generateOutput) // Create a segment record, link it into the global list, create a symbol table entry for it { SEGMENT_RECORD *theRecord; if((theRecord=(SEGMENT_RECORD *)NewPtr(sizeof(SEGMENT_RECORD)))) { theRecord->generateOutput=generateOutput; theRecord->pageCache=NULL; theRecord->firstPage=NULL; theRecord->currentPC=0; theRecord->codeGenOffset=0; theRecord->sawDS=false; theRecord->minDS=0; theRecord->maxDS=0; theRecord->previous=NULL; theRecord->next=segmentsHead; if((theRecord->theSymbol=STAddEntryAtEnd(segmentSymbols,segmentName,theRecord))) { segmentsHead=theRecord; return(theRecord); } DisposePtr(theRecord); } return(NULL); } static void GetSegmentMinMax(SEGMENT_RECORD *theSegment,int *minAddress,int *maxAddress) // Work out the minimum and maximum addresses occupied by theSegment { CODE_PAGE *thePage; int i; *minAddress=0; *maxAddress=0; if((thePage=theSegment->firstPage)) { i=0; while(i<256&&(thePage->usageMap[i>>3]&(1<<(i&7)))==0) { i++; } *minAddress=thePage->address+i; while(thePage->next) { thePage=thePage->next; } i=255; while(i>0&&(thePage->usageMap[i>>3]&(1<<(i&7)))==0) { i--; } *maxAddress=thePage->address+i; } if(theSegment->sawDS) { if((!theSegment->firstPage)||(theSegment->minDS<(unsigned int)*minAddress)) { *minAddress=theSegment->minDS; } if((!theSegment->firstPage)||(theSegment->maxDS>(unsigned int)*maxAddress)) { *maxAddress=theSegment->maxDS; } } } static void DumpSegmentListing(FILE *theFile,SEGMENT_RECORD *theSegment) // Create a listing of the given segment, and // what memory ranges it spanned { int minAddress, maxAddress; GetSegmentMinMax(theSegment,&minAddress,&maxAddress); fprintf(theFile,"%08X %08X %s\n",minAddress,maxAddress,theSegment->theSymbol->name); } void DumpSegmentsListing(FILE *theFile) // Create a listing of which segments were specified, and // what memory ranges they spanned { SEGMENT_RECORD *theSegment; fprintf(theFile,"Segment Listing\n"); fprintf(theFile,"MinAddr MaxAddr Segment\n"); fprintf(theFile,"-------- -------- -------\n"); theSegment=segmentsHead; while(theSegment) { DumpSegmentListing(theFile,theSegment); theSegment=theSegment->next; } } void UnInitSegments() // undo what InitSegments did { STDisposeSymbolTable(segmentSymbols); } bool InitSegments() // initialize symbol table for segments { if((segmentSymbols=STNewSymbolTable())) { return(true); } return(false); }