void SegDump (void) /* Dump the segments and it's contents */ { unsigned I, J; unsigned long Count; unsigned char* Data; for (I = 0; I < CollCount (&SegmentList); ++I) { Segment* Seg = CollAtUnchecked (&SegmentList, I); printf ("Segment: %s (%lu)\n", GetString (Seg->Name), Seg->Size); for (J = 0; J < CollCount (&Seg->Sections); ++J) { Section* S = CollAtUnchecked (&Seg->Sections, J); unsigned J; Fragment* F = S->FragRoot; printf (" Section:\n"); while (F) { switch (F->Type) { case FRAG_LITERAL: printf (" Literal (%u bytes):", F->Size); Count = F->Size; Data = F->LitBuf; J = 100; while (Count--) { if (J > 75) { printf ("\n "); J = 3; } printf (" %02X", *Data++); J += 3; } printf ("\n"); break; case FRAG_EXPR: printf (" Expression (%u bytes):\n", F->Size); printf (" "); DumpExpr (F->Expr, 0); break; case FRAG_SEXPR: printf (" Signed expression (%u bytes):\n", F->Size); printf (" "); DumpExpr (F->Expr, 0); break; case FRAG_FILL: printf (" Empty space (%u bytes)\n", F->Size); break; default: Internal ("Invalid fragment type: %02X", F->Type); } F = F->Next; } } } }
static void ReadIndex (void) /* Read the index of a library file */ { unsigned Count, I; /* Seek to the start of the index */ fseek (Lib, Header.IndexOffs, SEEK_SET); /* Read the object file count and calculate the cross ref size */ Count = ReadVar (Lib); /* Read all entries in the index */ while (Count--) { ReadIndexEntry (); } /* Read basic object file data from the actual entries */ for (I = 0; I < CollCount (&ObjPool); ++I) { /* Get the object file entry */ ObjData* O = CollAtUnchecked (&ObjPool, I); /* Read data */ ObjReadData (Lib, O); } }
int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count) /* Return true if any of the code entries in the given range has a label * attached. If the code segment does not span the given range, check the * possible span instead. */ { unsigned EntryCount = CS_GetEntryCount(S); /* Adjust count. We expect at least Start to be valid. */ CHECK (Start < EntryCount); if (Start + Count > EntryCount) { Count = EntryCount - Start; } /* Check each entry. Since we have validated the index above, we may * use the unchecked access function in the loop which is faster. */ while (Count--) { const CodeEntry* E = CollAtUnchecked (&S->Entries, Start++); if (CE_HasLabel (E)) { return 1; } } /* No label in the complete range */ return 0; }
int IsBSSType (Segment* S) /* Check if the given segment is a BSS style segment, that is, it does not ** contain non-zero data. */ { /* Loop over all sections */ unsigned I; for (I = 0; I < CollCount (&S->Sections); ++I) { /* Get the next section */ Section* Sec = CollAtUnchecked (&S->Sections, I); /* Loop over all fragments */ Fragment* F = Sec->FragRoot; while (F) { if (F->Type == FRAG_LITERAL) { unsigned char* Data = F->LitBuf; unsigned long Count = F->Size; while (Count--) { if (*Data++ != 0) { return 0; } } } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) { if (GetExprVal (F->Expr) != 0) { return 0; } } F = F->Next; } } return 1; }
void SymLeaveLevel (void) /* Leave the current lexical level */ { /* If this is a scope that allows to emit data into segments, close the ** open the spans. */ if (CurrentScope->Type <= SCOPE_HAS_DATA) { CloseSpanList (&CurrentScope->Spans); } /* If we have spans, the first one is the segment that was active, when the ** scope was opened. Set the size of the scope to the number of data bytes ** emitted into this segment. If we have an owner symbol set the size of ** this symbol, too. */ if (CollCount (&CurrentScope->Spans) > 0) { const Span* S = CollAtUnchecked (&CurrentScope->Spans, 0); unsigned long Size = GetSpanSize (S); DefSizeOfScope (CurrentScope, Size); if (CurrentScope->Label) { DefSizeOfSymbol (CurrentScope->Label, Size); } } /* Mark the scope as closed */ CurrentScope->Flags |= ST_CLOSED; /* Leave the scope */ CurrentScope = CurrentScope->Parent; }
void UseSeg (const SegDef* D) /* Use the segment with the given name */ { unsigned I; for (I = 0; I < CollCount (&SegmentList); ++I) { Segment* Seg = CollAtUnchecked (&SegmentList, I); if (strcmp (Seg->Def->Name, D->Name) == 0) { /* We found this segment. Check if the type is identical */ if (D->AddrSize != ADDR_SIZE_DEFAULT && Seg->Def->AddrSize != D->AddrSize) { Error ("Segment attribute mismatch"); /* Use the new attribute to avoid errors */ Seg->Def->AddrSize = D->AddrSize; } ActiveSeg = Seg; return; } } /* Segment is not in list, create a new one */ if (D->AddrSize == ADDR_SIZE_DEFAULT) { ActiveSeg = NewSegment (D->Name, ADDR_SIZE_ABS); } else { ActiveSeg = NewSegment (D->Name, D->AddrSize); } }
static void SymReplaceExprRefs (SymEntry* S) /* Replace the references to this symbol by a copy of the symbol expression */ { unsigned I; long Val; /* Check if the expression is const and get its value */ int IsConst = IsConstExpr (S->Expr, &Val); CHECK (IsConst); /* Loop over all references */ for (I = 0; I < CollCount (&S->ExprRefs); ++I) { /* Get the expression node */ ExprNode* E = CollAtUnchecked (&S->ExprRefs, I); /* Safety */ CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S); /* We cannot touch the root node, since there are pointers to it. ** Replace it by a literal node. */ E->Op = EXPR_LITERAL; E->V.IVal = Val; } /* Remove all symbol references from the symbol */ CollDeleteAll (&S->ExprRefs); }
void WriteAssertions (void) /* Write the assertion table to the object file */ { unsigned I; /* Get the number of assertions */ unsigned Count = CollCount (&Assertions); /* Tell the object file module that we're about to start the assertions */ ObjStartAssertions (); /* Write the string count to the list */ ObjWriteVar (Count); /* Write the assertions */ for (I = 0; I < Count; ++I) { /* Get the next assertion */ Assertion* A = CollAtUnchecked (&Assertions, I); /* Write it to the file */ WriteExpr (A->Expr); ObjWriteVar ((unsigned) A->Action); ObjWriteVar (A->Msg); WriteLineInfo (&A->LI); } /* Done writing the assertions */ ObjEndAssertions (); }
void CheckAssertions (void) /* Check all assertions */ { unsigned I; /* Walk over all assertions */ for (I = 0; I < CollCount (&Assertions); ++I) { const LineInfo* LI; const char* Module; unsigned Line; /* Get the assertion */ Assertion* A = CollAtUnchecked (&Assertions, I); /* Ignore assertions that shouldn't be handled at link time */ if (!AssertAtLinkTime (A->Action)) { continue; } /* Retrieve the relevant line info for this assertion */ LI = CollConstAt (&A->LineInfos, 0); /* Get file name and line number from the source */ Module = GetSourceName (LI); Line = GetSourceLine (LI); /* If the expression is not constant, we're not able to handle it */ if (!IsConstExpr (A->Expr)) { Warning ("Cannot evaluate assertion in module `%s', line %u", Module, Line); } else if (GetExprVal (A->Expr) == 0) { /* Assertion failed */ const char* Message = GetString (A->Msg); switch (A->Action) { case ASSERT_ACT_WARN: case ASSERT_ACT_LDWARN: Warning ("%s(%u): %s", Module, Line, Message); break; case ASSERT_ACT_ERROR: case ASSERT_ACT_LDERROR: Error ("%s(%u): %s", Module, Line, Message); break; default: Internal ("Invalid assertion action (%u) in module `%s', " "line %u (file corrupt?)", A->Action, Module, Line); break; } } } }
struct DbgSym* GetObjDbgSym (const ObjData* O, unsigned Id) /* Get a debug symbol from an object file checking for a valid index */ { if (Id >= CollCount (&O->DbgSyms)) { Error ("Invalid debug symbol index (%u) in module `%s'", Id, GetObjFileName (O)); } return CollAtUnchecked (&O->DbgSyms, Id); }
struct Export* GetObjExport (const ObjData* O, unsigned Id) /* Get an export from an object file checking for a valid index */ { if (Id >= CollCount (&O->Exports)) { Error ("Invalid export index (%u) in module `%s'", Id, GetObjFileName (O)); } return CollAtUnchecked (&O->Exports, Id); }
char* GetSearchPath (SearchPaths* P, unsigned Index) /* Return the search path at the given index, if the index is valid, return an ** empty string otherwise. */ { if (Index < CollCount (P)) return CollAtUnchecked (P, Index); return ""; }
struct Scope* GetObjScope (const ObjData* O, unsigned Id) /* Get a scope from an object file checking for a valid index */ { if (Id >= CollCount (&O->Scopes)) { Error ("Invalid scope index (%u) in module `%s'", Id, GetObjFileName (O)); } return CollAtUnchecked (&O->Scopes, Id); }
static void DestroyStrPool (Collection* C) /* Free all strings in the given pool plus the item pointers. Note: The * collection may not be reused later. */ { unsigned I; for (I = 0; I < CollCount (C); ++I) { xfree (CollAtUnchecked (C, I)); } DoneCollection (C); }
unsigned char GetSegAddrSize (unsigned SegNum) /* Return the address size of the segment with the given number */ { /* Is there such a segment? */ if (SegNum >= CollCount (&SegmentList)) { FAIL ("Invalid segment number"); } /* Return the address size */ return ((Segment*) CollAtUnchecked (&SegmentList, SegNum))->Def->AddrSize; }
static void DoneMacroExp (MacroExp* E) /* Cleanup after use of a MacroExp structure */ { unsigned I; /* Delete the list with actual arguments */ for (I = 0; I < CollCount (&E->ActualArgs); ++I) { FreeStrBuf (CollAtUnchecked (&E->ActualArgs, I)); } DoneCollection (&E->ActualArgs); SB_Done (&E->Replacement); }
struct CodeEntry* CS_GetNextEntry (CodeSeg* S, unsigned Index) /* Get the code entry following the one with the index Index. If there is no * following code entry, return NULL. */ { if (Index >= CollCount (&S->Entries)-1) { /* This is the last entry */ return 0; } else { /* Code entries left */ return CollAtUnchecked (&S->Entries, Index+1); } }
void FreeAttrList (Collection* C) /* Free a list of attributes */ { unsigned I; /* Walk over the collection and free all attributes */ for (I = 0; I < CollCount (C); ++I) { FreeAttr (CollAtUnchecked (C, I)); } /* Free the collection itself */ FreeCollection (C); }
struct CodeEntry* CS_GetPrevEntry (CodeSeg* S, unsigned Index) /* Get the code entry preceeding the one with the index Index. If there is no * preceeding code entry, return NULL. */ { if (Index == 0) { /* This is the first entry */ return 0; } else { /* Previous entry available */ return CollAtUnchecked (&S->Entries, Index-1); } }
ExprNode* ULabRef (int Which) /* Get an unnamed label. If Which is negative, it is a backreference (a * reference to an already defined label), and the function will return a * segment relative expression. If Which is positive, it is a forward ref, * and the function will return a expression node for an unnamed label that * must be resolved later. */ { int Index; ULabel* L; /* Which can never be 0 */ PRECONDITION (Which != 0); /* Get the index of the referenced label */ if (Which > 0) { --Which; } Index = (int) ULabDefCount + Which; /* We cannot have negative label indices */ if (Index < 0) { /* Label does not exist */ Error ("Undefined label"); /* We must return something valid */ return GenCurrentPC(); } /* Check if the label exists. If not, generate enough forward labels. */ if (Index < (int) CollCount (&ULabList)) { /* The label exists, get it. */ L = CollAtUnchecked (&ULabList, Index); } else { /* Generate new, undefined labels */ while (Index >= (int) CollCount (&ULabList)) { L = NewULabel (0); } } /* Mark the label as referenced */ ++L->Ref; /* If the label is already defined, return its value, otherwise return * just a reference. */ if (L->Val) { return CloneExpr (L->Val); } else { return GenULabelExpr (Index); } }
void FreeObjData (ObjData* O) /* Free an ObjData object. NOTE: This function works only for unused object * data, that is, ObjData objects that aren't used because they aren't * referenced. */ { unsigned I; for (I = 0; I < CollCount (&O->Files); ++I) { CollDeleteItem (&((FileInfo*) CollAtUnchecked (&O->Files, I))->Modules, O); } DoneCollection (&O->Files); DoneCollection (&O->Sections); for (I = 0; I < CollCount (&O->Exports); ++I) { FreeExport (CollAtUnchecked (&O->Exports, I)); } DoneCollection (&O->Exports); for (I = 0; I < CollCount (&O->Imports); ++I) { FreeImport (CollAtUnchecked (&O->Imports, I)); } DoneCollection (&O->Imports); DoneCollection (&O->DbgSyms); DoneCollection (&O->HLLDbgSyms); for (I = 0; I < CollCount (&O->LineInfos); ++I) { FreeLineInfo (CollAtUnchecked (&O->LineInfos, I)); } DoneCollection (&O->LineInfos); xfree (O->Strings); DoneCollection (&O->Assertions); DoneCollection (&O->Scopes); for (I = 0; I < CollCount (&O->Spans); ++I) { FreeSpan (CollAtUnchecked (&O->Spans, I)); } DoneCollection (&O->Spans); xfree (O); }
void ULabDone (void) /* Run through all unnamed labels, check for anomalies and errors and do * necessary cleanups. */ { /* Check if there are undefined labels */ unsigned I = ULabDefCount; while (I < CollCount (&ULabList)) { ULabel* L = CollAtUnchecked (&ULabList, I); LIError (&L->LineInfos, "Undefined label"); ++I; } /* Walk over all labels and emit a warning if any unreferenced ones * are found. Remove line infos because they're no longer needed. */ for (I = 0; I < CollCount (&ULabList); ++I) { ULabel* L = CollAtUnchecked (&ULabList, I); if (L->Ref == 0) { LIWarning (&L->LineInfos, 1, "No reference to unnamed label"); } ReleaseFullLineInfo (&L->LineInfos); } }
void ClearLine (void) /* Clear the current input line */ { unsigned I; /* Remove all pushed fragments from the input stack */ for (I = 0; I < CollCount (&InputStack); ++I) { FreeStrBuf (CollAtUnchecked (&InputStack, I)); } CollDeleteAll (&InputStack); /* Clear the contents of Line */ SB_Clear (Line); CurC = '\0'; NextC = '\0'; }
void WriteHLLDbgSyms (void) /* Write a list of all high level language symbols to the object file. */ { unsigned I; /* Only if debug info is enabled */ if (DbgSyms) { /* Write the symbol count to the list */ ObjWriteVar (CollCount (&HLLDbgSyms)); /* Walk through list and write all symbols to the file. */ for (I = 0; I < CollCount (&HLLDbgSyms); ++I) { /* Get the next symbol */ HLLDbgSym* S = CollAtUnchecked (&HLLDbgSyms, I); /* Get the type of the symbol */ unsigned SC = HLL_GET_SC (S->Flags); /* Remember if the symbol has debug info attached ** ### This should go into DbgInfoCheck */ if (S->Sym && S->Sym->DebugSymId != ~0U) { S->Flags |= HLL_DATA_SYM; } /* Write the symbol data */ ObjWriteVar (S->Flags); ObjWriteVar (S->Name); if (HLL_HAS_SYM (S->Flags)) { ObjWriteVar (S->Sym->DebugSymId); } if (SC == HLL_SC_AUTO || SC == HLL_SC_REG) { ObjWriteVar (S->Offs); } ObjWriteVar (S->Type); ObjWriteVar (S->Scope->Id); } } else { /* Write a count of zero */ ObjWriteVar (0); } }
void CheckSegments (void) /* Walk through the segment list and check if there are segments that were ** not written to the output file. Output an error if this is the case. */ { unsigned I; for (I = 0; I < CollCount (&SegmentList); ++I) { /* Get the next segment */ const Segment* S = CollAtUnchecked (&SegmentList, I); /* Check it */ if (S->Size > 0 && S->Dumped == 0) { Error ("Missing memory area assignment for segment '%s'", GetString (S->Name)); } } }
void BinWriteTarget (BinDesc* D, struct File* F) /* Write a binary output file */ { unsigned I; /* Place the filename in the control structure */ D->Filename = GetString (F->Name); /* Check for unresolved symbols. The function BinUnresolved is called * if we get an unresolved symbol. */ D->Undef = 0; /* Reset the counter */ CheckUnresolvedImports (BinUnresolved, D); if (D->Undef > 0) { /* We had unresolved symbols, cannot create output file */ Error ("%u unresolved external(s) found - cannot create output file", D->Undef); } /* Open the file */ D->F = fopen (D->Filename, "wb"); if (D->F == 0) { Error ("Cannot open `%s': %s", D->Filename, strerror (errno)); } /* Keep the user happy */ Print (stdout, 1, "Opened `%s'...\n", D->Filename); /* Dump all memory areas */ for (I = 0; I < CollCount (&F->MemoryAreas); ++I) { /* Get this entry */ MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I); Print (stdout, 1, " Dumping `%s'\n", GetString (M->Name)); BinWriteMem (D, M); } /* Close the file */ if (fclose (D->F) != 0) { Error ("Cannot write to `%s': %s", D->Filename, strerror (errno)); } /* Reset the file and filename */ D->F = 0; D->Filename = 0; }
int CS_GetEntries (CodeSeg* S, struct CodeEntry** List, unsigned Start, unsigned Count) /* Get Count code entries into List starting at index start. Return true if * we got the lines, return false if not enough lines were available. */ { /* Check if enough entries are available */ if (Start + Count > CollCount (&S->Entries)) { return 0; } /* Copy the entries */ while (Count--) { *List++ = CollAtUnchecked (&S->Entries, Start++); } /* We have the entries */ return 1; }
void PrintSegmentMap (FILE* F) /* Print a segment map to the given file */ { /* Allocate memory for the segment pool */ Segment** SegPool = xmalloc (CollCount (&SegmentList) * sizeof (Segment*)); /* Copy the segment pointers */ unsigned I; for (I = 0; I < CollCount (&SegmentList); ++I) { SegPool[I] = CollAtUnchecked (&SegmentList, I); } /* Sort the array by increasing start addresses */ qsort (SegPool, CollCount (&SegmentList), sizeof (Segment*), CmpSegStart); /* Print a header */ fprintf (F, "Name Start End Size Align\n" "----------------------------------------------------\n"); /* Print the segments */ for (I = 0; I < CollCount (&SegmentList); ++I) { /* Get a pointer to the segment */ Segment* S = SegPool[I]; /* Print empty segments only if explicitly requested */ if (VerboseMap || S->Size > 0) { /* Print the segment data */ long End = S->PC + S->Size; if (S->Size > 0) { /* Point to last element addressed */ --End; } fprintf (F, "%-20s %06lX %06lX %06lX %05lX\n", GetString (S->Name), S->PC, End, S->Size, S->Alignment); } } /* Free the segment pool */ xfree (SegPool); }
void CheckAssertions (void) /* Check all assertions and evaluate the ones we can evaluate here. */ { unsigned I; /* Get the number of assertions */ unsigned Count = CollCount (&Assertions); /* Check the assertions */ for (I = 0; I < Count; ++I) { long Val; /* Get the next assertion */ Assertion* A = CollAtUnchecked (&Assertions, I); /* Ignore it, if it should only be evaluated by the linker */ if (!AssertAtAsmTime (A->Action)) { continue; } /* Can we evaluate the expression? */ if (IsConstExpr (A->Expr, &Val) && Val == 0) { /* Apply the action */ const char* Msg = GetString (A->Msg); switch (A->Action) { case ASSERT_ACT_WARN: LIWarning (&A->LI, 0, "%s", Msg); break; case ASSERT_ACT_ERROR: LIError (&A->LI, "%s", Msg); break; default: Internal ("Illegal assert action specifier"); break; } } } }
ObjData* FindObjData (const char* Module) /* Search for the module with the given name and return it. Return NULL if the ** module is not in the list. */ { unsigned I; /* Hmm. Maybe we should hash the module names? */ for (I = 0; I < CollCount (&ObjPool); ++I) { /* Get this object file */ ObjData* O = CollAtUnchecked (&ObjPool, I); /* Did we find it? */ if (strcmp (O->Name, Module) == 0) { return O; } } return 0; }