📄 link.c
字号:
#include <stdlib.h>#include <stdio.h>#include "io.h"#include "ex.h"#include "res.h"#include "st.h"typedef struct FileBuf *FileBuf;struct FileBuf { char *Name; long Loc, Files, Segs, Gaps, Syms, Exps, Relocs; char **File; Segment Seg; Gap G; Symbol *Sym;};FileBuf FTab; int Fs;typedef struct Block *Block;struct Block { char *Src, *Obj; Segment Seg; Block Next;};static Block *BHead;static int *BSize;static Segment USeg;typedef struct Image *Image;struct Image { word Base; long Size; char *Src, *Obj; word Line; long Loc; Image Prev, Next;};static Image IHead, ITail;Exp *ExpBuf;static Image FormImage( word Base, long Size, char *Src, char *Obj, word Line, long Loc) { Image IP = (Image)Allocate(sizeof *IHead); IP->Base = Base, IP->Size = Size, IP->Src = Src, IP->Obj = Obj, IP->Line = Line, IP->Loc = Loc; return IP;}static void SetImage(void) { Block BP; for (IHead = ITail = 0, BP = BHead[0]; BP != 0; BP = BP->Next) { Segment Seg = BP->Seg; Image P, IP, NewI; for (IP = IHead; IP != 0; IP = IP->Next) if (IP->Base >= Seg->Base) break; P = (IP == 0)? ITail: IP->Prev; if (P != 0 && P->Base + P->Size > Seg->Base) FATAL("Overlapping segments at [%d] %s and [%d] %s.", P->Line, P->Src, Seg->Line, BP->Src ); if (IP != 0 && Seg->Base + Seg->Size > IP->Base) FATAL("Overlapping segments at [%d] %s and [%d] %s.", Seg->Line, BP->Src, IP->Line, IP->Src ); NewI = FormImage( Seg->Base, Seg->Size, BP->Src, BP->Obj, Seg->Line, Seg->Loc ); if (P == 0) IHead = NewI; else P->Next = NewI; if (IP == 0) ITail = NewI; else IP->Prev = NewI; NewI->Next = IP, NewI->Prev = P; }}static void FitGap(Gap G) { Image P, IP, NewI; long End, EndP; word Base = G->Seg->Base + G->Offset; long Size = G->Size; for (IP = IHead; IP != 0; IP = IP->Next) if (IP->Base > Base) break; P = (IP == 0)? ITail: IP->Prev; if (P == 0) FATAL("Internal error (2)."); End = Base + Size, EndP = P->Base + P->Size; if (EndP < End) FATAL("Internal error (3)."); if (P->Base < Base) { P->Size = Base - P->Base; if (EndP > End) { NewI = FormImage( (word)End, EndP - End, P->Src, P->Obj, P->Line, P->Loc + P->Size ); NewI->Next = IP, P->Next = NewI; NewI->Prev = P; if (IP == 0) ITail = NewI; else IP->Prev = NewI; } } else if (EndP > End) P->Base += Size, P->Size -= Size; else { if (P->Prev == 0) IHead = P->Next; else P->Prev->Next = P->Next; if (P->Next == 0) ITail = P->Prev; else P->Next->Prev = P->Prev; free(P); }}typedef struct Free *Free;struct Free { word Base; long Size; Block BP;};static Free *FHead;static int *FSize;void SetFree(void) { int T; FHead = (Free *)Allocate(SEG_TYPES * sizeof *FHead); FSize = (int *)Allocate(SEG_TYPES * sizeof *FSize); for (T = 0; T < SEG_TYPES; T++) { Block P, B; Free F; long Base; FHead[T] = (Free)Allocate((BSize[T] + 1) * sizeof *FHead[T]); for (P = 0, B = BHead[T], F = FHead[T]; B != 0; P = B, B = B->Next) { Base = (P == 0)? AddrTab[T].Lo: (long) P->Seg->Base + P->Seg->Size; if (Base >= B->Seg->Base) continue; F->Base = Base, F->Size = (long)B->Seg->Base - Base, F->BP = P, F++; } Base = (P == 0)? AddrTab[T].Lo: (long) P->Seg->Base + P->Seg->Size; if (Base <= AddrTab[T].Hi) F->Base = Base, F->Size = (long)AddrTab[T].Hi + 1 - Base, F->BP = P, F++; FSize[T] = F - FHead[T]; }}void PurgeFree(void) { int T; for (T = 0; T < SEG_TYPES; T++) free(FHead[T]); free(FHead), free(FSize);}void BestFit(char *Obj, Segment Seg) { byte T = Seg->Type; Free Best, FP; Block B; if (!Seg->Rel) return; StartLine = Seg->Line, StartF = Seg->File; for (Best = 0, FP = FHead[T]; FP < FHead[T] + FSize[T]; FP++) { if ( Seg->Size <= FP->Size && (Best == 0 || FP->Size < Best->Size) ) Best = FP; } if (Best == 0) FATAL("Cannot fit segment."); B = (Block)Allocate(sizeof *B); B->Seg = Seg, B->Src = FileTab[StartF], B->Obj = Obj; if (Best->BP == 0) B->Next = BHead[T], BHead[T] = B; else B->Next = Best->BP->Next, Best->BP->Next = B; Seg->Rel = 0, Seg->Base = Best->Base, Best->BP = B, Best->Base += Seg->Size, Best->Size -= Seg->Size;}void FitSegs(FileBuf F) { int S; Segment Seg; FileTab = F->File; for (S = TYPES; S < F->Segs; S++) { Seg = F->Seg + S - TYPES, BestFit(F->Name, Seg); }}void SetSeg(void) { Segment S; int I; USeg = (Segment)Allocate(TYPES * sizeof *USeg); for (S = USeg; S < USeg + TYPES; S++) S->Line = S->File = 0, S->Rel = 0, S->Type = S - USeg, S->Base = 0, S->Size = 0, S->Loc = 0L; BHead = (Block *)Allocate(SEG_TYPES * sizeof *BHead); BSize = (int *)Allocate(SEG_TYPES * sizeof *BSize); for (I = 0; I < SEG_TYPES; I++) BHead[I] = 0, BSize[I] = 0;}void FreeBlocks(void) { int I; for (I = 0; I < SEG_TYPES; I++) { Block B, N; for (B = BHead[I]; B != 0; B = N) N = B->Next, free(B); } free(BHead), free(BSize);}void Fit(char *Obj, Segment Seg) { byte T = Seg->Type; Block Cur, Prev, B; if (Seg->Rel) return; for (Prev = 0, Cur = BHead[T]; Cur != 0; Prev = Cur, Cur = Cur->Next) if (Cur->Seg->Base >= Seg->Base) break; if (Prev != 0 && Prev->Seg->Base + Prev->Seg->Size > Seg->Base) ERROR("Overlapping segments: %s [%d] and %s [%d].", FileTab[Seg->File], Seg->Line, Prev->Src, Prev->Seg->Line ); if (Cur != 0 && Cur->Seg->Base < Seg->Base + Seg->Size) ERROR("Overlapping segments: %s [%d] and %s [%d].", FileTab[Seg->File], Seg->Line, Cur->Src, Cur->Seg->Line ); B = (Block)Allocate(sizeof *B); B->Src = FileTab[Seg->File], B->Obj = Obj, B->Seg = Seg, B->Next = Cur; if (Prev == 0) BHead[T] = B; else Prev->Next = B; BSize[T]++;}void GetHead(FileBuf F) { word MAGIC; long S; byte Buf[0x100]; FILE *FP = fopen(F->Name, "rb+"); if (FP == 0) FATAL("Cannot open %s.", F->Name); MAGIC = GetW(FP); if (MAGIC != 0x55aa) FATAL("Invalid object file %s.", F->Name); F->Loc = GetL(FP), F->Files = GetL(FP), F->Segs = GetL(FP), F->Gaps = GetL(FP), F->Syms = GetL(FP), F->Exps = GetL(FP), F->Relocs = GetL(FP); S = F->Loc + F->Files + F->Segs + F->Gaps + F->Syms + F->Exps + F->Relocs; if (GetL(FP) != S&0xffffffff) FATAL("Corrupt object file %s.", F->Name); F->File = (char **)Allocate((word)F->Files * sizeof *F->File); F->Seg = (F->Segs < TYPES)? 0: (Segment)Allocate((word)(F->Segs - TYPES) * sizeof *F->Seg); F->G = (Gap)Allocate((word)F->Gaps * sizeof *F->G); F->Sym = (Symbol *)Allocate((word)F->Syms * sizeof *F->Sym); FileTab = F->File; fseek(FP, F->Loc, SEEK_SET); for (S = 0; S < F->Files; S++) { word L; L = GetW(FP), fread(Buf, 1, L, FP), Buf[L] = '\0'; F->File[S] = CopyS(Buf); } for (S = TYPES; S < F->Segs; S++) { Segment Seg = F->Seg + S - TYPES; word U; Seg->Line = GetW(FP), Seg->File = GetW(FP), U = GetW(FP), Seg->Size = GetW(FP), Seg->Base = GetW(FP), Seg->Loc = GetL(FP); Seg->Rel = (U >> 8)&1, Seg->Type = U&0xff; Fit(F->Name, Seg); } for (S = 0; S < F->Gaps; S++) { Gap G = F->G + S; word Sg; Sg = GetW(FP), G->Offset = GetW(FP), G->Size = GetW(FP); G->Seg = Sg < TYPES? &USeg[Sg]: &F->Seg[Sg - TYPES]; } for (S = 0; S < F->Syms; S++) { Symbol Sym; byte B, Defined, Global, Address; word U, L, Offset; B = GetB(FP), U = GetW(FP), Offset = GetW(FP), L = GetW(FP); if (L > 0) fread(Buf, 1, L, FP); Buf[L] = '\0'; Global = (B&8)? 1: 0, Defined = (B&4)? 1: 0, Address = (B&2)? 1: 0; if (!Global) { Sym = (Symbol)Allocate(sizeof *Sym); Sym->Variable = 0, Sym->Address = Address; Sym->Global = Global, Sym->Defined = Defined; Sym->Seg = !Address? 0: U < TYPES? &USeg[U]: &F->Seg[U - TYPES]; Sym->Offset = Offset; Sym->Index = F - FTab; Sym->Name = CopyS(Buf); } else { Sym = LookUp(Buf); if (Sym->Defined && Defined) ERROR("Symbol %s redefined: %s %s.", Sym->Name, FTab[Sym->Index].Name, F->Name ); else { if (Sym->Address) { Segment Seg = U < TYPES? &USeg[U]: &F->Seg[U - TYPES]; if (!Address) ERROR("Address %s redeclared as number: %s %s", Sym->Name, FTab[Sym->Index].Name, F->Name ); else if (Sym->Seg->Type != Seg->Type) ERROR("Type mismatch %s: %s %s", Sym->Name, FTab[Sym->Index].Name, F->Name ); } else if (Address && Sym->Global) ERROR("Number %s redeclared as address: %s %s", Sym->Name, FTab[Sym->Index].Name, F->Name ); if (Defined || !Sym->Global) { Sym->Variable = 0, Sym->Address = Address; Sym->Global = Global, Sym->Defined = Defined; Sym->Seg = !Address? 0: U < TYPES? &USeg[U]: &F->Seg[U - TYPES], Sym->Offset = Offset; Sym->Index = F - FTab; } } } F->Sym[S] = Sym; } F->Loc = ftell(FP); fclose(FP);}typedef struct RList *RList;struct RList { byte Size; long PC, Val; RList Next;};RList RHead;void AddReloc(byte Size, long PC, long Val) { RList R = Allocate(sizeof *R), P, S; for (P = 0, S = RHead; S != 0; P = S, S = S->Next) if (S->PC >= PC) break; if (S != 0 && S->PC == PC) FATAL("Internal error (4)."); if (P == 0) RHead = R; else P->Next = R; R->Next = S, R->Size = Size, R->PC = PC, R->Val = Val;}void SetRelocs(FileBuf F) { long S; struct Item IBuf; Exp E, NextE; FILE *FP = fopen(F->Name, "rb+"); if (FP == 0) FATAL("Cannot open %s.", F->Name); FileTab = F->File; fseek(FP, F->Loc, SEEK_SET); ExpBuf = (Exp *)Allocate((unsigned)F->Exps * sizeof *ExpBuf); ExpInit(); for (S = 0; S < F->Exps; S++) { Exp *EP = ExpBuf + S; byte Tag; Segment Seg; Exp A, B, C; word Line, File, U, Offset; byte Op; StartLine = GetW(FP), StartF = GetW(FP), Tag = GetB(FP); switch (Tag) { case NumX: Value = GetW(FP); *EP = MakeExp(NumX, Value); break; case AddrX: U = GetW(FP), Offset = GetW(FP); Seg = U < TYPES? &USeg[U]: &F->Seg[U - TYPES]; *EP = MakeExp(AddrX, Seg, Offset); break; case SymX: U = GetW(FP); *EP = MakeExp(SymX, F->Sym[U]); break; case UnX: Op = GetB(FP), U = GetW(FP), A = ExpBuf[U], *EP = MakeExp(UnX, Op, A); break; case BinX: Op = GetB(FP), U = GetW(FP), A = ExpBuf[U], U = GetW(FP), B = ExpBuf[U], *EP = MakeExp(BinX, Op, A, B); break; case CondX: U = GetW(FP), A = ExpBuf[U], U = GetW(FP), B = ExpBuf[U], U = GetW(FP), C = ExpBuf[U], *EP = MakeExp(CondX, A, B, C); break; } } for (S = 0; S < F->Relocs; S++) { word U, PC; IBuf.Line = GetW(FP), IBuf.File = GetW(FP), IBuf.Tag = GetB(FP), U = GetW(FP), IBuf.E = ExpBuf[U], U = GetW(FP), IBuf.Seg = U < TYPES? &USeg[U]: &F->Seg[U - TYPES]; IBuf.Offset = GetW(FP); Resolve(&IBuf); PC = (long)IBuf.Seg->Base + (long)IBuf.Offset; switch (IBuf.Tag) { case 'b': AddReloc(1, PC, LVal); break; case 'w': AddReloc(2, PC, LVal); break; default: FATAL("Internal error (5)."); } } fclose(FP); for (E = ExpHead; E != 0; E = NextE) NextE = E->Next, free(E); free(ExpBuf);}/* HEX OUTPUT ROUTINES */FILE *OutF = 0;byte HexBuf[0x10]; int HexX;long HexAddr;void OpenHex(char *Hex) { OutF = fopen(Hex, "w"); if (OutF == 0) FATAL("Cannot open output file."); HexX = 0;}void EndHex(void) { if (HexX > 0) { int H, Sum; Sum = (HexAddr&0xff) + ((HexAddr >> 8)&0xff) + HexX; fprintf(OutF, ":%02X%04X00", HexX, HexAddr); for (H = 0; H < HexX; H++) fprintf(OutF, "%02X", HexBuf[H]), Sum += HexBuf[H]; fprintf(OutF, "%02X\n", (-Sum)&0xff); HexX = 0; }}void PutHex(long Addr, byte Hex) { if (HexX == 0) HexAddr = Addr; HexBuf[HexX++] = Hex; if (HexX == 0x10) { int H, Sum; Sum = (HexAddr&0xff) + ((HexAddr >> 8)&0xff) + HexX; fprintf(OutF, ":10%04X00", HexAddr); for (H = 0; H < HexX; H++) fprintf(OutF, "%02X", HexBuf[H]), Sum += HexBuf[H]; fprintf(OutF, "%02X\n", (-Sum)&0xff); HexX = 0; }}void CloseHex(void) { EndHex(); fprintf(OutF, ":00000001FF\n"); fclose(OutF);}void GenImage(char *Hex) { Image IP; RList R; FILE *FP; char *File; FP = 0, File = 0; OpenHex(Hex); for (IP = IHead, R = RHead; IP != 0; IP = IP->Next) { long Addr; if (IP->Obj != File) { if (FP != 0) fclose(FP), FP = 0; FP = fopen(IP->Obj, "rb+"); if (FP == 0) FATAL("Cannot open %s.", IP->Obj); } fseek(FP, IP->Loc, SEEK_SET); for (Addr = IP->Base; Addr < IP->Base + IP->Size; ) { if (R != 0 && R->PC < Addr) FATAL("Internal error (6)."); if (R != 0 && R->PC == Addr) { switch (R->Size) { case 1: fgetc(FP); PutHex(Addr++, (byte)(R->Val&0xff)); break; case 2: fgetc(FP), fgetc(FP); PutHex(Addr++, (byte)((R->Val >> 8)&0xff)), PutHex(Addr++, (byte)(R->Val&0xff)); break; default: FATAL("Internal error (7)."); } R = R->Next; } else { int Ch = fgetc(FP); if (Ch == EOF) FATAL("Internal error (8)."); PutHex(Addr++, (byte)(Ch&0xff)); } } if (IP->Next != 0 && IP->Base + IP->Size < IP->Next->Base) EndHex(); } CloseHex();}void Link(char *Hex) { int A; Active = 1, Phase = 2; SymInit(); SetSeg(); for (A = 0; A < Fs; A++) GetHead(FTab + A); for (Sym = NIL->Next[0]; Sym != NIL; Sym = Sym->Next[0]) if (!Sym->Defined) ERROR("Unresolved external: %s.", Sym->Name); CHECK(); InSeg = 1; SetFree(); for (A = 0; A < Fs; A++) FitSegs(FTab + A); PurgeFree(); InSeg = 0; CHECK(); SetImage(); for (A = 0; A < Fs; A++) { Gap G; FileBuf F = FTab + A; for (G = F->G; G < F->G + F->Gaps; G++) FitGap(G); } CHECK(); FreeBlocks(); InSeg = 1; RHead = 0; for (A = 0; A < Fs; A++) SetRelocs(FTab + A); InSeg = 0; CHECK(); GenImage(Hex);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -