void InsertObjGlobals (ObjData* O) /* Insert imports and exports from the object file into the global import and * export lists. */ { unsigned I; /* Insert exports and imports */ for (I = 0; I < CollCount (&O->Exports); ++I) { InsertExport (CollAt (&O->Exports, I)); } for (I = 0; I < CollCount (&O->Imports); ++I) { InsertImport (CollAt (&O->Imports, I)); } }
void CS_DelLabel (CodeSeg* S, CodeLabel* L) /* Remove references from this label and delete it. */ { unsigned Count, I; /* First, remove the label from the hash chain */ CS_RemoveLabelFromHash (S, L); /* Remove references from insns jumping to this label */ Count = CollCount (&L->JumpFrom); for (I = 0; I < Count; ++I) { /* Get the insn referencing this label */ CodeEntry* E = CollAt (&L->JumpFrom, I); /* Remove the reference */ CE_ClearJumpTo (E); } CollDeleteAll (&L->JumpFrom); /* Remove the reference to the owning instruction if it has one. The * function may be called for a label without an owner when deleting * unfinished parts of the code. This is unfortunate since it allows * errors to slip through. */ if (L->Owner) { CollDeleteItem (&L->Owner->Labels, L); } /* All references removed, delete the label itself */ FreeCodeLabel (L); }
static unsigned GetRegInfo1 (CodeSeg* S, CodeEntry* E, int Index, Collection* Visited, unsigned Used, unsigned Unused, unsigned Wanted) /* Recursively called subfunction for GetRegInfo. */ { /* Remember the current count of the line collection */ unsigned Count = CollCount (Visited); /* Call the worker routine */ unsigned R = GetRegInfo2 (S, E, Index, Visited, Used, Unused, Wanted); /* Restore the old count, unmarking all new entries */ unsigned NewCount = CollCount (Visited); while (NewCount-- > Count) { CodeEntry* E = CollAt (Visited, NewCount); CE_ResetMark (E); CollDelete (Visited, NewCount); } /* Return the registers used */ return R; }
static void WriteDep (FILE* F, FileType Types) /* Helper function. Writes all file names that match Types to the output */ { unsigned I; /* Loop over all files */ for (I = 0; I < CollCount (&FileTab); ++I) { const StrBuf* Filename; /* Get the next input file */ const FileEntry* E = (const FileEntry*) CollAt (&FileTab, I); /* Ignore it if it is not of the correct type */ if ((E->Type & Types) == 0) { continue; } /* If this is not the first file, add a space */ if (I > 0) { fputc (' ', F); } /* Print the dependency */ Filename = GetStrBuf (E->Name); fprintf (F, "%*s", SB_GetLen (Filename), SB_GetConstBuf (Filename)); } }
void PopSearchPath (SearchPaths* P) /* Remove a search path from the head of an existing search path list */ { /* Remove the path at position 0 */ xfree (CollAt (P, 0)); CollDelete (P, 0); }
static void WriteDep (FILE* F, InputType Types) /* Helper function. Writes all file names that match Types to the output */ { unsigned I; /* Loop over all files */ unsigned FileCount = CollCount (&IFiles); for (I = 0; I < FileCount; ++I) { /* Get the next input file */ const IFile* IF = (const IFile*) CollAt (&IFiles, I); /* Ignore it if it is not of the correct type */ if ((IF->Type & Types) == 0) { continue; } /* If this is not the first file, add a space */ if (I > 0) { fputc (' ', F); } /* Print the dependency escaping spaces */ WriteEscaped (F, IF->Name); } }
const char* GetCurrentFile (void) /* Return the name of the current input file */ { unsigned AFileCount = CollCount (&AFiles); if (AFileCount > 0) { const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1); return AF->Input->Name; } else { /* No open file. Use the main file if we have one. */ unsigned IFileCount = CollCount (&IFiles); if (IFileCount > 0) { const IFile* IF = (const IFile*) CollAt (&IFiles, 0); return IF->Name; } else { return "(outside file scope)"; } } }
void ObjReadData (FILE* F, ObjData* O) /* Read object file data from the given file. The function expects the Name * and Start fields to be valid. Header and basic data are read. */ { unsigned long Count; /* Seek to the start of the object file data */ fseek (F, O->Start, SEEK_SET); /* Read the object file header */ ObjReadHeader (F, &O->Header, O->Name); /* Read the string pool */ fseek (F, O->Start + O->Header.StrPoolOffs, SEEK_SET); Count = ReadVar (F); CollGrow (&O->Strings, Count); while (Count--) { CollAppend (&O->Strings, ReadStr (F)); } /* Read the exports */ fseek (F, O->Start + O->Header.ExportOffs, SEEK_SET); Count = ReadVar (F); CollGrow (&O->Exports, Count); while (Count--) { unsigned char ConDes[CD_TYPE_COUNT]; /* Skip data until we get to the name */ unsigned Type = ReadVar (F); (void) Read8 (F); /* AddrSize */ ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type)); /* Now this is what we actually need: The name of the export */ CollAppend (&O->Exports, CollAt (&O->Strings, ReadVar (F))); /* Skip the export value */ if (SYM_IS_EXPR (Type)) { /* Expression tree */ SkipExpr (F); } else { /* Literal value */ (void) Read32 (F); } /* Skip the size if necessary */ if (SYM_HAS_SIZE (Type)) { (void) ReadVar (F); } /* Line info indices */ SkipLineInfoList (F); SkipLineInfoList (F); } }
static void ExecCmd (Collection* Args, const CmdEntry* Tab, unsigned Count) /* Search for the command in slot 0 of the given collection. If found, check * the argument count, then execute it. If there are problems, output a * diagnostic. */ { /* Search for the command, check number of args, then execute it */ const char* Cmd = CollAt (Args, 0); const CmdEntry* E = FindCmd (Cmd, Tab, Count); if (E == 0) { PrintLine ("No such command: %s", Cmd); return; } /* Check the number of arguments. Zero means that the function will check * itself. A negative count means that the function needs at least * abs(count) arguments. A positive count means that the function needs * exactly this number of arguments. * Note: The number includes the command itself. */ if (E->ArgCount > 0 && (int)CollCount (Args) != E->ArgCount) { /* Argument number mismatch */ switch (E->ArgCount) { case 1: PrintLine ("Command doesn't accept an argument"); return; case 2: PrintLine ("Command requires an argument"); return; default: PrintLine ("Command requires %d arguments", E->ArgCount-1); return; } } else if (E->ArgCount < 0 && (int)CollCount (Args) < -E->ArgCount) { /* Argument number mismatch */ switch (E->ArgCount) { case -2: PrintLine ("Command requires at least one argument"); return; default: PrintLine ("Command requires at least %d arguments", E->ArgCount-1); return; } } else { /* Remove the command from the argument list, then execute it */ CollDelete (Args, 0); E->Func (Args); } }
void ClearObjData (ObjData* O) /* Remove any data stored in O */ { unsigned I; xfree (O->Name); O->Name = 0; for (I = 0; I < CollCount (&O->Strings); ++I) { xfree (CollAt (&O->Strings, I)); } CollDeleteAll (&O->Strings); CollDeleteAll (&O->Exports); }
unsigned GetCurrentLine (void) /* Return the line number in the current input file */ { unsigned AFileCount = CollCount (&AFiles); if (AFileCount > 0) { const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1); return AF->Line; } else { /* No open file */ return 0; } }
ExprNode* ULabResolve (unsigned Index) /* Return a valid expression for the unnamed label with the given index. This * is used to resolve unnamed labels when assembly is done, so it is an error * if a label is still undefined in this phase. */ { /* Get the label and check that it is defined */ ULabel* L = CollAt (&ULabList, Index); CHECK (L->Val != 0); /* Return the label value */ return CloneExpr (L->Val); }
void FreeObjData (ObjData* O) /* Free a complete struct */ { unsigned I; xfree (O->Name); for (I = 0; I < CollCount (&O->Strings); ++I) { xfree (CollAt (&O->Strings, I)); } DoneCollection (&O->Strings); DoneCollection (&O->Exports); xfree (O); }
Section* GetExprSection (ExprNode* Expr) /* Get the segment for a section expression node */ { /* Check that this is really a section node */ PRECONDITION (Expr->Op == EXPR_SECTION); /* If we have an object file, get the section from it, otherwise * (internally generated expressions), get the section from the * section pointer. */ if (Expr->Obj) { /* Return the export */ return CollAt (&Expr->Obj->Sections, Expr->V.SecNum); } else { return Expr->V.Sec; } }
void CollMove (Collection* C, unsigned OldIndex, unsigned NewIndex) /* Move an item from one position in the collection to another. OldIndex ** is the current position of the item, NewIndex is the new index after ** the function has done it's work. Existing entries with indices NewIndex ** and up are moved one position upwards. */ { /* Get the item and remove it from the collection */ void* Item = CollAt (C, OldIndex); CollDelete (C, OldIndex); /* Correct NewIndex if needed */ if (NewIndex >= OldIndex) { /* Position has changed with removal */ --NewIndex; } /* Now insert it at the new position */ CollInsert (C, Item, NewIndex); }
static IFile* FindFile (const char* Name) /* Find the file with the given name in the list of all files. Since the list * is not large (usually less than 10), I don't care about using hashes or * similar things and do a linear search. */ { unsigned I; for (I = 0; I < CollCount (&IFiles); ++I) { /* Get the file struct */ IFile* IF = (IFile*) CollAt (&IFiles, I); /* Check the name */ if (strcmp (Name, IF->Name) == 0) { /* Found, return the struct */ return IF; } } /* Not found */ return 0; }
static void CS_MoveLabelsToEntry (CodeSeg* S, CodeEntry* E) /* Move all labels from the label pool to the given entry and remove them * from the pool. */ { /* Transfer the labels if we have any */ unsigned I; unsigned LabelCount = CollCount (&S->Labels); for (I = 0; I < LabelCount; ++I) { /* Get the label */ CodeLabel* L = CollAt (&S->Labels, I); /* Attach it to the entry */ CE_AttachLabel (E, L); } /* Delete the transfered labels */ CollDeleteAll (&S->Labels); }
int FindAttr (const Collection* C, const char* Name, unsigned* Index) /* Search for an attribute with the given name in the collection. If it is * found, the function returns true and Index contains the index of the * entry. If Name isn't found, the function returns false and Index * will contain the insert position. */ { /* Do a binary search */ int Lo = 0; int Hi = (int) CollCount (C) - 1; while (Lo <= Hi) { /* Mid of range */ int Cur = (Lo + Hi) / 2; /* Get item */ const Attr* A = CollAt (C, Cur); /* Compare */ int Res = strcmp (A->Name, Name); /* Found? */ if (Res < 0) { Lo = Cur + 1; } else if (Res > 0) { Hi = Cur - 1; } else { /* Found! */ *Index = Cur; return 1; } } /* Pass back the insert position */ *Index = Lo; return 0; }
Export* ReadExport (FILE* F, ObjData* O) /* Read an export from a file */ { unsigned ConDesCount; unsigned I; Export* E; /* Read the type */ unsigned Type = ReadVar (F); /* Read the address size */ unsigned char AddrSize = Read8 (F); /* Create a new export without a name */ E = NewExport (Type, AddrSize, INVALID_STRING_ID, O); /* Read the constructor/destructor decls if we have any */ ConDesCount = SYM_GET_CONDES_COUNT (Type); if (ConDesCount > 0) { unsigned char ConDes[CD_TYPE_COUNT]; /* Read the data into temp storage */ ReadData (F, ConDes, ConDesCount); /* Re-order the data. In the file, each decl is encoded into a byte ** which contains the type and the priority. In memory, we will use ** an array of types which contain the priority. */ for (I = 0; I < ConDesCount; ++I) { E->ConDes[CD_GET_TYPE (ConDes[I])] = CD_GET_PRIO (ConDes[I]); } } /* Read the name */ E->Name = MakeGlobalStringId (O, ReadVar (F)); /* Read the value */ if (SYM_IS_EXPR (Type)) { E->Expr = ReadExpr (F, O); } else { E->Expr = LiteralExpr (Read32 (F), O); } /* Read the size */ if (SYM_HAS_SIZE (Type)) { E->Size = ReadVar (F); } /* Last are the locations */ ReadLineInfoList (F, O, &E->DefLines); ReadLineInfoList (F, O, &E->RefLines); /* If this symbol is exported as a condes, and the condes type declares a ** forced import, add this import to the object module. */ for (I = 0; I < CD_TYPE_COUNT; ++I) { const ConDesImport* CDI; if (E->ConDes[I] != CD_PRIO_NONE && (CDI = ConDesGetImport (I)) != 0) { unsigned J; /* Generate a new import, and add it to the module's import list. */ Import* Imp = GenImport (CDI->Name, CDI->AddrSize); Imp->Obj = O; CollAppend (&O->Imports, Imp); /* Add line info for the export that is actually the condes that ** forces the import. Then, add line info for the config. file. ** The export's info is added first because the import pretends ** that it came from the object module instead of the config. file. */ for (J = 0; J < CollCount (&E->DefLines); ++J) { CollAppend (&Imp->RefLines, DupLineInfo (CollAt (&E->DefLines, J))); } CollAppend (&Imp->RefLines, GenLineInfo (&CDI->Pos)); } } /* Return the new export */ return E; }
static StrBuf* ME_GetActual (MacroExp* E, unsigned Index) /* Return an actual macro argument with the given index */ { return CollAt (&E->ActualArgs, Index); }