virtual void VisitExpr( const SymbolicExpr& v) { SymbolicVal in1, fr1; bool _hasfrac = hasfrac; SymbolicExpr::OpdIterator opds = v.GetOpdIterator(); for ( ; !opds.ReachEnd(); ++opds) { if (operator()(v.Term2Val(*opds), inp, frp)) { _hasfrac = true; break; } } if (opds.ReachEnd()) { if (inp != 0) *inp = v; } else { if (inp == 0 && frp == 0) return; SymbolicExpr* inv = (inp == 0)? 0 : v.DistributeExpr(SYMOP_NIL, SymbolicVal()); SymbolicExpr* frv = (frp == 0)? 0 : v.DistributeExpr(SYMOP_NIL, SymbolicVal()); SymbolicExpr::OpdIterator opd1 = v.GetOpdIterator(); for ( ; opd1 != opds ; ++opd1) { if (inv != 0) inv->AddOpd(*opd1); if (frv != 0) frv->AddOpd(*opd1); } if (inv != 0) inv->ApplyOpd(*inp); if (frv != 0) frv->ApplyOpd(*frp); for (++opd1; !opd1.ReachEnd(); ++opd1) { SymbolicVal cur = v.Term2Val(*opd1); if (operator()(cur, inp, frp)) { if (inv != 0) inv->ApplyOpd(*inp); if (frv != 0) frv->ApplyOpd(*frp); } else { if (inv != 0) inv->AddOpd(*opd1); if (frv != 0) frv->AddOpd(*opd1); } } if (inp != 0) *inp = GetExprVal(inv); if (frp != 0) *frp = GetExprVal(frv); } hasfrac = _hasfrac; }
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; }
long GetExportVal (const Export* E) /* Get the value of this export */ { if (E->Expr == 0) { /* OOPS */ Internal ("`%s' is an undefined external", GetString (E->Name)); } return GetExprVal (E->Expr); }
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; } } } }
unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size) /* Write a supposedly constant expression to the target file. Do a range ** check and return one of the SEG_EXPR_xxx codes. */ { static const unsigned long U_Hi[4] = { 0x000000FFUL, 0x0000FFFFUL, 0x00FFFFFFUL, 0xFFFFFFFFUL }; static const long S_Hi[4] = { 0x0000007FL, 0x00007FFFL, 0x007FFFFFL, 0x7FFFFFFFL }; static const long S_Lo[4] = { ~0x0000007FL, ~0x00007FFFL, ~0x007FFFFFL, ~0x7FFFFFFFL }; /* Get the expression value */ long Val = GetExprVal (E); /* Check the size */ CHECK (Size >= 1 && Size <= 4); /* Check for a range error */ if (Signed) { if (Val > S_Hi[Size-1] || Val < S_Lo[Size-1]) { /* Range error */ return SEG_EXPR_RANGE_ERROR; } } else { if (((unsigned long)Val) > U_Hi[Size-1]) { /* Range error */ return SEG_EXPR_RANGE_ERROR; } } /* Write the value to the file */ WriteVal (F, Val, Size); /* Success */ return SEG_EXPR_OK; }
int IsConstExpr (ExprNode* Root) /* Return true if the given expression is a constant expression, that is, one * with no references to external symbols. */ { int Const; Export* E; Section* S; MemoryArea* M; if (EXPR_IS_LEAF (Root->Op)) { switch (Root->Op) { case EXPR_LITERAL: return 1; case EXPR_SYMBOL: /* Get the referenced export */ E = GetExprExport (Root); /* If this export has a mark set, we've already encountered it. * This means that the export is used to define it's own value, * which in turn means, that we have a circular reference. */ if (ExportHasMark (E)) { CircularRefError (E); Const = 0; } else { MarkExport (E); Const = IsConstExport (E); UnmarkExport (E); } return Const; case EXPR_SECTION: /* A section expression is const if the segment it is in is * not relocatable and already placed. */ S = GetExprSection (Root); M = S->Seg->MemArea; return M != 0 && (M->Flags & MF_PLACED) != 0 && !M->Relocatable; case EXPR_SEGMENT: /* A segment is const if it is not relocatable and placed */ M = Root->V.Seg->MemArea; return M != 0 && (M->Flags & MF_PLACED) != 0 && !M->Relocatable; case EXPR_MEMAREA: /* A memory area is const if it is not relocatable and placed */ return !Root->V.Mem->Relocatable && (Root->V.Mem->Flags & MF_PLACED); default: /* Anything else is not const */ return 0; } } else if (EXPR_IS_UNARY (Root->Op)) { SegExprDesc D; /* Special handling for the BANK pseudo function */ switch (Root->Op) { case EXPR_BANK: /* Get segment references for the expression */ GetSegExprVal (Root->Left, &D); /* The expression is const if the expression contains exactly * one segment that is assigned to a memory area which has a * bank attribute that is constant. */ return (D.TooComplex == 0 && D.Seg != 0 && D.Seg->MemArea != 0 && D.Seg->MemArea->BankExpr != 0 && IsConstExpr (D.Seg->MemArea->BankExpr)); default: /* All others handled normal */ return IsConstExpr (Root->Left); } } else { /* We must handle shortcut boolean expressions here */ switch (Root->Op) { case EXPR_BOOLAND: if (IsConstExpr (Root->Left)) { /* lhs is const, if it is zero, don't eval right */ if (GetExprVal (Root->Left) == 0) { return 1; } else { return IsConstExpr (Root->Right); } } else { /* lhs not const --> tree not const */ return 0; } break; case EXPR_BOOLOR: if (IsConstExpr (Root->Left)) { /* lhs is const, if it is not zero, don't eval right */ if (GetExprVal (Root->Left) != 0) { return 1; } else { return IsConstExpr (Root->Right); } } else { /* lhs not const --> tree not const */ return 0; } break; default: /* All others are handled normal */ return IsConstExpr (Root->Left) && IsConstExpr (Root->Right); } } }
long GetExprVal (ExprNode* Expr) /* Get the value of a constant expression */ { long Right; long Left; long Val; Section* S; Export* E; SegExprDesc D; switch (Expr->Op) { case EXPR_LITERAL: return Expr->V.IVal; case EXPR_SYMBOL: /* Get the referenced export */ E = GetExprExport (Expr); /* If this export has a mark set, we've already encountered it. * This means that the export is used to define it's own value, * which in turn means, that we have a circular reference. */ if (ExportHasMark (E)) { CircularRefError (E); Val = 0; } else { MarkExport (E); Val = GetExportVal (E); UnmarkExport (E); } return Val; case EXPR_SECTION: S = GetExprSection (Expr); return S->Offs + S->Seg->PC; case EXPR_SEGMENT: return Expr->V.Seg->PC; case EXPR_MEMAREA: return Expr->V.Mem->Start; case EXPR_PLUS: return GetExprVal (Expr->Left) + GetExprVal (Expr->Right); case EXPR_MINUS: return GetExprVal (Expr->Left) - GetExprVal (Expr->Right); case EXPR_MUL: return GetExprVal (Expr->Left) * GetExprVal (Expr->Right); case EXPR_DIV: Left = GetExprVal (Expr->Left); Right = GetExprVal (Expr->Right); if (Right == 0) { Error ("Division by zero"); } return Left / Right; case EXPR_MOD: Left = GetExprVal (Expr->Left); Right = GetExprVal (Expr->Right); if (Right == 0) { Error ("Modulo operation with zero"); } return Left % Right; case EXPR_OR: return GetExprVal (Expr->Left) | GetExprVal (Expr->Right); case EXPR_XOR: return GetExprVal (Expr->Left) ^ GetExprVal (Expr->Right); case EXPR_AND: return GetExprVal (Expr->Left) & GetExprVal (Expr->Right); case EXPR_SHL: return GetExprVal (Expr->Left) << GetExprVal (Expr->Right); case EXPR_SHR: return GetExprVal (Expr->Left) >> GetExprVal (Expr->Right); case EXPR_EQ: return (GetExprVal (Expr->Left) == GetExprVal (Expr->Right)); case EXPR_NE: return (GetExprVal (Expr->Left) != GetExprVal (Expr->Right)); case EXPR_LT: return (GetExprVal (Expr->Left) < GetExprVal (Expr->Right)); case EXPR_GT: return (GetExprVal (Expr->Left) > GetExprVal (Expr->Right)); case EXPR_LE: return (GetExprVal (Expr->Left) <= GetExprVal (Expr->Right)); case EXPR_GE: return (GetExprVal (Expr->Left) >= GetExprVal (Expr->Right)); case EXPR_BOOLAND: return GetExprVal (Expr->Left) && GetExprVal (Expr->Right); case EXPR_BOOLOR: return GetExprVal (Expr->Left) || GetExprVal (Expr->Right); case EXPR_BOOLXOR: return (GetExprVal (Expr->Left) != 0) ^ (GetExprVal (Expr->Right) != 0); case EXPR_MAX: Left = GetExprVal (Expr->Left); Right = GetExprVal (Expr->Right); return (Left > Right)? Left : Right; case EXPR_MIN: Left = GetExprVal (Expr->Left); Right = GetExprVal (Expr->Right); return (Left < Right)? Left : Right; case EXPR_UNARY_MINUS: return -GetExprVal (Expr->Left); case EXPR_NOT: return ~GetExprVal (Expr->Left); case EXPR_SWAP: Left = GetExprVal (Expr->Left); return ((Left >> 8) & 0x00FF) | ((Left << 8) & 0xFF00); case EXPR_BOOLNOT: return !GetExprVal (Expr->Left); case EXPR_BANK: GetSegExprVal (Expr->Left, &D); if (D.TooComplex || D.Seg == 0) { Error ("Argument for .BANK is not segment relative or too complex"); } if (D.Seg->MemArea == 0) { Error ("Segment `%s' is referenced by .BANK but " "not assigned to a memory area", GetString (D.Seg->Name)); } if (D.Seg->MemArea->BankExpr == 0) { Error ("Memory area `%s' is referenced by .BANK but " "has no BANK attribute", GetString (D.Seg->MemArea->Name)); } return GetExprVal (D.Seg->MemArea->BankExpr); case EXPR_BYTE0: return GetExprVal (Expr->Left) & 0xFF; case EXPR_BYTE1: return (GetExprVal (Expr->Left) >> 8) & 0xFF; case EXPR_BYTE2: return (GetExprVal (Expr->Left) >> 16) & 0xFF; case EXPR_BYTE3: return (GetExprVal (Expr->Left) >> 24) & 0xFF; case EXPR_WORD0: return GetExprVal (Expr->Left) & 0xFFFF; case EXPR_WORD1: return (GetExprVal (Expr->Left) >> 16) & 0xFFFF; case EXPR_FARADDR: return GetExprVal (Expr->Left) & 0xFFFFFF; case EXPR_DWORD: return GetExprVal (Expr->Left) & 0xFFFFFFFF; default: Internal ("Unknown expression Op type: %u", Expr->Op); /* NOTREACHED */ return 0; } }