static void CreateRunDefines (SegDesc* S, unsigned long SegAddr) /* Create the defines for a RUN segment */ { StrBuf Buf = STATIC_STRBUF_INITIALIZER; SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name)); CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start); SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name)); CreateConstExport (GetStrBufId (&Buf), S->Seg->Size); S->Flags |= SF_RUN_DEF; SB_Done (&Buf); }
static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr) /* Create the defines for a LOAD segment */ { StrBuf Buf = STATIC_STRBUF_INITIALIZER; SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name)); CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start); S->Flags |= SF_LOAD_DEF; SB_Done (&Buf); }
unsigned AddFile (const StrBuf* Name, FileType Type, unsigned long Size, unsigned long MTime) /* Add a new file to the list of input files. Return the index of the file in * the table. */ { /* Create a new file entry and insert it into the tables */ FileEntry* F = NewFileEntry (GetStrBufId (Name), Type, Size, MTime); /* Return the index */ return F->Index; }
unsigned GetFileIndex (const StrBuf* Name) /* Return the file index for the given file name. */ { /* Get the string pool index from the name */ unsigned NameIdx = GetStrBufId (Name); /* Search in the hash table for the name */ const FileEntry* F = HT_Find (&HashTab, &NameIdx); /* If we don't have this index, print a diagnostic and use the main file */ if (F == 0) { Error ("File name `%m%p' not found in file table", Name); return 0; } else { return F->Index; } }
static int ValidateType (StrBuf* Type) /* Check if the given type is valid and if so, return a string id for it. If ** the type isn't valid, return -1. Type is overwritten when checking. */ { unsigned I; const char* A; char* B; /* The length must not be zero and divideable by two */ unsigned Length = SB_GetLen (Type); if (Length < 2 || (Length & 0x01) != 0) { ErrorSkip ("Type value has invalid length"); return -1; } /* The string must consist completely of hex digit chars */ A = SB_GetConstBuf (Type); for (I = 0; I < Length; ++I) { if (!IsXDigit (A[I])) { ErrorSkip ("Type value contains invalid characters"); return -1; } } /* Convert the type to binary */ B = SB_GetBuf (Type); while (A < SB_GetConstBuf (Type) + Length) { /* Since we know, there are only hex digits, there can't be any errors */ *B++ = (HexValue (A[0]) << 4) | HexValue (A[1]); A += 2; } Type->Len = (Length /= 2); /* Allocate the type and return it */ return GetStrBufId (Type); }
SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags) /* Allocate a symbol table entry, initialize and return it */ { unsigned I; /* Allocate memory */ SymEntry* S = xmalloc (sizeof (SymEntry)); /* Initialize the entry */ S->Left = 0; S->Right = 0; S->Locals = 0; S->Sym.Tab = 0; S->DefLines = EmptyCollection; S->RefLines = EmptyCollection; for (I = 0; I < sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0]); ++I) { S->GuessedUse[I] = 0; } S->HLLSym = 0; S->Flags = Flags; S->DebugSymId = ~0U; S->ImportId = ~0U; S->ExportId = ~0U; S->Expr = 0; S->ExprRefs = AUTO_COLLECTION_INITIALIZER; S->ExportSize = ADDR_SIZE_DEFAULT; S->AddrSize = ADDR_SIZE_DEFAULT; memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio)); S->Name = GetStrBufId (Name); /* Insert it into the list of all entries */ S->List = SymList; SymList = S; /* Return the initialized entry */ return S; }
void OptStr (unsigned char Type, const StrBuf* Text) /* Add a string option */ { NewOption (Type, GetStrBufId (Text)); }
void OptOS (const StrBuf* OS) /* Add an operating system option */ { NewOption (OPT_OS, GetStrBufId (OS)); }
void OptCompiler (const StrBuf* Compiler) /* Add a compiler option */ { NewOption (OPT_COMPILER, GetStrBufId (Compiler)); }
void OptTranslator (const StrBuf* Translator) /* Add a translator option */ { NewOption (OPT_TRANSLATOR, GetStrBufId (Translator)); }
void OptAuthor (const StrBuf* Author) /* Add an author statement */ { NewOption (OPT_AUTHOR, GetStrBufId (Author)); }
void OptComment (const StrBuf* Comment) /* Add a comment */ { NewOption (OPT_COMMENT, GetStrBufId (Comment)); }
static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name) /* Allocate a symbol table on the heap and return it */ { /* Determine the lexical level and the number of table slots */ unsigned Level = Parent? Parent->Level + 1 : 0; unsigned Slots = ScopeTableSize (Level); /* Allocate memory */ SymTable* S = xmalloc (sizeof (SymTable) + (Slots-1) * sizeof (SymEntry*)); /* Set variables and clear hash table entries */ S->Next = 0; S->Left = 0; S->Right = 0; S->Childs = 0; S->Label = 0; S->Spans = AUTO_COLLECTION_INITIALIZER; S->Id = ScopeCount++; S->Flags = ST_NONE; S->AddrSize = ADDR_SIZE_DEFAULT; S->Type = SCOPE_UNDEF; S->Level = Level; S->TableSlots = Slots; S->TableEntries = 0; S->Parent = Parent; S->Name = GetStrBufId (Name); while (Slots--) { S->Table[Slots] = 0; } /* Insert the symbol table into the list of all symbol tables */ if (RootScope == 0) { RootScope = S; } else { LastScope->Next = S; } LastScope = S; /* Insert the symbol table into the child tree of the parent */ if (Parent) { SymTable* T = Parent->Childs; if (T == 0) { /* First entry */ Parent->Childs = S; } else { while (1) { /* Choose next entry */ int Cmp = SB_Compare (Name, GetStrBuf (T->Name)); if (Cmp < 0) { if (T->Left) { T = T->Left; } else { T->Left = S; break; } } else if (Cmp > 0) { if (T->Right) { T = T->Right; } else { T->Right = S; break; } } else { /* Duplicate scope name */ Internal ("Duplicate scope name: `%m%p'", Name); } } } } /* Return the prepared struct */ return S; }
void DbgInfoSym (void) /* Parse and handle SYM subcommand of the .dbg pseudo instruction */ { static const char* const StorageKeys[] = { "AUTO", "EXTERN", "REGISTER", "STATIC", }; unsigned Name; int Type; unsigned AsmName = EMPTY_STRING_ID; unsigned Flags; int Offs = 0; HLLDbgSym* S; /* Parameters are separated by a comma */ ConsumeComma (); /* Name */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Name = GetStrBufId (&CurTok.SVal); NextTok (); /* Comma expected */ ConsumeComma (); /* Type */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Type = ValidateType (&CurTok.SVal); if (Type < 0) { return; } NextTok (); /* Comma expected */ ConsumeComma (); /* The storage class follows */ if (CurTok.Tok != TOK_IDENT) { ErrorSkip ("Storage class specifier expected"); return; } switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) { case 0: Flags = HLL_SC_AUTO; break; case 1: Flags = HLL_SC_EXTERN; break; case 2: Flags = HLL_SC_REG; break; case 3: Flags = HLL_SC_STATIC; break; default: ErrorSkip ("Storage class specifier expected"); return; } /* Skip the storage class token and the following comma */ NextTok (); ConsumeComma (); /* The next tokens depend on the storage class */ if (Flags == HLL_SC_AUTO) { /* Auto: Stack offset follows */ Offs = ConstExpression (); } else { /* Register, extern or static: Assembler name follows */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } AsmName = GetStrBufId (&CurTok.SVal); NextTok (); /* For register, an offset follows */ if (Flags == HLL_SC_REG) { ConsumeComma (); Offs = ConstExpression (); } } /* Add the function */ S = NewHLLDbgSym (Flags | HLL_TYPE_SYM, Name, Type); S->AsmName = AsmName; S->Offs = Offs; CollAppend (&HLLDbgSyms, S); }
void DbgInfoFunc (void) /* Parse and handle func subcommand of the .dbg pseudo instruction */ { static const char* const StorageKeys[] = { "EXTERN", "STATIC", }; unsigned Name; int Type; unsigned AsmName; unsigned Flags; HLLDbgSym* S; /* Parameters are separated by a comma */ ConsumeComma (); /* Name */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Name = GetStrBufId (&CurTok.SVal); NextTok (); /* Comma expected */ ConsumeComma (); /* Type */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Type = ValidateType (&CurTok.SVal); if (Type < 0) { return; } NextTok (); /* Comma expected */ ConsumeComma (); /* The storage class follows */ if (CurTok.Tok != TOK_IDENT) { ErrorSkip ("Storage class specifier expected"); return; } switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) { case 0: Flags = HLL_TYPE_FUNC | HLL_SC_EXTERN; break; case 1: Flags = HLL_TYPE_FUNC | HLL_SC_STATIC; break; default: ErrorSkip ("Storage class specifier expected"); return; } NextTok (); /* Comma expected */ ConsumeComma (); /* Assembler name follows */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } AsmName = GetStrBufId (&CurTok.SVal); NextTok (); /* There may only be one function per scope */ if (CurrentScope == RootScope) { ErrorSkip ("Functions may not be used in the root scope"); return; } else if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label == 0) { ErrorSkip ("Functions can only be tagged to .PROC scopes"); return; } else if (CurrentScope->Label->HLLSym != 0) { ErrorSkip ("Only one HLL symbol per asm symbol is allowed"); return; } else if (CurrentScope->Label->Name != AsmName) { ErrorSkip ("Scope label and asm name for function must match"); return; } /* Add the function */ S = NewHLLDbgSym (Flags, Name, Type); S->Sym = CurrentScope->Label; CurrentScope->Label->HLLSym = S; CollAppend (&HLLDbgSyms, S); }
unsigned CfgAssignSegments (void) /* Assign segments, define linker symbols where requested. The function will * return the number of memory area overflows (so zero means anything went ok). * In case of overflows, a short mapfile can be generated later, to ease the * task of rearranging segments for the user. */ { unsigned Overflows = 0; /* Walk through each of the memory sections. Add up the sizes and check * for an overflow of the section. Assign the start addresses of the * segments while doing this. */ Memory* M = MemoryList; while (M) { MemListNode* N; /* Get the start address of this memory area */ unsigned long Addr = M->Start; /* Remember if this is a relocatable memory area */ M->Relocatable = RelocatableBinFmt (M->F->Format); /* Walk through the segments in this memory area */ N = M->SegList; while (N) { /* Get the segment from the node */ SegDesc* S = N->Seg; /* Some actions depend on wether this is the load or run memory * area. */ if (S->Run == M) { /* This is the run (and maybe load) memory area. Handle * alignment and explict start address and offset. */ if (S->Flags & SF_ALIGN) { /* Align the address */ unsigned long Val = (0x01UL << S->Align) - 1; Addr = (Addr + Val) & ~Val; } else if (S->Flags & (SF_OFFSET | SF_START)) { /* Give the segment a fixed starting address */ unsigned long NewAddr = S->Addr; if (S->Flags & SF_OFFSET) { /* An offset was given, no address, make an address */ NewAddr += M->Start; } if (Addr > NewAddr) { /* Offset already too large */ if (S->Flags & SF_OFFSET) { Error ("Offset too small in `%s', segment `%s'", GetString (M->Name), GetString (S->Name)); } else { Error ("Start address too low in `%s', segment `%s'", GetString (M->Name), GetString (S->Name)); } } Addr = NewAddr; } /* Set the start address of this segment, set the readonly flag * in the segment and and remember if the segment is in a * relocatable file or not. */ S->Seg->PC = Addr; S->Seg->ReadOnly = (S->Flags & SF_RO) != 0; S->Seg->Relocatable = M->Relocatable; } else if (S->Load == M) { /* This is the load memory area, *and* run and load are * different (because of the "else" above). Handle alignment. */ if (S->Flags & SF_ALIGN_LOAD) { /* Align the address */ unsigned long Val = (0x01UL << S->AlignLoad) - 1; Addr = (Addr + Val) & ~Val; } } /* Increment the fill level of the memory area and check for an * overflow. */ M->FillLevel = Addr + S->Seg->Size - M->Start; if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) { ++Overflows; M->Flags |= MF_OVERFLOW; Warning ("Memory area overflow in `%s', segment `%s' (%lu bytes)", GetString (M->Name), GetString (S->Name), M->FillLevel - M->Size); } /* If requested, define symbols for the start and size of the * segment. */ if (S->Flags & SF_DEFINE) { if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) { CreateRunDefines (S, Addr); } if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) { CreateLoadDefines (S, Addr); } } /* Calculate the new address */ Addr += S->Seg->Size; /* Next segment */ N = N->Next; } /* If requested, define symbols for start and size of the memory area */ if (M->Flags & MF_DEFINE) { StrBuf Buf = STATIC_STRBUF_INITIALIZER; SB_Printf (&Buf, "__%s_START__", GetString (M->Name)); CreateMemoryExport (GetStrBufId (&Buf), M, 0); SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name)); CreateConstExport (GetStrBufId (&Buf), M->Size); SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name)); CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel); SB_Done (&Buf); } /* Next memory area */ M = M->Next; } /* Return the number of memory area overflows */ return Overflows; }