(* Copyright 2016 Anton Krotov This file is part of Compiler. Compiler is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Compiler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Compiler. If not, see . *) MODULE X86; IMPORT UTILS, sys := SYSTEM, SCAN, ELF; CONST ADIM* = 5; lxPlus = 51; lxMinus = 52; lxMult = 53; lxSlash = 54; lxEQ = 71; lxNE = 72; lxLT = 73; lxGT = 74; lxLE = 75; lxGE = 76; TINTEGER = 1; TREAL = 2; TLONGREAL = 3; TCHAR = 4; TSET = 5; TBOOLEAN = 6; TVOID = 7; TNIL = 8; TCARD16 = 9; TSTRING = 10; TARRAY = 11; TRECORD = 12; TPOINTER = 13; TPROC = 14; stABS* = 1; stODD* = 2; stLEN* = 3; stLSL* = 4; stASR* = 5; stROR* = 6; stFLOOR* = 7; stFLT* = 8; stORD* = 9; stCHR* = 10; stLONG* = 11; stSHORT* = 12; stINC* = 13; stDEC* = 14; stINCL* = 15; stEXCL* = 16; stCOPY* = 17; stNEW* = 18; stASSERT* = 19; stPACK* = 20; stUNPK* = 21; stDISPOSE* = 22; stFABS* = 23; stINC1* = 24; stDEC1* = 25; stASSERT1* = 26; stUNPK1* = 27; stPACK1* = 28; stLSR* = 29; stLENGTH* = 30; sysMOVE* = 108; JMP* = 0E9X; CALL = 0E8X; JE = 84X; JNE = 85X; JLE = 8EX; JGE = 8DX; JG = 8FX; JL = 8CX; JCMD = 1; LCMD = 2; GCMD = 3; OCMD = 4; ECMD = 5; PUSHEAX = 6; PUSHECX = 7; PUSHEDX = 8; POPEAX = 9; POPECX = 10; POPEDX = 11; ICMP1 = 13; ICMP2 = 14; defcall = 0; stdcall = 1; cdecl = 2; winapi = 3; _rset* = 0; _inset* = 1; _saverec* = 2; _length* = 3; _checktype* = 4; _strcmp* = 5; _lstrcmp* = 6; _rstrcmp* = 7; _savearr* = 8; _newrec* = 9; _disprec* = 10; _arrayidx* = 11; _arrayrot* = 12; _assrt* = 13; _strcopy* = 14; _arrayidx1* = 15; _init* = 16; _close* = 17; _halt* = 18; ASSRT = 19; hInstance = 20; SELFNAME = 21; RTABLE = 22;LoadLibrary = 23; GetProcAddress = 24; Exports = 25; szSTART = 26; START = 27; szversion = 28; _floor = 29; HALT = 30; FREGS = 8; TYPE ASMLINE* = POINTER TO RECORD (UTILS.rITEM) cmd, clen, varadr, adr, tcmd, codeadr: INTEGER; short: BOOLEAN END; TFLT = ARRAY 2 OF INTEGER; TIDX* = ARRAY ADIM OF INTEGER; SECTIONNAME = ARRAY 8 OF CHAR; SECTION = RECORD name: SECTIONNAME; size, adr, sizealign, OAPfile, reserved6, reserved7, reserved8, attrflags: INTEGER END; HEADER = RECORD msdos: ARRAY 180 OF CHAR; typecomp, seccount: sys.CARD16; time, reserved1, reserved2: INTEGER; PEoptsize, infflags, PEfile, compver: sys.CARD16; codesize, datasize, initdatasize, startadr, codeadr, rdataadr, loadadr, secalign, filealign, oldestver, version, oldestverNT, reserved3, filesize, headersize, dllcrc: INTEGER; UI, reserved4: sys.CARD16; stksize, stkalloc, heapsize, heapalloc, reserved5, structcount: INTEGER; structs: ARRAY 16 OF RECORD adr, size: INTEGER END; sections: ARRAY 3 OF SECTION END; COFFHEADER = RECORD Machine: sys.CARD16; NumberOfSections: sys.CARD16; TimeDateStamp, PointerToSymbolTable, NumberOfSymbols: INTEGER; SizeOfOptionalHeader, Characteristics: sys.CARD16; text, data, bss: SECTION END; KOSHEADER = RECORD menuet01: ARRAY 8 OF CHAR; ver, start, size, mem, sp, param, path: INTEGER END; ETABLE = RECORD reserved1, time, reserved2, dllnameoffset, firstnum, adrcount, namecount, arradroffset, arrnameptroffset, arrnumoffset: INTEGER; arradr, arrnameptr: ARRAY 10000H OF INTEGER; arrnum: ARRAY 10000H OF sys.CARD16; text: ARRAY 1000000 OF CHAR; textlen, size: INTEGER END; RELOC = RECORD Page, Size: INTEGER; reloc: ARRAY 1024 OF sys.CARD16 END; VAR asmlist: UTILS.LIST; start: ASMLINE; dll, con, gui, kos, elf, obj: BOOLEAN; Lcount, reccount, topstk: INTEGER; recarray: ARRAY 2048 OF INTEGER; current*: ASMLINE; callstk: ARRAY 1024, 2 OF ASMLINE; OutFile: UTILS.STRING; Code: ARRAY 4000000 OF CHAR; ccount: INTEGER; Data: ARRAY 1000000 OF CHAR; dcount: INTEGER; Labels: ARRAY 200000 OF INTEGER; rdata: ARRAY 400H OF INTEGER; Header: HEADER; etable: ETABLE; ExecName: UTILS.STRING; LoadAdr: INTEGER; Reloc: ARRAY 200000 OF CHAR; rcount: INTEGER; RtlProc: ARRAY 20 OF INTEGER; OutFilePos: INTEGER; RelocSection: SECTION; fpu*: INTEGER; isfpu: BOOLEAN; maxfpu: INTEGER; fpucmd: ASMLINE; kosexp: ARRAY 65536 OF RECORD Name: SCAN.NODE; Adr, NameLabel: INTEGER END; kosexpcount: INTEGER; PROCEDURE AddRtlProc*(idx, proc: INTEGER); BEGIN RtlProc[idx] := proc END AddRtlProc; PROCEDURE IntToCard16(i: INTEGER): sys.CARD16; VAR w: sys.CARD16; BEGIN sys.GET(sys.ADR(i), w) RETURN w END IntToCard16; PROCEDURE CopyStr(VAR Dest: ARRAY OF CHAR; Source: ARRAY OF CHAR; VAR di: INTEGER; si: INTEGER); BEGIN DEC(di); REPEAT INC(di); Dest[di] := Source[si]; INC(si) UNTIL Dest[di] = 0X END CopyStr; PROCEDURE exch(VAR a, b: INTEGER); VAR c: INTEGER; BEGIN c := a; a := b; b := c END exch; PROCEDURE Sort(VAR NamePtr, Adr: ARRAY OF INTEGER; Text: ARRAY OF CHAR; LB, RB: INTEGER); VAR L, R: INTEGER; PROCEDURE strle(s1, s2: INTEGER): BOOLEAN; VAR S1, S2: ARRAY 256 OF CHAR; i: INTEGER; BEGIN i := 0; CopyStr(S1, Text, i, s1); i := 0; CopyStr(S2, Text, i, s2) RETURN S1 <= S2 END strle; BEGIN IF LB < RB THEN L := LB; R := RB; REPEAT WHILE (L < RB) & strle(NamePtr[L], NamePtr[LB]) DO INC(L) END; WHILE (R > LB) & strle(NamePtr[LB], NamePtr[R]) DO DEC(R) END; IF L < R THEN exch(NamePtr[L], NamePtr[R]); exch(Adr[L], Adr[R]) END UNTIL L >= R; IF R > LB THEN exch(NamePtr[LB], NamePtr[R]); exch(Adr[LB], Adr[R]); Sort(NamePtr, Adr, Text, LB, R - 1) END; Sort(NamePtr, Adr, Text, R + 1, RB) END END Sort; PROCEDURE PackExport(Name: ARRAY OF CHAR); VAR i: INTEGER; BEGIN Sort(etable.arrnameptr, etable.arradr, etable.text, 0, etable.namecount - 1); FOR i := 0 TO etable.namecount - 1 DO etable.arrnum[i] := IntToCard16(i) END; etable.size := 40 + etable.adrcount * 4 + etable.namecount * 6; etable.arradroffset := 40; etable.arrnameptroffset := 40 + etable.adrcount * 4; etable.arrnumoffset := etable.arrnameptroffset + etable.namecount * 4; etable.dllnameoffset := etable.size + etable.textlen; CopyStr(etable.text, Name, etable.textlen, 0); INC(etable.textlen); FOR i := 0 TO etable.namecount - 1 DO etable.arrnameptr[i] := etable.arrnameptr[i] + etable.size END; etable.size := etable.size + etable.textlen END PackExport; PROCEDURE ProcExport*(Number: INTEGER; Name: SCAN.NODE; NameLabel: INTEGER); BEGIN IF dll THEN etable.arradr[etable.adrcount] := Number; INC(etable.adrcount); etable.arrnameptr[etable.namecount] := etable.textlen; INC(etable.namecount); CopyStr(etable.text, Name.Name, etable.textlen, 0); INC(etable.textlen) ELSIF obj THEN kosexp[kosexpcount].Name := Name; kosexp[kosexpcount].Adr := Number; kosexp[kosexpcount].NameLabel := NameLabel; INC(kosexpcount) END END ProcExport; PROCEDURE Err(code: INTEGER); BEGIN CASE code OF |1: UTILS.ErrMsg(67); UTILS.OutString(OutFile) |2: UTILS.ErrMsg(69); UTILS.OutString(OutFile) ELSE END; UTILS.Ln; UTILS.HALT(1) END Err; PROCEDURE Align*(n, m: INTEGER): INTEGER; RETURN n + (m - n MOD m) MOD m END Align; PROCEDURE PutReloc(R: RELOC); VAR i: INTEGER; BEGIN sys.PUT(sys.ADR(Reloc[rcount]), R.Page); INC(rcount, 4); sys.PUT(sys.ADR(Reloc[rcount]), R.Size); INC(rcount, 4); FOR i := 0 TO ASR(R.Size - 8, 1) - 1 DO sys.PUT(sys.ADR(Reloc[rcount]), R.reloc[i]); INC(rcount, 2) END END PutReloc; PROCEDURE InitArray(VAR adr: INTEGER; chars: UTILS.STRING); VAR i, x, n: INTEGER; BEGIN n := LEN(chars) - 1; i := 0; WHILE (i < n) & (chars[i] # 0X) DO x := SCAN.hex(chars[i]) * 16 + SCAN.hex(chars[i + 1]); sys.PUT(adr, CHR(x)); INC(adr); INC(i, 2) END END InitArray; PROCEDURE WriteF(F, A, N: INTEGER); BEGIN IF UTILS.Write(F, A, N) # N THEN Err(2) END END WriteF; PROCEDURE Write(A, N: INTEGER); BEGIN sys.MOVE(A, OutFilePos, N); OutFilePos := OutFilePos + N END Write; PROCEDURE Fill(n: INTEGER; c: CHAR); VAR i: INTEGER; BEGIN FOR i := 1 TO n DO Write(sys.ADR(c), 1) END END Fill; PROCEDURE SetSection(VAR Section: SECTION; name: SECTIONNAME; size, adr, sizealign, OAPfile, attrflags: INTEGER); BEGIN Section.name := name; Section.size := size; Section.adr := adr; Section.sizealign := sizealign; Section.OAPfile := OAPfile; Section.attrflags := attrflags; END SetSection; PROCEDURE WritePE(FName: ARRAY OF CHAR; stksize, codesize, datasize, rdatasize, gsize: INTEGER); CONST textattr = 60000020H; rdataattr = 40000040H; dataattr = 0C0000040H; relocattr = 42000040H; VAR i, F, adr, acodesize, compver, version, stkalloc, heapsize, heapalloc, filesize, filebuf: INTEGER; cur: ASMLINE; BEGIN compver := 0; version := 0; stkalloc := stksize; heapsize := 100000H; heapalloc := 100000H; acodesize := Align(codesize, 1000H) + 1000H; adr := sys.ADR(rdata); filesize := acodesize + Align(rdatasize, 1000H) + Align(datasize, 1000H) + Align(rcount, 1000H); InitArray(adr, "5000000040000000000000003400000000000000000000006200000000000000"); InitArray(adr, "0000000000000000000000000000000000000000500000004000000000000000"); InitArray(adr, "A4014C6F61644C6962726172794100001F0147657450726F6341646472657373"); InitArray(adr, "00006B65726E656C33322E646C6C0000"); rdata[ 0] := acodesize + 50H; rdata[ 1] := acodesize + 40H; rdata[ 3] := acodesize + 34H; rdata[ 6] := acodesize + 62H; rdata[ 7] := acodesize; rdata[13] := acodesize + 50H; rdata[14] := acodesize + 40H; adr := sys.ADR(Header.msdos); InitArray(adr, "4D5A90000300000004000000FFFF0000B8000000000000004000000000000000"); InitArray(adr, "00000000000000000000000000000000000000000000000000000000B0000000"); InitArray(adr, "0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F"); InitArray(adr, "742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000"); InitArray(adr, "5DCF9F8719AEF1D419AEF1D419AEF1D497B1E2D413AEF1D4E58EE3D418AEF1D4"); InitArray(adr, "5269636819AEF1D4000000000000000050450000"); Header.typecomp := IntToCard16(014CH); IF dll THEN Header.seccount := IntToCard16(0004H); Header.infflags := IntToCard16(210EH) ELSE Header.seccount := IntToCard16(0003H); Header.infflags := IntToCard16(010FH) END; Header.time := UTILS.Date; Header.PEoptsize := IntToCard16(00E0H); Header.PEfile := IntToCard16(010BH); Header.compver := IntToCard16(compver); Header.codesize := Align(codesize, 200H); Header.datasize := Align(datasize + gsize, 200H) + Align(rdatasize, 200H) + Align(rcount, 200H); Header.startadr := 1000H; Header.codeadr := 1000H; Header.rdataadr := Header.codeadr + Align(codesize, 1000H); Header.loadadr := LoadAdr; Header.secalign := 1000H; Header.filealign := 0200H; Header.oldestver := 0004H; Header.version := version; Header.oldestverNT := 0004H; Header.filesize := Align(codesize, 1000H) + Align(datasize + gsize, 1000H) + Align(rdatasize, 1000H) + Align(rcount, 1000H) + 1000H; Header.headersize := 0400H; Header.UI := IntToCard16(ORD(con) + 2); Header.stksize := stksize; Header.stkalloc := stkalloc; Header.heapsize := heapsize; Header.heapalloc := heapalloc; Header.structcount := 10H; IF dll THEN Header.structs[0].adr := Header.rdataadr + 0DAH; Header.structs[0].size := etable.size END; Header.structs[1].adr := Header.rdataadr + 0CH; Header.structs[1].size := 28H; Header.structs[12].adr := Header.rdataadr; Header.structs[12].size := 0CH; SetSection(Header.sections[0], ".text", codesize, 1000H, Align(codesize, 200H), 400H, textattr); SetSection(Header.sections[1], ".rdata", rdatasize, Align(codesize, 1000H) + 1000H, Align(rdatasize, 200H), Align(codesize, 200H) + 400H, rdataattr); SetSection(Header.sections[2], ".data", datasize + gsize, Align(codesize, 1000H) + Align(rdatasize, 1000H) + 1000H, Align(datasize, 200H), Align(codesize, 200H) + Align(rdatasize, 200H) + 400H, dataattr); IF dll THEN SetSection(RelocSection, ".reloc", rcount, Header.sections[2].adr + Align(datasize + gsize, 1000H), Align(rcount, 200H), Header.sections[2].OAPfile + Align(datasize, 200H), relocattr); Header.structs[5].adr := RelocSection.adr; Header.structs[5].size := rcount END; F := UTILS.CreateF(FName); IF F = 0 THEN Err(1) END; OutFilePos := UTILS.GetMem(filesize); filebuf := OutFilePos; UTILS.MemErr(OutFilePos = 0); Write(sys.ADR(Header), sys.SIZE(HEADER)); IF dll THEN Write(sys.ADR(RelocSection), sys.SIZE(SECTION)); Fill(Align(sys.SIZE(HEADER) + sys.SIZE(SECTION), 200H) - (sys.SIZE(HEADER) + sys.SIZE(SECTION)), 0X) ELSE Fill(Align(sys.SIZE(HEADER), 200H) - sys.SIZE(HEADER), 0X) END; cur := asmlist.First(ASMLINE); WHILE cur # NIL DO Write(sys.ADR(Code[cur.cmd]), cur.clen); cur := cur.Next(ASMLINE) END; Fill(Align(codesize, 200H) - codesize, 0X); Write(sys.ADR(rdata), 0DAH); IF dll THEN etable.time := Header.time; Write(sys.ADR(etable), 40); Write(sys.ADR(etable.arradr), etable.adrcount * 4); Write(sys.ADR(etable.arrnameptr), etable.namecount * 4); Write(sys.ADR(etable.arrnum), etable.namecount * 2); Write(sys.ADR(etable.text), etable.textlen) END; Fill(Align(rdatasize, 200H) - rdatasize, 0X); Write(sys.ADR(Data), datasize); Fill(Align(datasize, 200H) - datasize, 0X); IF dll THEN Write(sys.ADR(Reloc), rcount); Fill(Align(rcount, 200H) - rcount, 0X) END; WriteF(F, filebuf, OutFilePos - filebuf); UTILS.CloseF(F) END WritePE; PROCEDURE New; VAR nov: ASMLINE; BEGIN NEW(nov); UTILS.MemErr(nov = NIL); nov.cmd := ccount; UTILS.Insert(asmlist, nov, current); current := current.Next(ASMLINE) END New; PROCEDURE Empty(varadr: INTEGER); BEGIN New; current.clen := 0; current.tcmd := ECMD; current.varadr := varadr END Empty; PROCEDURE OutByte(byte: INTEGER); BEGIN New; current.clen := 1; Code[ccount] := CHR(byte); INC(ccount) END OutByte; PROCEDURE OutInt(int: INTEGER); BEGIN New; current.clen := 4; sys.PUT(sys.ADR(Code[ccount]), int); INC(ccount, 4) END OutInt; PROCEDURE PushEAX; BEGIN OutByte(50H); current.tcmd := PUSHEAX END PushEAX; PROCEDURE PushECX; BEGIN OutByte(51H); current.tcmd := PUSHECX END PushECX; PROCEDURE PushEDX; BEGIN OutByte(52H); current.tcmd := PUSHEDX END PushEDX; PROCEDURE PopEAX; BEGIN OutByte(58H); current.tcmd := POPEAX END PopEAX; PROCEDURE PopECX; BEGIN OutByte(59H); current.tcmd := POPECX END PopECX; PROCEDURE PopEDX; BEGIN OutByte(5AH); current.tcmd := POPEDX END PopEDX; PROCEDURE OutCode(cmd: UTILS.STRING); VAR a, b: INTEGER; BEGIN New; a := sys.ADR(Code[ccount]); b := a; InitArray(a, cmd); ccount := a - b + ccount; current.clen := a - b END OutCode; PROCEDURE Del*(last: ASMLINE); BEGIN last.Next := current.Next; IF current = asmlist.Last THEN asmlist.Last := last END; current := last END Del; PROCEDURE NewLabel*(): INTEGER; BEGIN INC(Lcount) RETURN Lcount END NewLabel; PROCEDURE PushCall*(asmline: ASMLINE); BEGIN New; callstk[topstk][0] := asmline; callstk[topstk][1] := current; INC(topstk) END PushCall; PROCEDURE Param*; BEGIN current := callstk[topstk - 1][0] END Param; PROCEDURE EndCall*; BEGIN current := callstk[topstk - 1][1]; DEC(topstk) END EndCall; PROCEDURE Init*(UI: INTEGER); VAR nov: ASMLINE; BEGIN dcount := 4; dll := UI = 1; gui := UI = 2; con := UI = 3; kos := UI = 4; elf := UI = 5; obj := UI = 6; Lcount := HALT; asmlist := UTILS.CreateList(); NEW(nov); UTILS.MemErr(nov = NIL); UTILS.Push(asmlist, nov); current := nov; END Init; PROCEDURE datastr(str: UTILS.STRING); VAR i, n: INTEGER; BEGIN i := 0; n := LEN(str); WHILE (i < n) & (str[i] # 0X) DO Data[dcount] := str[i]; INC(dcount); INC(i) END; Data[dcount] := 0X; INC(dcount) END datastr; PROCEDURE dataint(n: INTEGER); BEGIN sys.PUT(sys.ADR(Data[dcount]), n); INC(dcount, 4) END dataint; PROCEDURE jmp*(jamp: CHAR; label: INTEGER); VAR n: INTEGER; BEGIN New; CASE jamp OF |JMP, CALL: n := 5 |JE, JLE, JGE, JG, JL, JNE: Code[ccount] := 0FX; INC(ccount); n := 6 ELSE END; current.clen := n; Code[ccount] := jamp; INC(ccount); current.codeadr := sys.ADR(Code[ccount]); current.varadr := sys.ADR(Labels[label]); current.tcmd := JCMD; current.short := TRUE; INC(ccount, 4) END jmp; PROCEDURE jmplong(jamp: CHAR; label: INTEGER); BEGIN jmp(jamp, label); current.short := FALSE END jmplong; PROCEDURE Label*(label: INTEGER); BEGIN New; current.varadr := sys.ADR(Labels[label]); current.tcmd := LCMD END Label; PROCEDURE CmdN(Number: INTEGER); BEGIN New; current.clen := 4; current.codeadr := sys.ADR(Code[ccount]); current.varadr := sys.ADR(Labels[Number]); current.tcmd := OCMD; INC(ccount, 4) END CmdN; PROCEDURE IntByte(bytecode, intcode: UTILS.STRING; n: INTEGER); BEGIN IF (n <= 127) & (n >= -128) THEN OutCode(bytecode); OutByte(n) ELSE OutCode(intcode); OutInt(n) END END IntByte; PROCEDURE DropFpu*(long: BOOLEAN); BEGIN IF long THEN OutCode("83EC08DD1C24") ELSE OutCode("83EC04D91C24") END; DEC(fpu) END DropFpu; PROCEDURE AfterRet(func, float: BOOLEAN; callconv, parsize: INTEGER); BEGIN IF callconv = cdecl THEN OutCode("81C4"); OutInt(parsize) END; IF func THEN IF float THEN OutCode("83EC08DD1C24") ELSE PushEAX END END END AfterRet; PROCEDURE FpuSave(local: INTEGER); VAR i: INTEGER; BEGIN IF fpu > maxfpu THEN maxfpu := fpu END; FOR i := 1 TO fpu DO IntByte("DD5D", "DD9D", -local - i * 8) END END FpuSave; PROCEDURE Incfpu; BEGIN IF fpu >= FREGS THEN UTILS.ErrMsgPos(SCAN.coord.line, SCAN.coord.col, 97); UTILS.HALT(1) END; INC(fpu); isfpu := TRUE END Incfpu; PROCEDURE FpuLoad(local: INTEGER; float: BOOLEAN); VAR i: INTEGER; BEGIN FOR i := fpu TO 1 BY -1 DO IntByte("DD45", "DD85", -local - i * 8) END; IF float THEN Incfpu; OutCode("DD042483C408") END END FpuLoad; PROCEDURE Call*(proc: INTEGER; func, float: BOOLEAN; callconv, ccall, bases, level, parsize, local: INTEGER); VAR i: INTEGER; BEGIN IF ccall # 0 THEN FOR i := level TO level - bases + ORD(ccall = 1) + 1 BY -1 DO IntByte("FF75", "FFB5", 4 * i + 4) END; IF ccall = 1 THEN OutByte(55H) END END; FpuSave(local); jmplong(CALL, proc); AfterRet(func, float, callconv, parsize); FpuLoad(local, func & float) END Call; PROCEDURE CallRTL(Proc: INTEGER); BEGIN New; current.clen := 5; Code[ccount] := CALL; INC(ccount); current.codeadr := sys.ADR(Code[ccount]); current.varadr := sys.ADR(RtlProc[Proc]); current.tcmd := JCMD; INC(ccount, 4) END CallRTL; PROCEDURE PushInt*(n: INTEGER); BEGIN OutByte(68H); CmdN(n) END PushInt; PROCEDURE Prolog*(exename: UTILS.STRING); BEGIN ExecName := exename; Labels[hInstance] := -dcount; dataint(0); Labels[SELFNAME] := -dcount; datastr(exename); Label(START); IF dll THEN OutCode("558BEC837D0C007507"); CallRTL(_close); OutCode("EB06837D0C017409B801000000C9C20C00") ELSIF obj THEN OutCode("558BEC") END; start := asmlist.Last(ASMLINE) END Prolog; PROCEDURE AddRec*(base: INTEGER); BEGIN INC(reccount); recarray[reccount] := base END AddRec; PROCEDURE CmpOpt(inv: BOOLEAN): INTEGER; VAR cur: ASMLINE; c: INTEGER; BEGIN c := ORD(Code[current.Prev.Prev(ASMLINE).cmd]); IF inv THEN IF ODD(c) THEN DEC(c) ELSE INC(c) END END; cur := current; REPEAT cur.tcmd := 0; cur.clen := 0; cur := cur.Prev(ASMLINE) UNTIL cur.tcmd = ICMP1; cur.tcmd := 0; cur.clen := 0 RETURN c - 16 END CmpOpt; PROCEDURE ifwh*(L: INTEGER); VAR c: INTEGER; BEGIN IF current.Prev(ASMLINE).tcmd = ICMP2 THEN c := CmpOpt(TRUE); OutCode("5A583BC2"); jmp(CHR(c), L) ELSE PopECX; OutCode("85C9"); jmp(JE, L) END END ifwh; PROCEDURE PushConst*(Number: INTEGER); BEGIN IntByte("6A", "68", Number); current.Prev(ASMLINE).varadr := Number END PushConst; PROCEDURE IfWhile*(L: INTEGER; orop: BOOLEAN); VAR c, L1: INTEGER; BEGIN L1 := NewLabel(); IF current.Prev(ASMLINE).tcmd = ICMP2 THEN c := CmpOpt(orop); OutCode("5A583BC2"); jmp(CHR(c), L1); PushConst(ORD(orop)) ELSE PopECX; OutCode("85C9"); IF orop THEN jmp(JE, L1) ELSE jmp(JNE, L1) END; PushECX END; jmp(JMP, L); Label(L1) END IfWhile; PROCEDURE newrec*; BEGIN CallRTL(_newrec) END newrec; PROCEDURE disprec*; BEGIN CallRTL(_disprec) END disprec; PROCEDURE String*(Number, Len: INTEGER; str: UTILS.STRING); BEGIN Labels[Number] := -dcount; IF Len > 1 THEN datastr(str) ELSIF Len = 1 THEN dataint(ORD(str[0])) ELSE dataint(0) END END String; PROCEDURE InsertFpuInit; VAR t: ASMLINE; BEGIN IF isfpu THEN t := current; current := fpucmd; IF maxfpu > 0 THEN OutCode("83EC"); OutByte(maxfpu * 8) END; OutCode("DBE3"); current := t END END InsertFpuInit; PROCEDURE ProcBeg*(Number, Local: INTEGER; Module: BOOLEAN); VAR i: INTEGER; BEGIN IF Module THEN OutCode("EB0C"); Label(Number + 3); PushInt(Number + 2); jmplong(JMP, HALT); Label(Number + 1) ELSE Label(Number) END; OutCode("558BEC"); IF Local > 12 THEN IntByte("83EC", "81EC", Local); OutCode("8BD733C08BFCB9"); OutInt(ASR(Local, 2)); OutCode("9CFCF3AB8BFA9D") ELSE FOR i := 4 TO Local BY 4 DO OutCode("6A00") END END; fpucmd := current; fpu := 0; maxfpu := 0; isfpu := FALSE END ProcBeg; PROCEDURE Leave*; BEGIN OutByte(0C9H); InsertFpuInit END Leave; PROCEDURE ProcEnd*(Number, Param: INTEGER; func, float: BOOLEAN); BEGIN IF func & ~float THEN PopEAX END; OutByte(0C9H); IF Param = 0 THEN OutByte(0C3H) ELSE OutByte(0C2H); OutByte(Param MOD 256); OutByte(ASR(Param, 8)) END; InsertFpuInit END ProcEnd; PROCEDURE Module*(Name: UTILS.STRING; Number: INTEGER); BEGIN String(Number + 2, LENGTH(Name), Name); jmplong(JMP, Number + 1) END Module; PROCEDURE Asm*(s: UTILS.STRING); BEGIN OutCode(s) END Asm; PROCEDURE GlobalAdr*(offset: INTEGER); BEGIN OutByte(0BAH); OutInt(offset); current.codeadr := sys.ADR(Code[ccount - 4]); current.tcmd := GCMD; PushEDX END GlobalAdr; PROCEDURE Mono*(Number: INTEGER); BEGIN PopEDX; PushInt(Number) END Mono; PROCEDURE StrMono*; BEGIN PopEDX; OutCode("6A02"); PushEDX END StrMono; PROCEDURE Not*; BEGIN PopECX; OutCode("85C90F94C1"); PushECX END Not; PROCEDURE NegSet*; BEGIN OutCode("F71424") END NegSet; PROCEDURE Int*(Op: INTEGER); BEGIN PopEDX; CASE Op OF |lxPlus: OutCode("011424") |lxMinus: OutCode("291424") |lxMult: OutCode("58F7EA"); PushEAX ELSE END END Int; PROCEDURE Set*(Op: INTEGER); BEGIN PopEDX; OutByte(58H); CASE Op OF |lxPlus: OutByte(0BH) |lxMinus: OutCode("F7D223") |lxMult: OutByte(23H) |lxSlash: OutByte(33H) ELSE END; OutByte(0C2H); PushEAX END Set; PROCEDURE Setfpu*(newfpu: INTEGER); BEGIN fpu := newfpu END Setfpu; PROCEDURE PushFlt*(x: LONGREAL); VAR f: TFLT; L: INTEGER; BEGIN sys.PUT(sys.ADR(f), x); Incfpu; IF x = 0.0D0 THEN OutCode("D9EE") ELSIF x = 1.0D0 THEN OutCode("D9E8") ELSE L := NewLabel(); Labels[L] := -dcount; dataint(f[0]); dataint(f[1]); OutByte(0BAH); CmdN(L); OutCode("DD02") END END PushFlt; PROCEDURE farith*(op: INTEGER); VAR n: INTEGER; BEGIN OutByte(0DEH); CASE op OF |lxPlus: n := 0C1H |lxMinus: n := 0E9H |lxMult: n := 0C9H |lxSlash: n := 0F9H ELSE END; OutByte(n); DEC(fpu) END farith; PROCEDURE fcmp*(Op: INTEGER); VAR n: INTEGER; BEGIN OutCode("33C9DED9DFE09E0F"); CASE Op OF |lxEQ: n := 94H |lxNE: n := 95H |lxLT: n := 97H |lxGT: n := 92H |lxLE: n := 93H |lxGE: n := 96H ELSE END; DEC(fpu, 2); OutByte(n); OutByte(0C1H); PushECX END fcmp; PROCEDURE fneg*; BEGIN OutCode("D9E0") END fneg; PROCEDURE OnError*(n: INTEGER); BEGIN OutByte(68H); OutInt(LSL(UTILS.Line, 4) + n); jmplong(JMP, UTILS.Unit + 3) END OnError; PROCEDURE idivmod*(opmod: BOOLEAN); BEGIN PopECX; IF opmod THEN OutCode("58E32E538BD833D9C1FB1F8BD0C1FA1F83F9FF750C3D0000008075055B6A00EB1AF7F985DB740685D2740203D15B52EB0A") ELSE OutCode("58E32C538BD833D9C1FB1F8BD0C1FA1F83F9FF750B3D0000008075045B50EB19F7F985DB740585D27401485B50EB0A") END; OnError(8) END idivmod; PROCEDURE rset*; BEGIN CallRTL(_rset); PushEAX END rset; PROCEDURE inset*; BEGIN CallRTL(_inset); PushEAX END inset; PROCEDURE Dup*; BEGIN PopEDX; PushEDX; PushEDX END Dup; PROCEDURE Inclusion*(Op: INTEGER); BEGIN PopEDX; PopEAX; IF Op = lxLE THEN PushEDX ELSE PushEAX END; OutCode("0BC25933C8E3046A00EB026A01") END Inclusion; PROCEDURE NegInt*; BEGIN OutCode("F71C24") END NegInt; PROCEDURE CmpInt*(Op: INTEGER); VAR n: INTEGER; BEGIN OutCode("33C95A583BC20F"); current.tcmd := ICMP1; CASE Op OF |lxEQ: n := 94H |lxNE: n := 95H |lxLT: n := 9CH |lxGT: n := 9FH |lxLE: n := 9EH |lxGE: n := 9DH ELSE END; OutByte(n); OutByte(0C1H); current.tcmd := ICMP2; PushECX; END CmpInt; PROCEDURE CallVar*(func, float: BOOLEAN; callconv, parsize, local: INTEGER); BEGIN PopEDX; OutCode("8B1285D2750A"); OnError(2); FpuSave(local); OutCode("FFD2"); AfterRet(func, float, callconv, parsize); FpuLoad(local, func & float) END CallVar; PROCEDURE LocalAdr*(offset, bases: INTEGER); BEGIN IF bases = 0 THEN Empty(offset); OutCode("8BD5") ELSE IntByte("8B55", "8B95", 4 * bases + 4) END; IntByte("83C2", "81C2", offset); PushEDX; IF bases = 0 THEN Empty(offset) END END LocalAdr; PROCEDURE Field*(offset: INTEGER); BEGIN IF offset # 0 THEN IntByte("830424", "810424", offset) END END Field; PROCEDURE DerefType*(n: INTEGER); BEGIN IntByte("8B5424", "8B9424", n); OutCode("FF72FC") END DerefType; PROCEDURE Guard*(T: INTEGER; Check: BOOLEAN); BEGIN IF Check THEN PopEAX; OutCode("85C074"); IF T <= 127 THEN OutByte(9) ELSE OutByte(12) END; PushEAX END; PushConst(T); PushEAX; CallRTL(_checktype); IF Check THEN PushEAX ELSE OutCode("85C0750A"); OnError(3) END END Guard; PROCEDURE StProc*(proc: INTEGER); BEGIN CASE proc OF |stINC: PopEDX; OutCode("590111") |stDEC: PopEDX; OutCode("592911") |stINC1: PopEDX; OutCode("FF02") |stDEC1: PopEDX; OutCode("FF0A") |stINCL: PopEDX; OutCode("580910") |stEXCL: PopEDX; OutCode("582110") |stPACK: OutCode("DB04245A5ADD02D9FDDD1A"); isfpu := TRUE |stPACK1: OutCode("DB04245A5AD902D9FDD91A"); isfpu := TRUE |stUNPK: PopEDX; OutCode("59DD01D9F4DD19DB1A"); isfpu := TRUE |stUNPK1: PopEDX; OutCode("59D901D9F4D919DB1A"); isfpu := TRUE |stCOPY: CallRTL(_strcopy) |sysMOVE: CallRTL(_savearr) ELSE END END StProc; PROCEDURE Assert*(proc, assrt: INTEGER); BEGIN PopEDX; OutCode("85D2751368"); OutInt(UTILS.Line * 16 + 1); PushInt(UTILS.Unit + 2); IF proc = stASSERT THEN OutCode("6A026A") ELSE OutCode("6A016A") END; OutByte(assrt); jmplong(JMP, ASSRT) END Assert; PROCEDURE StFunc*(func: INTEGER); BEGIN CASE func OF |stABS: PopEDX; OutCode("85D27D02F7DA"); PushEDX |stFABS: OutCode("D9E1") |stFLT: OutCode("DB0424"); PopEAX; Incfpu; |stFLOOR: jmplong(CALL, _floor); PushEAX; DEC(fpu) |stODD: OutCode("83242401") |stROR: PopECX; OutCode("58D3C8"); PushEAX |stASR: PopECX; OutCode("58D3F8"); PushEAX |stLSL: PopECX; OutCode("58D3E0"); PushEAX |stLSR: PopECX; OutCode("58D3E8"); PushEAX |stORD: PopEDX; OutCode("85D274036A015A"); PushEDX |stLENGTH: CallRTL(_length); PushEAX ELSE END END StFunc; PROCEDURE Load*(T: INTEGER); VAR lastcmd: ASMLINE; offset: INTEGER; PROCEDURE del; BEGIN lastcmd.tcmd := 0; offset := lastcmd.varadr; lastcmd := lastcmd.Prev(ASMLINE); WHILE lastcmd.tcmd # ECMD DO lastcmd.clen := 0; lastcmd.tcmd := 0; lastcmd := lastcmd.Prev(ASMLINE) END; lastcmd.tcmd := 0 END del; BEGIN lastcmd := current; CASE T OF |TINTEGER, TSET, TPOINTER, TPROC: IF lastcmd.tcmd = ECMD THEN del; IntByte("8B55", "8B95", offset); PushEDX ELSE PopEDX; OutCode("FF32") END |TCHAR, TBOOLEAN: IF lastcmd.tcmd = ECMD THEN del; OutCode("33D28A"); IntByte("55", "95", offset); PushEDX ELSE PopEDX; OutCode("33C98A0A"); PushECX END |TLONGREAL: IF lastcmd.tcmd = ECMD THEN del; IntByte("DD45", "DD85", offset) ELSE PopEDX; OutCode("DD02") END; Incfpu |TREAL: IF lastcmd.tcmd = ECMD THEN del; IntByte("D945", "D985", offset) ELSE PopEDX; OutCode("D902") END; Incfpu |TCARD16: IF lastcmd.tcmd = ECMD THEN del; OutCode("33D2668B"); IntByte("55", "95", offset); PushEDX ELSE PopEDX; OutCode("33C9668B0A"); PushECX END ELSE END END Load; PROCEDURE Save*(T: INTEGER); BEGIN CASE T OF |TINTEGER, TSET, TPOINTER, TPROC: PopEDX; OutCode("588910") |TCHAR, TSTRING, TBOOLEAN: PopEDX; OutCode("588810") |TCARD16: PopEDX; OutCode("58668910") |TLONGREAL: PopEDX; OutCode("DD1A"); DEC(fpu) |TREAL: PopEDX; OutCode("D91A"); DEC(fpu) |TRECORD: CallRTL(_saverec); OutCode("85C0750A"); OnError(4) |TARRAY: CallRTL(_savearr) ELSE END END Save; PROCEDURE OpenArray*(A: TIDX; n: INTEGER); VAR i: INTEGER; BEGIN PopEDX; FOR i := n - 1 TO 0 BY -1 DO PushConst(A[i]) END; PushEDX END OpenArray; PROCEDURE OpenIdx*(n: INTEGER); BEGIN OutByte(54H); IF n > 1 THEN PushConst(n); CallRTL(_arrayidx) ELSE CallRTL(_arrayidx1) END; PopEDX; OutCode("85D2750A"); OnError(5); PushEDX; END OpenIdx; PROCEDURE FixIdx*(len, size: INTEGER); BEGIN PopEDX; IntByte("5983FA", "5981FA", len); OutCode("720A"); OnError(5); IF size > 1 THEN IntByte("6BD2", "69D2", size) END; OutCode("03D1"); PushEDX END FixIdx; PROCEDURE Idx*; BEGIN PopEDX; PopECX; OutCode("03D1"); PushEDX END Idx; PROCEDURE DupLoadCheck*; BEGIN PopEDX; OutCode("528B125285D2750A"); OnError(6) END DupLoadCheck; PROCEDURE DupLoad*; BEGIN PopEDX; OutCode("528B12"); PushEDX; END DupLoad; PROCEDURE CheckNIL*; BEGIN PopEDX; OutCode("85D2750A"); OnError(6); PushEDX; END CheckNIL; PROCEDURE ExtArray*(A: TIDX; n, m: INTEGER); VAR i: INTEGER; BEGIN FOR i := n - 1 TO 0 BY -1 DO PushConst(A[i]) END; OutByte(54H); PushConst(n); PushConst(m); CallRTL(_arrayrot) END ExtArray; PROCEDURE ADR*(dim: INTEGER); BEGIN IF dim > 0 THEN PopEDX; OutCode("83C4"); OutByte(dim * 4); PushEDX END END ADR; PROCEDURE Len*(dim: INTEGER); BEGIN PopEDX; IF dim < 0 THEN PushConst(-dim) ELSIF dim > 1 THEN PopEDX; OutCode("83C4"); OutByte((dim - 1) * 4); PushEDX END END Len; PROCEDURE For*(inc: BOOLEAN; VAR LBeg, LEnd: INTEGER); BEGIN LEnd := NewLabel(); LBeg := NewLabel(); Label(LBeg); OutCode("8B14248B4424043910"); IF inc THEN jmp(JG, LEnd) ELSE jmp(JL, LEnd) END END For; PROCEDURE NextFor*(step, LBeg, LEnd: INTEGER); BEGIN OutCode("8B542404"); IF step = 1 THEN OutCode("FF02") ELSIF step = -1 THEN OutCode("FF0A") ELSE IntByte("8302", "8102", step) END; jmp(JMP, LBeg); Label(LEnd); OutCode("83C408") END NextFor; PROCEDURE CaseLabel*(a, b, LBeg: INTEGER); VAR L: INTEGER; BEGIN L := NewLabel(); IntByte("83FA", "81FA", a); IF a = b THEN jmp(JNE, L) ELSE jmp(JL, L); IntByte("83FA", "81FA", b); jmp(JG, L) END; jmp(JMP, LBeg); Label(L) END CaseLabel; PROCEDURE Drop*; BEGIN PopEDX END Drop; PROCEDURE strcmp*(Op, LR: INTEGER); BEGIN CASE Op OF |lxEQ: PushConst(0) |lxNE: PushConst(1) |lxLT: PushConst(2) |lxGT: PushConst(3) |lxLE: PushConst(4) |lxGE: PushConst(5) ELSE END; CASE LR OF |-1: CallRTL(_lstrcmp) | 0: CallRTL(_strcmp) | 1: CallRTL(_rstrcmp) ELSE END; PushEAX END strcmp; PROCEDURE Optimization; VAR cur: ASMLINE; flag: BOOLEAN; BEGIN cur := asmlist.First(ASMLINE); WHILE cur # NIL DO flag := FALSE; CASE cur.tcmd OF |PUSHEAX: flag := cur.Next(ASMLINE).tcmd = POPEAX |PUSHECX: flag := cur.Next(ASMLINE).tcmd = POPECX |PUSHEDX: flag := cur.Next(ASMLINE).tcmd = POPEDX ELSE END; IF flag THEN cur.clen := 0; cur.tcmd := 0; cur := cur.Next(ASMLINE); cur.clen := 0; cur.tcmd := 0 END; cur := cur.Next(ASMLINE) END END Optimization; PROCEDURE WriteKOS(FName: ARRAY OF CHAR; stk, size, datasize, gsize: INTEGER; obj: BOOLEAN); CONST strsize = 2048; VAR Header: KOSHEADER; F, i, filesize, filebuf, a, sec, adr, size2: INTEGER; cur: ASMLINE; Coff: COFFHEADER; sym: ARRAY 18 * 4 OF CHAR; FileName: UTILS.STRING; BEGIN F := UTILS.CreateF(FName); IF F <= 0 THEN Err(1) END; OutFilePos := UTILS.GetMem(Align(size, 4) + datasize + 1000H); filebuf := OutFilePos; UTILS.MemErr(OutFilePos = 0); IF ~obj THEN Header.menuet01 := "MENUET01"; Header.ver := 1; Header.start := sys.SIZE(KOSHEADER); Header.size := Align(size, 4) + datasize; Header.mem := Header.size + stk + gsize + strsize * 2 + 1000H; Header.sp := Header.size + gsize + stk; Header.param := Header.sp; Header.path := Header.param + strsize; Write(sys.ADR(Header), sys.SIZE(KOSHEADER)); cur := asmlist.First(ASMLINE); WHILE cur # NIL DO Write(sys.ADR(Code[cur.cmd]), cur.clen); cur := cur.Next(ASMLINE) END; Fill(Align(size, 4) - size, 0X); Write(sys.ADR(Data), datasize); WriteF(F, filebuf, OutFilePos - filebuf) ELSE size2 := size; size := Align(size, 4) - sys.SIZE(KOSHEADER); Coff.Machine := IntToCard16(014CH); Coff.NumberOfSections := IntToCard16(3); Coff.TimeDateStamp := UTILS.Date; Coff.SizeOfOptionalHeader := IntToCard16(0); Coff.Characteristics := IntToCard16(0184H); Coff.text.name := ".flat"; Coff.text.size := 0; Coff.text.adr := 0; Coff.text.sizealign := size; Coff.text.OAPfile := 8CH; Coff.text.reserved6 := size + datasize + 8CH; Coff.text.reserved7 := 0; Coff.text.attrflags := 40300020H; Coff.data.name := ".data"; Coff.data.size := 0; Coff.data.adr := 0; Coff.data.sizealign := datasize; Coff.data.OAPfile := size + 8CH; Coff.data.reserved6 := 0; Coff.data.reserved7 := 0; Coff.data.reserved8 := 0; Coff.data.attrflags := 0C0300040H; Coff.bss.name := ".bss"; Coff.bss.size := 0; Coff.bss.adr := 0; Coff.bss.sizealign := gsize; Coff.bss.OAPfile := 0; Coff.bss.reserved6 := 0; Coff.bss.reserved7 := 0; Coff.bss.reserved8 := 0; Coff.bss.attrflags := 0C03000C0H; size := Align(size2, 4); rcount := 0; cur := asmlist.First(ASMLINE); WHILE cur # NIL DO IF cur.tcmd IN {OCMD, GCMD} THEN sys.GET(sys.ADR(Code[cur.cmd]), a); IF a < size THEN a := a - sys.SIZE(KOSHEADER); sec := 1 ELSIF a < size + datasize THEN a := a - size; sec := 2 ELSE a := a - size - datasize; sec := 3 END; sys.PUT(sys.ADR(Code[cur.cmd]), a); sys.PUT(sys.ADR(Reloc[rcount]), cur.adr - sys.SIZE(KOSHEADER)); INC(rcount, 4); sys.PUT(sys.ADR(Reloc[rcount]), sec); INC(rcount, 4); sys.PUT(sys.ADR(Reloc[rcount]), 06X); INC(rcount); sys.PUT(sys.ADR(Reloc[rcount]), 00X); INC(rcount); END; Write(sys.ADR(Code[cur.cmd]), cur.clen); cur := cur.Next(ASMLINE) END; size := size2; Fill(Align(size, 4) - size2, 0X); Write(sys.ADR(Data), datasize); Coff.text.reserved8 := rcount DIV 10; Coff.PointerToSymbolTable := Coff.text.reserved6 + rcount; Coff.NumberOfSymbols := 4; WriteF(F, sys.ADR(Coff), sys.SIZE(COFFHEADER)); WriteF(F, filebuf, OutFilePos - filebuf); WriteF(F, sys.ADR(Reloc), rcount); adr := sys.ADR(sym); InitArray(adr, "4558504F52545300000000000100000002002E666C617400000000000000010000000300"); InitArray(adr, "2E64617461000000000000000200000003002E6273730000000000000000030000000300"); sys.PUT(sys.ADR(sym) + 8, Labels[Exports] - sys.SIZE(KOSHEADER)); WriteF(F, sys.ADR(sym), LEN(sym)); i := 4; WriteF(F, sys.ADR(i), 4) END; UTILS.CloseF(F) END WriteKOS; PROCEDURE WriteELF(FName: ARRAY OF CHAR; code, data, glob: INTEGER); VAR F, delta, filebuf: INTEGER; cur: ASMLINE; bytes: ARRAY 817H + 55FH + 4900 OF CHAR; PROCEDURE Add(offset: INTEGER); VAR m: INTEGER; BEGIN sys.GET(sys.ADR(bytes[offset]), m); sys.PUT(sys.ADR(bytes[offset]), m + delta) END Add; PROCEDURE Sub(offset: INTEGER); VAR m: INTEGER; BEGIN sys.GET(sys.ADR(bytes[offset]), m); sys.PUT(sys.ADR(bytes[offset]), m - delta) END Sub; PROCEDURE Add8(a1, a2, a3, a4, a5, a6, a7, a8: INTEGER); BEGIN Add(a1); Add(a2); Add(a3); Add(a4); Add(a5); Add(a6); Add(a7); Add(a8) END Add8; BEGIN sys.MOVE(ELF.get(), sys.ADR(bytes[0]), ELF.size); DEC(code, 13); delta := Align(data, 1000H) - 100000H; Add8(0020H, 00A4H, 00A8H, 0258H, 02B8H, 0308H, 0494H, 049CH); Add8(04A4H, 0679H, 0681H, 06A4H, 06B0H, 06BAH, 0703H, 0762H); Add8(0774H, 0786H, 0819H, 0823H, 17C5H, 17E5H, 17E9H, 1811H); Add8(1839H, 1861H, 1889H, 1A25H, 1A95H, 1AA5H, 1C05H, 1C55H); Add(1CE5H); Add(1D09H); Add(1D15H); Add(1D25H); Add(1D35H); Add(1D55H); delta := Align(glob, 1000H) - 3200000H; Add(00A8H); Add(17EDH); Add(1C09H); Add(1D25H); delta := Align(code, 1000H) - 100000H; Add8(0020H, 0084H, 0088H, 0098H, 009CH, 00A0H, 00B8H, 00BCH); Add8(00C0H, 0118H, 011CH, 0120H, 0258H, 0278H, 02B8H, 0308H); Add8(048CH, 0494H, 049CH, 04A4H, 04ACH, 04B4H, 04BCH, 04C4H); Add8(04CCH, 04D4H, 04DCH, 04E4H, 04ECH, 04F4H, 04FCH, 0504H); Add8(050CH, 0514H, 052BH, 0544H, 054EH, 0554H, 055EH, 056EH); Add8(057EH, 058EH, 059EH, 05AEH, 05BEH, 05CEH, 05DEH, 05EEH); Add8(05FEH, 060EH, 061EH, 062EH, 064CH, 0651H, 0679H, 0681H); Add8(0686H, 068CH, 06A4H, 06ABH, 06B0H, 06BAH, 06D7H, 06EBH); Add8(0703H, 0762H, 0774H, 0786H, 0819H, 0823H, 0828H, 082DH); Add8(1635H, 1655H, 1659H, 167DH, 1681H, 16A5H, 16A9H, 16CDH); Add8(16D1H, 16F5H, 16F9H, 171DH, 1721H, 1745H, 1749H, 176DH); Add8(1771H, 1795H, 1799H, 17BDH, 17C1H, 17E5H, 17E9H, 1811H); Add8(1839H, 1861H, 1889H, 1985H, 1995H, 19A5H, 19B5H, 19C5H); Add8(19D5H, 19E5H, 19F5H, 1A05H, 1A15H, 1A25H, 1A55H, 1A65H); Add8(1A75H, 1A95H, 1AA5H, 1AD5H, 1AE5H, 1AF5H, 1B05H, 1B25H); Add8(1B35H, 1B45H, 1B55H, 1B65H, 1B75H, 1BB5H, 1BC5H, 1BE5H); Add8(1C05H, 1C15H, 1C55H, 1C75H, 1CA5H, 1CB5H, 1CE5H, 1D05H); Add8(1D15H, 1D25H, 1D35H, 1D55H, 1D75H, 1D89H, 08DEH, 08E8H); Sub(0845H); Sub(087BH); Sub(0916H); Add(0C52H); Add(0C8AH); Add(0D0AH); OutFilePos := UTILS.GetMem(code + data + 8000H); filebuf := OutFilePos; UTILS.MemErr(OutFilePos = 0); Write(sys.ADR(bytes), 817H); Fill(2DDH, 90X); cur := asmlist.First(ASMLINE); WHILE cur # NIL DO Write(sys.ADR(Code[cur.cmd]), cur.clen); cur := cur.Next(ASMLINE) END; Fill(Align(code, 1000H) - code, 90X); Write(sys.ADR(bytes[817H]), 55FH); Write(sys.ADR(Data), data); Fill(Align(data, 1000H) - data, 0X); Write(sys.ADR(bytes[817H + 55FH + 55FH]), 0DC5H); F := UTILS.CreateF(FName); IF F <= 0 THEN Err(1) END; WriteF(F, filebuf, OutFilePos - filebuf); UTILS.CloseF(F) END WriteELF; PROCEDURE DelProc*(beg, end: ASMLINE); BEGIN WHILE beg # end DO beg.clen := 0; beg.tcmd := 0; beg := beg.Next(ASMLINE) END; beg.clen := 0; beg.tcmd := 0 END DelProc; PROCEDURE FixLabels*(FName: ARRAY OF CHAR; stk, gsize, glob: INTEGER); VAR size, asize, i, rdatasize, RCount, n, temp, temp2, temp3: INTEGER; cur: ASMLINE; R: RELOC; c: CHAR; BEGIN dcount := Align(dcount, 4); IF dll THEN LoadAdr := 10000000H; PackExport(ExecName) ELSIF con OR gui THEN LoadAdr := 400000H ELSIF kos OR obj THEN LoadAdr := sys.SIZE(KOSHEADER) ELSIF elf THEN LoadAdr := 134514420 + 1024; INC(gsize, 1024) END; IF dll OR con OR gui THEN rdatasize := 0DAH + etable.size; size := 1000H + LoadAdr; ELSIF kos OR elf OR obj THEN rdatasize := 0; size := LoadAdr END; Optimization; temp2 := size; cur := asmlist.First(ASMLINE); WHILE cur # NIL DO cur.adr := size; IF cur.tcmd = LCMD THEN sys.PUT(cur.varadr, size) END; size := size + cur.clen; cur := cur.Next(ASMLINE) END; size := temp2; cur := asmlist.First(ASMLINE); WHILE cur # NIL DO cur.adr := size; IF cur.tcmd = LCMD THEN sys.PUT(cur.varadr, size) ELSIF (cur.tcmd = JCMD) & cur.short THEN sys.GET(cur.varadr, i); temp3 := i - cur.Next(ASMLINE).adr; IF (-131 <= temp3) & (temp3 <= 123) THEN sys.GET(cur(ASMLINE).codeadr - 1, c); IF c = JMP THEN sys.PUT(cur(ASMLINE).codeadr - 1, 0EBX) ELSE (*JE, JNE, JLE, JGE, JG, JL*) sys.PUT(cur(ASMLINE).codeadr - 2, ORD(c) - 16); sys.PUT(cur(ASMLINE).codeadr - 1, temp3); DEC(cur(ASMLINE).codeadr) END; cur.clen := 2 END END; size := size + cur.clen; cur := cur.Next(ASMLINE) END; IF dll OR con OR gui THEN asize := Align(size, 1000H) ELSIF kos OR obj THEN asize := Align(size, 4) ELSIF elf THEN asize := 134514420 + 6508 + Align(size - 13 - LoadAdr, 1000H) END; FOR i := 0 TO Lcount DO IF Labels[i] < 0 THEN Labels[i] := -Labels[i] + asize + Align(rdatasize, 1000H) END END; temp := dcount; IF elf THEN asize := asize + Align(dcount, 1000H) + 64 + 1024; sys.PUT(sys.ADR(Code[glob + 1]), asize - 1024); dcount := 0 END; IF dll THEN asize := asize - LoadAdr + 0DAH; FOR i := 0 TO etable.namecount - 1 DO etable.arradr[i] := Labels[etable.arradr[i]] - LoadAdr; etable.arrnameptr[i] := etable.arrnameptr[i] + asize END; etable.arradroffset := etable.arradroffset + asize; etable.arrnameptroffset := etable.arrnameptroffset + asize; etable.arrnumoffset := etable.arrnumoffset + asize; etable.dllnameoffset := etable.dllnameoffset + asize; asize := asize + LoadAdr - 0DAH END; IF dll OR con OR gui THEN Labels[LoadLibrary] := asize + 4; Labels[GetProcAddress] := asize; R.Page := 0; R.Size := 0; RCount := 0; END; cur := asmlist.First(ASMLINE); FOR i := 0 TO LEN(RtlProc) - 1 DO RtlProc[i] := Labels[RtlProc[i]] END; temp3 := asize + Align(rdatasize, 1000H) + dcount; WHILE cur # NIL DO CASE cur.tcmd OF |JCMD: sys.GET(cur.varadr, i); sys.PUT(cur.codeadr, i - cur.Next(ASMLINE).adr) |GCMD: sys.GET(cur.codeadr, i); sys.PUT(cur.codeadr, i + temp3) |OCMD: sys.MOVE(cur.varadr, cur.codeadr, 4) ELSE END; IF dll & (cur.tcmd IN {GCMD, OCMD}) THEN n := cur.adr - LoadAdr; IF ASR(n, 12) = ASR(R.Page, 12) THEN R.reloc[RCount] := IntToCard16(n MOD 1000H + 3000H); INC(RCount); INC(R.Size, 2) ELSE IF R.Size # 0 THEN PutReloc(R) END; R.Page := ASR(n, 12) * 1000H; R.Size := 10; R.reloc[0] := IntToCard16(n MOD 1000H + 3000H); RCount := 1 END END; cur := cur.Next(ASMLINE) END; IF R.Size # 0 THEN PutReloc(R) END; IF dll OR con OR gui THEN WritePE(FName, stk, size - 1000H - LoadAdr, dcount, rdatasize, gsize) ELSIF kos OR obj THEN WriteKOS(FName, Align(stk, 4), size, dcount, gsize, obj) ELSIF elf THEN WriteELF(FName, size - LoadAdr, temp, gsize) END END FixLabels; PROCEDURE OutStringZ(str: ARRAY OF CHAR); VAR i: INTEGER; BEGIN New; current.clen := LENGTH(str); FOR i := 0 TO current.clen - 1 DO Code[ccount] := str[i]; INC(ccount) END; Code[ccount] := 0X; INC(ccount); INC(current.clen) END OutStringZ; PROCEDURE Epilog*(gsize: INTEGER; FName: ARRAY OF CHAR; stk: INTEGER); VAR i, glob: INTEGER; BEGIN glob := 0; gsize := Align(gsize, 4) + 4; COPY(FName, OutFile); Labels[RTABLE] := -dcount; dataint(recarray[0]); FOR i := 1 TO reccount DO dataint(recarray[i]) END; current := start; IF con OR gui OR dll THEN PushInt(LoadLibrary); PushInt(GetProcAddress); OutCode("5859FF31FF3054") ELSIF elf THEN OutCode("6800000000"); glob := current.cmd; ELSIF kos OR obj THEN OutByte(54H) END; GlobalAdr(0); PushConst(ASR(gsize, 2)); PushInt(RTABLE); PushInt(SELFNAME); CallRTL(_init); current := asmlist.Last(ASMLINE); IF dll THEN OutCode("B801000000C9C20C00") END; IF obj THEN OutCode("B801000000C9C20000") END; OutCode("EB05"); Label(ASSRT); CallRTL(_assrt); OutCode("EB09"); Label(HALT); OutCode("6A006A00"); CallRTL(_assrt); OutCode("6A00"); CallRTL(_halt); Label(_floor); OutCode("83EC06D93C2466812424FFF366810C24FFF7D92C2483C402D9FCDB1C2458C3"); IF obj THEN Label(Exports); CmdN(szSTART); CmdN(START); CmdN(szversion); OutInt(stk); FOR i := 0 TO kosexpcount - 1 DO CmdN(kosexp[i].NameLabel); CmdN(kosexp[i].Adr) END; OutInt(0); Label(szSTART); OutStringZ("lib_init"); Label(szversion); OutStringZ("version"); FOR i := 0 TO kosexpcount - 1 DO Label(kosexp[i].NameLabel); OutStringZ(kosexp[i].Name.Name) END END; FixLabels(FName, stk, gsize, glob) END Epilog; END X86.