forked from KolibriOS/kolibrios
82d72daa76
git-svn-id: svn://kolibrios.org@7597 a494cfbc-eb01-0410-851d-a64ba20cac60
2406 lines
63 KiB
Plaintext
2406 lines
63 KiB
Plaintext
(*
|
|
BSD 2-Clause License
|
|
|
|
Copyright (c) 2018, 2019, Anton Krotov
|
|
All rights reserved.
|
|
*)
|
|
|
|
MODULE X86;
|
|
|
|
IMPORT CODE, REG, UTILS, LISTS, BIN, PE32, KOS, MSCOFF, ELF, mConst := CONSTANTS, MACHINE, CHL := CHUNKLISTS, PATHS;
|
|
|
|
|
|
CONST
|
|
|
|
eax = REG.R0; ecx = REG.R1; edx = REG.R2;
|
|
|
|
al = eax; cl = ecx; dl = edx; ah = 4;
|
|
|
|
ax = eax; cx = ecx; dx = edx;
|
|
|
|
esp = 4;
|
|
ebp = 5;
|
|
|
|
sete = 94H; setne = 95H; setl = 9CH; setge = 9DH; setle = 9EH; setg = 9FH; setc = 92H; setnc = 93H;
|
|
|
|
je = 84H; jne = 85H; jl = 8CH; jge = 8DH; jle = 8EH; jg = 8FH; jb = 82H; jnb = 83H;
|
|
|
|
|
|
CODECHUNK = 8;
|
|
|
|
|
|
TYPE
|
|
|
|
COMMAND = CODE.COMMAND;
|
|
|
|
|
|
ANYCODE = POINTER TO RECORD (LISTS.ITEM)
|
|
|
|
offset: INTEGER
|
|
|
|
END;
|
|
|
|
TCODE = POINTER TO RECORD (ANYCODE)
|
|
|
|
code: ARRAY CODECHUNK OF BYTE;
|
|
length: INTEGER
|
|
|
|
END;
|
|
|
|
LABEL = POINTER TO RECORD (ANYCODE)
|
|
|
|
label: INTEGER
|
|
|
|
END;
|
|
|
|
JUMP = POINTER TO RECORD (ANYCODE)
|
|
|
|
label, diff: INTEGER;
|
|
short: BOOLEAN
|
|
|
|
END;
|
|
|
|
JMP = POINTER TO RECORD (JUMP)
|
|
|
|
END;
|
|
|
|
JCC = POINTER TO RECORD (JUMP)
|
|
|
|
jmp: INTEGER
|
|
|
|
END;
|
|
|
|
CALL = POINTER TO RECORD (JUMP)
|
|
|
|
END;
|
|
|
|
RELOC = POINTER TO RECORD (ANYCODE)
|
|
|
|
op, value: INTEGER
|
|
|
|
END;
|
|
|
|
|
|
VAR
|
|
|
|
R: REG.REGS;
|
|
|
|
program: BIN.PROGRAM;
|
|
|
|
CodeList: LISTS.LIST;
|
|
|
|
|
|
PROCEDURE Byte (n: INTEGER): BYTE;
|
|
RETURN MACHINE.Byte(n, 0)
|
|
END Byte;
|
|
|
|
|
|
PROCEDURE Word (n: INTEGER): INTEGER;
|
|
RETURN MACHINE.Byte(n, 0) + MACHINE.Byte(n, 1) * 256
|
|
END Word;
|
|
|
|
|
|
PROCEDURE OutByte* (n: BYTE);
|
|
VAR
|
|
c: TCODE;
|
|
last: ANYCODE;
|
|
|
|
BEGIN
|
|
last := CodeList.last(ANYCODE);
|
|
|
|
IF (last IS TCODE) & (last(TCODE).length < CODECHUNK) THEN
|
|
c := last(TCODE);
|
|
c.code[c.length] := n;
|
|
INC(c.length)
|
|
ELSE
|
|
NEW(c);
|
|
c.code[0] := n;
|
|
c.length := 1;
|
|
LISTS.push(CodeList, c)
|
|
END
|
|
|
|
END OutByte;
|
|
|
|
|
|
PROCEDURE OutInt (n: INTEGER);
|
|
BEGIN
|
|
OutByte(MACHINE.Byte(n, 0));
|
|
OutByte(MACHINE.Byte(n, 1));
|
|
OutByte(MACHINE.Byte(n, 2));
|
|
OutByte(MACHINE.Byte(n, 3))
|
|
END OutInt;
|
|
|
|
|
|
PROCEDURE OutByte2 (a, b: BYTE);
|
|
BEGIN
|
|
OutByte(a);
|
|
OutByte(b)
|
|
END OutByte2;
|
|
|
|
|
|
PROCEDURE OutByte3 (a, b, c: BYTE);
|
|
BEGIN
|
|
OutByte(a);
|
|
OutByte(b);
|
|
OutByte(c)
|
|
END OutByte3;
|
|
|
|
|
|
PROCEDURE OutWord (n: INTEGER);
|
|
BEGIN
|
|
ASSERT((0 <= n) & (n <= 65535));
|
|
OutByte2(n MOD 256, n DIV 256)
|
|
END OutWord;
|
|
|
|
|
|
PROCEDURE isByte (n: INTEGER): BOOLEAN;
|
|
RETURN (-128 <= n) & (n <= 127)
|
|
END isByte;
|
|
|
|
|
|
PROCEDURE short (n: INTEGER): INTEGER;
|
|
RETURN 2 * ORD(isByte(n))
|
|
END short;
|
|
|
|
|
|
PROCEDURE long (n: INTEGER): INTEGER;
|
|
RETURN 40H * ORD(~isByte(n))
|
|
END long;
|
|
|
|
|
|
PROCEDURE OutIntByte (n: INTEGER);
|
|
BEGIN
|
|
IF isByte(n) THEN
|
|
OutByte(Byte(n))
|
|
ELSE
|
|
OutInt(n)
|
|
END
|
|
END OutIntByte;
|
|
|
|
|
|
PROCEDURE shift* (op, reg: INTEGER);
|
|
BEGIN
|
|
CASE op OF
|
|
|CODE.opASR, CODE.opASR1, CODE.opASR2: OutByte(0F8H + reg)
|
|
|CODE.opROR, CODE.opROR1, CODE.opROR2: OutByte(0C8H + reg)
|
|
|CODE.opLSL, CODE.opLSL1, CODE.opLSL2: OutByte(0E0H + reg)
|
|
|CODE.opLSR, CODE.opLSR1, CODE.opLSR2: OutByte(0E8H + reg)
|
|
END
|
|
END shift;
|
|
|
|
|
|
PROCEDURE mov (reg1, reg2: INTEGER);
|
|
BEGIN
|
|
OutByte2(89H, 0C0H + reg2 * 8 + reg1) // mov reg1, reg2
|
|
END mov;
|
|
|
|
|
|
PROCEDURE xchg (reg1, reg2: INTEGER);
|
|
VAR
|
|
regs: SET;
|
|
|
|
BEGIN
|
|
regs := {reg1, reg2};
|
|
IF regs = {eax, ecx} THEN
|
|
OutByte(91H) // xchg eax, ecx
|
|
ELSIF regs = {eax, edx} THEN
|
|
OutByte(92H) // xchg eax, edx
|
|
ELSIF regs = {ecx, edx} THEN
|
|
OutByte2(87H, 0D1H) // xchg ecx, edx
|
|
END
|
|
END xchg;
|
|
|
|
|
|
PROCEDURE pop (reg: INTEGER);
|
|
BEGIN
|
|
OutByte(58H + reg) // pop reg
|
|
END pop;
|
|
|
|
|
|
PROCEDURE push (reg: INTEGER);
|
|
BEGIN
|
|
OutByte(50H + reg) // push reg
|
|
END push;
|
|
|
|
|
|
PROCEDURE movrc (reg, n: INTEGER);
|
|
BEGIN
|
|
OutByte(0B8H + reg); // mov reg, n
|
|
OutInt(n)
|
|
END movrc;
|
|
|
|
|
|
PROCEDURE pushc (n: INTEGER);
|
|
BEGIN
|
|
OutByte(68H + short(n)); // push n
|
|
OutIntByte(n)
|
|
END pushc;
|
|
|
|
|
|
PROCEDURE test (reg: INTEGER);
|
|
BEGIN
|
|
OutByte2(85H, 0C0H + reg * 9) // test reg, reg
|
|
END test;
|
|
|
|
|
|
PROCEDURE neg (reg: INTEGER);
|
|
BEGIN
|
|
OutByte2(0F7H, 0D8H + reg) // neg reg
|
|
END neg;
|
|
|
|
|
|
PROCEDURE not (reg: INTEGER);
|
|
BEGIN
|
|
OutByte2(0F7H, 0D0H + reg) // not reg
|
|
END not;
|
|
|
|
|
|
PROCEDURE add (reg1, reg2: INTEGER);
|
|
BEGIN
|
|
OutByte2(01H, 0C0H + reg2 * 8 + reg1) // add reg1, reg2
|
|
END add;
|
|
|
|
|
|
PROCEDURE andrc (reg, n: INTEGER);
|
|
BEGIN
|
|
OutByte2(81H + short(n), 0E0H + reg); // and reg, n
|
|
OutIntByte(n)
|
|
END andrc;
|
|
|
|
|
|
PROCEDURE orrc (reg, n: INTEGER);
|
|
BEGIN
|
|
OutByte2(81H + short(n), 0C8H + reg); // or reg, n
|
|
OutIntByte(n)
|
|
END orrc;
|
|
|
|
|
|
PROCEDURE addrc (reg, n: INTEGER);
|
|
BEGIN
|
|
OutByte2(81H + short(n), 0C0H + reg); // add reg, n
|
|
OutIntByte(n)
|
|
END addrc;
|
|
|
|
|
|
PROCEDURE subrc (reg, n: INTEGER);
|
|
BEGIN
|
|
OutByte2(81H + short(n), 0E8H + reg); // sub reg, n
|
|
OutIntByte(n)
|
|
END subrc;
|
|
|
|
|
|
PROCEDURE cmprr (reg1, reg2: INTEGER);
|
|
BEGIN
|
|
OutByte2(39H, 0C0H + reg2 * 8 + reg1) // cmp reg1, reg2
|
|
END cmprr;
|
|
|
|
|
|
PROCEDURE cmprc (reg, n: INTEGER);
|
|
BEGIN
|
|
OutByte2(81H + short(n), 0F8H + reg); // cmp reg, n
|
|
OutIntByte(n)
|
|
END cmprc;
|
|
|
|
|
|
PROCEDURE setcc (cond, reg: INTEGER);
|
|
BEGIN
|
|
OutByte3(0FH, cond, 0C0H + reg) // setcc reg
|
|
END setcc;
|
|
|
|
|
|
PROCEDURE drop;
|
|
BEGIN
|
|
REG.Drop(R)
|
|
END drop;
|
|
|
|
|
|
PROCEDURE log2* (x: INTEGER): INTEGER;
|
|
VAR
|
|
n: INTEGER;
|
|
|
|
BEGIN
|
|
ASSERT(x > 0);
|
|
|
|
n := 0;
|
|
WHILE ~ODD(x) DO
|
|
x := x DIV 2;
|
|
INC(n)
|
|
END;
|
|
|
|
IF x # 1 THEN
|
|
n := -1
|
|
END
|
|
|
|
RETURN n
|
|
END log2;
|
|
|
|
|
|
PROCEDURE cond* (op: INTEGER): INTEGER;
|
|
VAR
|
|
res: INTEGER;
|
|
|
|
BEGIN
|
|
CASE op OF
|
|
|CODE.opGT, CODE.opGTR, CODE.opLTL: res := jg
|
|
|CODE.opGE, CODE.opGER, CODE.opLEL: res := jge
|
|
|CODE.opLT, CODE.opLTR, CODE.opGTL: res := jl
|
|
|CODE.opLE, CODE.opLER, CODE.opGEL: res := jle
|
|
|CODE.opEQ, CODE.opEQR, CODE.opEQL: res := je
|
|
|CODE.opNE, CODE.opNER, CODE.opNEL: res := jne
|
|
END
|
|
|
|
RETURN res
|
|
END cond;
|
|
|
|
|
|
PROCEDURE inv1* (op: INTEGER): INTEGER;
|
|
BEGIN
|
|
IF ODD(op) THEN
|
|
DEC(op)
|
|
ELSE
|
|
INC(op)
|
|
END
|
|
|
|
RETURN op
|
|
END inv1;
|
|
|
|
|
|
PROCEDURE Reloc* (op, value: INTEGER);
|
|
VAR
|
|
reloc: RELOC;
|
|
|
|
BEGIN
|
|
NEW(reloc);
|
|
reloc.op := op;
|
|
reloc.value := value;
|
|
LISTS.push(CodeList, reloc)
|
|
END Reloc;
|
|
|
|
|
|
PROCEDURE jcc* (cc, label: INTEGER);
|
|
VAR
|
|
j: JCC;
|
|
|
|
BEGIN
|
|
NEW(j);
|
|
j.label := label;
|
|
j.jmp := cc;
|
|
j.short := FALSE;
|
|
LISTS.push(CodeList, j)
|
|
END jcc;
|
|
|
|
|
|
PROCEDURE jmp* (label: INTEGER);
|
|
VAR
|
|
j: JMP;
|
|
|
|
BEGIN
|
|
NEW(j);
|
|
j.label := label;
|
|
j.short := FALSE;
|
|
LISTS.push(CodeList, j)
|
|
END jmp;
|
|
|
|
|
|
PROCEDURE call* (label: INTEGER);
|
|
VAR
|
|
c: CALL;
|
|
|
|
BEGIN
|
|
NEW(c);
|
|
c.label := label;
|
|
c.short := TRUE;
|
|
LISTS.push(CodeList, c)
|
|
END call;
|
|
|
|
|
|
PROCEDURE Pic (reg, opcode, value: INTEGER);
|
|
BEGIN
|
|
OutByte(0E8H); OutInt(0); // call L
|
|
// L:
|
|
pop(reg);
|
|
OutByte2(081H, 0C0H + reg); // add reg, ...
|
|
Reloc(opcode, value)
|
|
END Pic;
|
|
|
|
|
|
PROCEDURE CallRTL (pic: BOOLEAN; proc: INTEGER);
|
|
VAR
|
|
label: INTEGER;
|
|
reg1: INTEGER;
|
|
|
|
BEGIN
|
|
label := CODE.codes.rtl[proc];
|
|
|
|
IF label < 0 THEN
|
|
label := -label;
|
|
IF pic THEN
|
|
reg1 := REG.GetAnyReg(R);
|
|
Pic(reg1, BIN.PICIMP, label);
|
|
OutByte2(0FFH, 010H + reg1); // call dword[reg1]
|
|
drop
|
|
ELSE
|
|
OutByte2(0FFH, 015H); // call dword[label]
|
|
Reloc(BIN.RIMP, label)
|
|
END
|
|
ELSE
|
|
call(label)
|
|
END
|
|
END CallRTL;
|
|
|
|
|
|
PROCEDURE SetLabel* (label: INTEGER);
|
|
VAR
|
|
L: LABEL;
|
|
|
|
BEGIN
|
|
NEW(L);
|
|
L.label := label;
|
|
LISTS.push(CodeList, L)
|
|
END SetLabel;
|
|
|
|
|
|
PROCEDURE fixup*;
|
|
VAR
|
|
code: ANYCODE;
|
|
count, i: INTEGER;
|
|
shorted: BOOLEAN;
|
|
jump: JUMP;
|
|
|
|
BEGIN
|
|
|
|
REPEAT
|
|
|
|
shorted := FALSE;
|
|
count := 0;
|
|
|
|
code := CodeList.first(ANYCODE);
|
|
WHILE code # NIL DO
|
|
code.offset := count;
|
|
|
|
CASE code OF
|
|
|TCODE: INC(count, code.length)
|
|
|LABEL: BIN.SetLabel(program, code.label, count)
|
|
|JMP: IF code.short THEN INC(count, 2) ELSE INC(count, 5) END; code.offset := count
|
|
|JCC: IF code.short THEN INC(count, 2) ELSE INC(count, 6) END; code.offset := count
|
|
|CALL: INC(count, 5); code.offset := count
|
|
|RELOC: INC(count, 4)
|
|
END;
|
|
|
|
code := code.next(ANYCODE)
|
|
END;
|
|
|
|
code := CodeList.first(ANYCODE);
|
|
WHILE code # NIL DO
|
|
|
|
IF code IS JUMP THEN
|
|
jump := code(JUMP);
|
|
jump.diff := BIN.GetLabel(program, jump.label) - code.offset;
|
|
IF ~jump.short & isByte(jump.diff) THEN
|
|
jump.short := TRUE;
|
|
shorted := TRUE
|
|
END
|
|
END;
|
|
|
|
code := code.next(ANYCODE)
|
|
END
|
|
|
|
UNTIL ~shorted;
|
|
|
|
code := CodeList.first(ANYCODE);
|
|
WHILE code # NIL DO
|
|
|
|
CASE code OF
|
|
|
|
|TCODE:
|
|
FOR i := 0 TO code.length - 1 DO
|
|
BIN.PutCode(program, code.code[i])
|
|
END
|
|
|
|
|LABEL:
|
|
BIN.SetLabel(program, code.label, code.offset)
|
|
|
|
|JMP:
|
|
IF code.short THEN
|
|
BIN.PutCode(program, 0EBH);
|
|
BIN.PutCode(program, Byte(code.diff))
|
|
ELSE
|
|
BIN.PutCode(program, 0E9H);
|
|
BIN.PutCode32LE(program, code.diff)
|
|
END
|
|
|
|
|JCC:
|
|
IF code.short THEN
|
|
BIN.PutCode(program, code.jmp - 16);
|
|
BIN.PutCode(program, Byte(code.diff))
|
|
ELSE
|
|
BIN.PutCode(program, 0FH);
|
|
BIN.PutCode(program, code.jmp);
|
|
BIN.PutCode32LE(program, code.diff)
|
|
END
|
|
|
|
|CALL:
|
|
BIN.PutCode(program, 0E8H);
|
|
BIN.PutCode32LE(program, code.diff)
|
|
|
|
|RELOC:
|
|
BIN.PutReloc(program, code.op);
|
|
BIN.PutCode32LE(program, code.value)
|
|
|
|
END;
|
|
|
|
code := code.next(ANYCODE)
|
|
END
|
|
|
|
END fixup;
|
|
|
|
|
|
PROCEDURE UnOp (VAR reg: INTEGER);
|
|
BEGIN
|
|
REG.UnOp(R, reg)
|
|
END UnOp;
|
|
|
|
|
|
PROCEDURE BinOp (VAR reg1, reg2: INTEGER);
|
|
BEGIN
|
|
REG.BinOp(R, reg1, reg2)
|
|
END BinOp;
|
|
|
|
|
|
PROCEDURE PushAll (NumberOfParameters: INTEGER);
|
|
BEGIN
|
|
REG.PushAll(R);
|
|
R.pushed := R.pushed - NumberOfParameters
|
|
END PushAll;
|
|
|
|
|
|
PROCEDURE NewLabel (): INTEGER;
|
|
BEGIN
|
|
BIN.NewLabel(program)
|
|
RETURN CODE.NewLabel()
|
|
END NewLabel;
|
|
|
|
|
|
PROCEDURE GetRegA;
|
|
BEGIN
|
|
ASSERT(REG.GetReg(R, eax))
|
|
END GetRegA;
|
|
|
|
|
|
PROCEDURE translate (code: CODE.CODES; pic: BOOLEAN; stroffs: INTEGER);
|
|
VAR
|
|
cmd: COMMAND;
|
|
|
|
reg1, reg2: INTEGER;
|
|
|
|
n, a, b, label, cc: INTEGER;
|
|
|
|
param1, param2: INTEGER;
|
|
|
|
float: REAL;
|
|
|
|
BEGIN
|
|
cmd := code.commands.first(COMMAND);
|
|
|
|
WHILE cmd # NIL DO
|
|
|
|
param1 := cmd.param1;
|
|
param2 := cmd.param2;
|
|
|
|
CASE cmd.opcode OF
|
|
|
|
|CODE.opJMP:
|
|
jmp(param1)
|
|
|
|
|CODE.opCALL:
|
|
call(param1)
|
|
|
|
|CODE.opCALLI:
|
|
IF pic THEN
|
|
reg1 := REG.GetAnyReg(R);
|
|
Pic(reg1, BIN.PICIMP, param1);
|
|
OutByte2(0FFH, 010H + reg1); // call dword[reg1]
|
|
drop
|
|
ELSE
|
|
OutByte2(0FFH, 015H); // call dword[L]
|
|
Reloc(BIN.RIMP, param1)
|
|
END
|
|
|
|
|CODE.opCALLP:
|
|
UnOp(reg1);
|
|
OutByte2(0FFH, 0D0H + reg1); // call reg1
|
|
drop;
|
|
ASSERT(R.top = -1)
|
|
|
|
|CODE.opPRECALL:
|
|
n := param2;
|
|
IF (param1 # 0) & (n # 0) THEN
|
|
subrc(esp, 8)
|
|
END;
|
|
WHILE n > 0 DO
|
|
subrc(esp, 8);
|
|
OutByte3(0DDH, 01CH, 024H); // fstp qword[esp]
|
|
DEC(n)
|
|
END;
|
|
PushAll(0)
|
|
|
|
|CODE.opALIGN16:
|
|
ASSERT(eax IN R.regs);
|
|
mov(eax, esp);
|
|
andrc(esp, -16);
|
|
n := (3 - param2 MOD 4) * 4;
|
|
IF n > 0 THEN
|
|
subrc(esp, n)
|
|
END;
|
|
push(eax)
|
|
|
|
|CODE.opRES:
|
|
ASSERT(R.top = -1);
|
|
GetRegA;
|
|
n := param2;
|
|
WHILE n > 0 DO
|
|
OutByte3(0DDH, 004H, 024H); // fld qword[esp]
|
|
addrc(esp, 8);
|
|
DEC(n)
|
|
END
|
|
|
|
|CODE.opRESF:
|
|
n := param2;
|
|
IF n > 0 THEN
|
|
OutByte3(0DDH, 5CH + long(n * 8), 24H);
|
|
OutIntByte(n * 8); // fstp qword[esp + n*8]
|
|
INC(n)
|
|
END;
|
|
|
|
WHILE n > 0 DO
|
|
OutByte3(0DDH, 004H, 024H); // fld qword[esp]
|
|
addrc(esp, 8);
|
|
DEC(n)
|
|
END
|
|
|
|
|CODE.opENTER:
|
|
ASSERT(R.top = -1);
|
|
|
|
SetLabel(param1);
|
|
|
|
push(ebp);
|
|
mov(ebp, esp);
|
|
|
|
n := param2;
|
|
IF n > 4 THEN
|
|
movrc(ecx, n);
|
|
pushc(0); // @@: push 0
|
|
OutByte2(0E2H, 0FCH) // loop @b
|
|
ELSE
|
|
WHILE n > 0 DO
|
|
pushc(0);
|
|
DEC(n)
|
|
END
|
|
END
|
|
|
|
|CODE.opLEAVE, CODE.opLEAVER, CODE.opLEAVEF:
|
|
IF cmd.opcode = CODE.opLEAVER THEN
|
|
UnOp(reg1);
|
|
IF reg1 # eax THEN
|
|
GetRegA;
|
|
ASSERT(REG.Exchange(R, reg1, eax));
|
|
drop
|
|
END;
|
|
drop
|
|
END;
|
|
|
|
ASSERT(R.top = -1);
|
|
|
|
mov(esp, ebp);
|
|
pop(ebp);
|
|
|
|
n := param2;
|
|
IF n > 0 THEN
|
|
n := n * 4;
|
|
OutByte(0C2H); OutWord(Word(n)) // ret n
|
|
ELSE
|
|
OutByte(0C3H) // ret
|
|
END
|
|
|
|
|CODE.opERRC:
|
|
pushc(param2)
|
|
|
|
|CODE.opPARAM:
|
|
n := param2;
|
|
IF n = 1 THEN
|
|
UnOp(reg1);
|
|
push(reg1);
|
|
drop
|
|
ELSE
|
|
ASSERT(R.top + 1 <= n);
|
|
PushAll(n)
|
|
END
|
|
|
|
|CODE.opCLEANUP:
|
|
n := param2 * 4;
|
|
IF n # 0 THEN
|
|
addrc(esp, n)
|
|
END
|
|
|
|
|CODE.opPOPSP:
|
|
pop(esp)
|
|
|
|
|CODE.opCONST:
|
|
reg1 := REG.GetAnyReg(R);
|
|
movrc(reg1, param2)
|
|
|
|
|CODE.opLABEL:
|
|
SetLabel(param2) // L:
|
|
|
|
|CODE.opNOP:
|
|
|
|
|CODE.opGADR:
|
|
reg1 := REG.GetAnyReg(R);
|
|
IF pic THEN
|
|
Pic(reg1, BIN.PICBSS, param2)
|
|
ELSE
|
|
OutByte(0B8H + reg1); // mov reg1, _bss + param2
|
|
Reloc(BIN.RBSS, param2)
|
|
END
|
|
|
|
|CODE.opLADR:
|
|
n := param2 * 4;
|
|
reg1 := REG.GetAnyReg(R);
|
|
OutByte2(8DH, 45H + reg1 * 8 + long(n)); // lea reg1, dword[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opVADR:
|
|
n := param2 * 4;
|
|
reg1 := REG.GetAnyReg(R);
|
|
OutByte2(8BH, 45H + reg1 * 8 + long(n)); // mov reg1, dword[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opSADR:
|
|
reg1 := REG.GetAnyReg(R);
|
|
IF pic THEN
|
|
Pic(reg1, BIN.PICDATA, stroffs + param2);
|
|
ELSE
|
|
OutByte(0B8H + reg1); // mov reg1, _data + stroffs + param2
|
|
Reloc(BIN.RDATA, stroffs + param2)
|
|
END
|
|
|
|
|CODE.opSAVEC:
|
|
UnOp(reg1);
|
|
OutByte2(0C7H, reg1); OutInt(param2); // mov dword[reg1], param2
|
|
drop
|
|
|
|
|CODE.opSAVE8C:
|
|
UnOp(reg1);
|
|
OutByte3(0C6H, reg1, Byte(param2)); // mov byte[reg1], param2
|
|
drop
|
|
|
|
|CODE.opSAVE16C:
|
|
UnOp(reg1);
|
|
OutByte3(66H, 0C7H, reg1); OutWord(Word(param2)); // mov word[reg1], param2
|
|
drop
|
|
|
|
|CODE.opVLOAD32:
|
|
n := param2 * 4;
|
|
reg1 := REG.GetAnyReg(R);
|
|
OutByte2(8BH, 45H + reg1 * 8 + long(n)); // mov reg1, dword[ebp + n]
|
|
OutIntByte(n);
|
|
OutByte2(8BH, reg1 * 9) // mov reg1, dword[reg1]
|
|
|
|
|CODE.opGLOAD32:
|
|
reg1 := REG.GetAnyReg(R);
|
|
IF pic THEN
|
|
Pic(reg1, BIN.PICBSS, param2);
|
|
OutByte2(8BH, reg1 * 9) // mov reg1, dword[reg1]
|
|
ELSE
|
|
OutByte2(08BH, 05H + reg1 * 8); // mov reg1, dword[_bss + param2]
|
|
Reloc(BIN.RBSS, param2)
|
|
END
|
|
|
|
|CODE.opLLOAD32:
|
|
n := param2 * 4;
|
|
reg1 := REG.GetAnyReg(R);
|
|
OutByte2(8BH, 45H + reg1 * 8 + long(n)); // mov reg1, dword[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opLOAD32:
|
|
UnOp(reg1);
|
|
OutByte2(8BH, reg1 * 9) // mov reg1, dword[reg1]
|
|
|
|
|CODE.opVLOAD8:
|
|
n := param2 * 4;
|
|
reg1 := REG.GetAnyReg(R);
|
|
OutByte2(8BH, 45H + reg1 * 8 + long(n)); // mov reg1, dword[ebp + n]
|
|
OutIntByte(n);
|
|
OutByte3(0FH, 0B6H, reg1 * 9) // movzx reg1, byte[reg1]
|
|
|
|
|CODE.opGLOAD8:
|
|
reg1 := REG.GetAnyReg(R);
|
|
IF pic THEN
|
|
Pic(reg1, BIN.PICBSS, param2);
|
|
OutByte3(0FH, 0B6H, reg1 * 9) // movzx reg1, byte[reg1]
|
|
ELSE
|
|
OutByte3(00FH, 0B6H, 05H + reg1 * 8); // movzx reg1, byte[_bss + param2]
|
|
Reloc(BIN.RBSS, param2)
|
|
END
|
|
|
|
|CODE.opLLOAD8:
|
|
n := param2 * 4;
|
|
reg1 := REG.GetAnyReg(R);
|
|
OutByte3(0FH, 0B6H, 45H + reg1 * 8 + long(n)); // movzx reg1, byte[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opLOAD8:
|
|
UnOp(reg1);
|
|
OutByte3(0FH, 0B6H, reg1 * 9) // movzx reg1, byte[reg1]
|
|
|
|
|CODE.opVLOAD16:
|
|
n := param2 * 4;
|
|
reg1 := REG.GetAnyReg(R);
|
|
OutByte2(8BH, 45H + reg1 * 8 + long(n)); // mov reg1, dword[ebp + n]
|
|
OutIntByte(n);
|
|
OutByte3(0FH, 0B7H, reg1 * 9) // movzx reg1, word[reg1]
|
|
|
|
|CODE.opGLOAD16:
|
|
reg1 := REG.GetAnyReg(R);
|
|
IF pic THEN
|
|
Pic(reg1, BIN.PICBSS, param2);
|
|
OutByte3(0FH, 0B7H, reg1 * 9) // movzx reg1, word[reg1]
|
|
ELSE
|
|
OutByte3(00FH, 0B7H, 05H + reg1 * 8); // movzx reg1, word[_bss + param2]
|
|
Reloc(BIN.RBSS, param2)
|
|
END
|
|
|
|
|CODE.opLLOAD16:
|
|
n := param2 * 4;
|
|
reg1 := REG.GetAnyReg(R);
|
|
OutByte3(0FH, 0B7H, 45H + reg1 * 8 + long(n)); // movzx reg1, word[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opLOAD16:
|
|
UnOp(reg1);
|
|
OutByte3(0FH, 0B7H, reg1 * 9) // movzx reg1, word[reg1]
|
|
|
|
|CODE.opUMINUS:
|
|
UnOp(reg1);
|
|
neg(reg1)
|
|
|
|
|CODE.opADD:
|
|
BinOp(reg1, reg2);
|
|
add(reg1, reg2);
|
|
drop
|
|
|
|
|CODE.opADDL, CODE.opADDR:
|
|
IF param2 # 0 THEN
|
|
UnOp(reg1);
|
|
IF param2 = 1 THEN
|
|
OutByte(40H + reg1) // inc reg1
|
|
ELSIF param2 = -1 THEN
|
|
OutByte(48H + reg1) // dec reg1
|
|
ELSE
|
|
addrc(reg1, param2)
|
|
END
|
|
END
|
|
|
|
|CODE.opSUB:
|
|
BinOp(reg1, reg2);
|
|
OutByte2(29H, 0C0H + reg2 * 8 + reg1); // sub reg1, reg2
|
|
drop
|
|
|
|
|CODE.opSUBR, CODE.opSUBL:
|
|
UnOp(reg1);
|
|
n := param2;
|
|
IF n = 1 THEN
|
|
OutByte(48H + reg1) // dec reg1
|
|
ELSIF n = -1 THEN
|
|
OutByte(40H + reg1) // inc reg1
|
|
ELSIF n # 0 THEN
|
|
subrc(reg1, n)
|
|
END;
|
|
IF cmd.opcode = CODE.opSUBL THEN
|
|
neg(reg1)
|
|
END
|
|
|
|
|CODE.opMULC:
|
|
UnOp(reg1);
|
|
|
|
a := param2;
|
|
IF a > 1 THEN
|
|
n := log2(a)
|
|
ELSIF a < -1 THEN
|
|
n := log2(-a)
|
|
ELSE
|
|
n := -1
|
|
END;
|
|
|
|
IF a = 1 THEN
|
|
|
|
ELSIF a = -1 THEN
|
|
neg(reg1)
|
|
ELSIF a = 0 THEN
|
|
OutByte2(31H, 0C0H + reg1 * 9) // xor reg1, reg1
|
|
ELSE
|
|
IF n > 0 THEN
|
|
IF a < 0 THEN
|
|
neg(reg1)
|
|
END;
|
|
|
|
IF n # 1 THEN
|
|
OutByte3(0C1H, 0E0H + reg1, n) // shl reg1, n
|
|
ELSE
|
|
OutByte2(0D1H, 0E0H + reg1) // shl reg1, 1
|
|
END
|
|
ELSE
|
|
OutByte2(69H + short(a), 0C0H + reg1 * 9); // imul reg1, a
|
|
OutIntByte(a)
|
|
END
|
|
END
|
|
|
|
|CODE.opMUL:
|
|
BinOp(reg1, reg2);
|
|
OutByte3(0FH, 0AFH, 0C0H + reg1 * 8 + reg2); // imul reg1, reg2
|
|
drop
|
|
|
|
|CODE.opSAVE, CODE.opSAVE32:
|
|
BinOp(reg2, reg1);
|
|
OutByte2(89H, reg2 * 8 + reg1); // mov dword[reg1], reg2
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opSAVE8:
|
|
BinOp(reg2, reg1);
|
|
OutByte2(88H, reg2 * 8 + reg1); // mov byte[reg1], reg2
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opSAVE16:
|
|
BinOp(reg2, reg1);
|
|
OutByte3(66H, 89H, reg2 * 8 + reg1); // mov word[reg1], reg2
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opSAVEP:
|
|
UnOp(reg1);
|
|
IF pic THEN
|
|
reg2 := REG.GetAnyReg(R);
|
|
Pic(reg2, BIN.PICCODE, param2);
|
|
OutByte2(089H, reg2 * 8 + reg1); // mov dword[reg1], reg2
|
|
drop
|
|
ELSE
|
|
OutByte2(0C7H, reg1); // mov dword[reg1], L
|
|
Reloc(BIN.RCODE, param2)
|
|
END;
|
|
drop
|
|
|
|
|CODE.opSAVEIP:
|
|
UnOp(reg1);
|
|
IF pic THEN
|
|
reg2 := REG.GetAnyReg(R);
|
|
Pic(reg2, BIN.PICIMP, param2);
|
|
OutByte2(0FFH, 30H + reg2); // push dword[reg2]
|
|
OutByte2(08FH, reg1); // pop dword[reg1]
|
|
drop
|
|
ELSE
|
|
OutByte2(0FFH, 035H); // push dword[L]
|
|
Reloc(BIN.RIMP, param2);
|
|
OutByte2(08FH, reg1) // pop dword[reg1]
|
|
END;
|
|
drop
|
|
|
|
|CODE.opPUSHP:
|
|
reg1 := REG.GetAnyReg(R);
|
|
IF pic THEN
|
|
Pic(reg1, BIN.PICCODE, param2)
|
|
ELSE
|
|
OutByte(0B8H + reg1); // mov reg1, L
|
|
Reloc(BIN.RCODE, param2)
|
|
END
|
|
|
|
|CODE.opPUSHIP:
|
|
reg1 := REG.GetAnyReg(R);
|
|
IF pic THEN
|
|
Pic(reg1, BIN.PICIMP, param2);
|
|
OutByte2(08BH, reg1 * 9) // mov reg1, dword[reg1]
|
|
ELSE
|
|
OutByte2(08BH, 05H + reg1 * 8); // mov reg1, dword[L]
|
|
Reloc(BIN.RIMP, param2)
|
|
END
|
|
|
|
|CODE.opNOT:
|
|
UnOp(reg1);
|
|
test(reg1);
|
|
setcc(sete, reg1);
|
|
andrc(reg1, 1)
|
|
|
|
|CODE.opORD:
|
|
UnOp(reg1);
|
|
test(reg1);
|
|
setcc(setne, reg1);
|
|
andrc(reg1, 1)
|
|
|
|
|CODE.opSBOOL:
|
|
BinOp(reg2, reg1);
|
|
test(reg2);
|
|
setcc(setne, reg2);
|
|
OutByte2(88H, reg2 * 8 + reg1); // mov byte[reg1], reg2
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opSBOOLC:
|
|
UnOp(reg1);
|
|
OutByte3(0C6H, reg1, ORD(param2 # 0)); // mov byte[reg1], 0/1
|
|
drop
|
|
|
|
|CODE.opODD:
|
|
UnOp(reg1);
|
|
andrc(reg1, 1)
|
|
|
|
|CODE.opGTR, CODE.opLTL, CODE.opGER, CODE.opLEL,
|
|
CODE.opLER, CODE.opGEL, CODE.opLTR, CODE.opGTL,
|
|
CODE.opEQR, CODE.opEQL, CODE.opNER, CODE.opNEL:
|
|
UnOp(reg1);
|
|
IF param2 = 0 THEN
|
|
test(reg1)
|
|
ELSE
|
|
cmprc(reg1, param2)
|
|
END;
|
|
drop;
|
|
cc := cond(cmd.opcode);
|
|
|
|
IF cmd.next(COMMAND).opcode = CODE.opJE THEN
|
|
label := cmd.next(COMMAND).param1;
|
|
jcc(cc, label);
|
|
cmd := cmd.next(COMMAND)
|
|
|
|
ELSIF cmd.next(COMMAND).opcode = CODE.opJNE THEN
|
|
label := cmd.next(COMMAND).param1;
|
|
jcc(inv1(cc), label);
|
|
cmd := cmd.next(COMMAND)
|
|
|
|
ELSE
|
|
reg1 := REG.GetAnyReg(R);
|
|
setcc(cc + 16, reg1);
|
|
andrc(reg1, 1)
|
|
END;
|
|
|
|
|CODE.opGT, CODE.opGE, CODE.opLT,
|
|
CODE.opLE, CODE.opEQ, CODE.opNE:
|
|
BinOp(reg1, reg2);
|
|
cmprr(reg1, reg2);
|
|
drop;
|
|
drop;
|
|
cc := cond(cmd.opcode);
|
|
|
|
IF cmd.next(COMMAND).opcode = CODE.opJE THEN
|
|
label := cmd.next(COMMAND).param1;
|
|
jcc(cc, label);
|
|
cmd := cmd.next(COMMAND)
|
|
|
|
ELSIF cmd.next(COMMAND).opcode = CODE.opJNE THEN
|
|
label := cmd.next(COMMAND).param1;
|
|
jcc(inv1(cc), label);
|
|
cmd := cmd.next(COMMAND)
|
|
|
|
ELSE
|
|
reg1 := REG.GetAnyReg(R);
|
|
setcc(cc + 16, reg1);
|
|
andrc(reg1, 1)
|
|
END
|
|
|
|
|CODE.opEQB, CODE.opNEB:
|
|
BinOp(reg1, reg2);
|
|
drop;
|
|
drop;
|
|
|
|
test(reg1);
|
|
OutByte2(74H, 5); // je @f
|
|
movrc(reg1, 1); // mov reg1, 1
|
|
// @@:
|
|
test(reg2);
|
|
OutByte2(74H, 5); // je @f
|
|
movrc(reg2, 1); // mov reg2, 1
|
|
// @@:
|
|
|
|
cmprr(reg1, reg2);
|
|
reg1 := REG.GetAnyReg(R);
|
|
IF cmd.opcode = CODE.opEQB THEN
|
|
setcc(sete, reg1)
|
|
ELSE
|
|
setcc(setne, reg1)
|
|
END;
|
|
andrc(reg1, 1)
|
|
|
|
|CODE.opDROP:
|
|
UnOp(reg1);
|
|
drop
|
|
|
|
|CODE.opJNZ:
|
|
UnOp(reg1);
|
|
test(reg1);
|
|
jcc(jne, param1)
|
|
|
|
|CODE.opJZ:
|
|
UnOp(reg1);
|
|
test(reg1);
|
|
jcc(je, param1)
|
|
|
|
|CODE.opJE:
|
|
UnOp(reg1);
|
|
test(reg1);
|
|
jcc(jne, param1);
|
|
drop;
|
|
|
|
|CODE.opJNE:
|
|
UnOp(reg1);
|
|
test(reg1);
|
|
jcc(je, param1);
|
|
drop;
|
|
|
|
|CODE.opSWITCH:
|
|
UnOp(reg1);
|
|
IF param2 = 0 THEN
|
|
reg2 := eax
|
|
ELSE
|
|
reg2 := ecx
|
|
END;
|
|
IF reg1 # reg2 THEN
|
|
ASSERT(REG.GetReg(R, reg2));
|
|
ASSERT(REG.Exchange(R, reg1, reg2));
|
|
drop
|
|
END;
|
|
drop
|
|
|
|
|CODE.opENDSW:
|
|
|
|
|CODE.opCASEL:
|
|
cmprc(eax, param1);
|
|
jcc(jl, param2)
|
|
|
|
|CODE.opCASER:
|
|
cmprc(eax, param1);
|
|
jcc(jg, param2)
|
|
|
|
|CODE.opCASELR:
|
|
cmprc(eax, param1);
|
|
jcc(jl, param2);
|
|
jcc(jg, cmd.param3)
|
|
|
|
|CODE.opCODE:
|
|
OutByte(param2)
|
|
|
|
|CODE.opGET:
|
|
BinOp(reg1, reg2);
|
|
drop;
|
|
drop;
|
|
|
|
CASE param2 OF
|
|
|1:
|
|
OutByte2(8AH, reg1 * 9); // mov reg1, byte[reg1]
|
|
OutByte2(88H, reg1 * 8 + reg2) // mov byte[reg2], reg1
|
|
|
|
|2:
|
|
OutByte3(66H, 8BH, reg1 * 9); // mov reg1, word[reg1]
|
|
OutByte3(66H, 89H, reg1 * 8 + reg2) // mov word[reg2], reg1
|
|
|
|
|4:
|
|
OutByte2(8BH, reg1 * 9); // mov reg1, dword[reg1]
|
|
OutByte2(89H, reg1 * 8 + reg2) // mov dword[reg2], reg1
|
|
|
|
|8:
|
|
PushAll(0);
|
|
push(reg2);
|
|
push(reg1);
|
|
pushc(8);
|
|
CallRTL(pic, CODE._move)
|
|
|
|
END
|
|
|
|
|CODE.opSAVES:
|
|
UnOp(reg1);
|
|
drop;
|
|
PushAll(0);
|
|
push(reg1);
|
|
|
|
IF pic THEN
|
|
Pic(reg1, BIN.PICDATA, stroffs + param2);
|
|
push(reg1)
|
|
ELSE
|
|
OutByte(068H); // push _data + stroffs + param2
|
|
Reloc(BIN.RDATA, stroffs + param2);
|
|
END;
|
|
|
|
pushc(param1);
|
|
CallRTL(pic, CODE._move)
|
|
|
|
|CODE.opCHKBYTE:
|
|
BinOp(reg1, reg2);
|
|
cmprc(reg1, 256);
|
|
jcc(jb, param1)
|
|
|
|
|CODE.opCHKIDX:
|
|
UnOp(reg1);
|
|
cmprc(reg1, param2);
|
|
jcc(jb, param1)
|
|
|
|
|CODE.opCHKIDX2:
|
|
BinOp(reg1, reg2);
|
|
IF param2 # -1 THEN
|
|
cmprr(reg2, reg1);
|
|
mov(reg1, reg2);
|
|
drop;
|
|
jcc(jb, param1)
|
|
ELSE
|
|
INCL(R.regs, reg1);
|
|
DEC(R.top);
|
|
R.stk[R.top] := reg2
|
|
END
|
|
|
|
|CODE.opLEN:
|
|
n := param2;
|
|
UnOp(reg1);
|
|
drop;
|
|
EXCL(R.regs, reg1);
|
|
|
|
WHILE n > 0 DO
|
|
UnOp(reg2);
|
|
drop;
|
|
DEC(n)
|
|
END;
|
|
|
|
INCL(R.regs, reg1);
|
|
ASSERT(REG.GetReg(R, reg1))
|
|
|
|
|CODE.opINC1:
|
|
UnOp(reg1);
|
|
OutByte2(0FFH, reg1); // inc dword[reg1]
|
|
drop
|
|
|
|
|CODE.opDEC1:
|
|
UnOp(reg1);
|
|
OutByte2(0FFH, 8 + reg1); // dec dword[reg1]
|
|
drop
|
|
|
|
|CODE.opINCC:
|
|
UnOp(reg1);
|
|
n := param2;
|
|
OutByte2(81H + short(n), reg1); OutIntByte(n); // add dword[reg1], n
|
|
drop
|
|
|
|
|CODE.opDECC:
|
|
UnOp(reg1);
|
|
n := param2;
|
|
OutByte2(81H + short(n), 28H + reg1); OutIntByte(n); // sub dword[reg1], n
|
|
drop
|
|
|
|
|CODE.opINC:
|
|
BinOp(reg1, reg2);
|
|
OutByte2(01H, reg1 * 8 + reg2); // add dword[reg2], reg1
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opDEC:
|
|
BinOp(reg1, reg2);
|
|
OutByte2(29H, reg1 * 8 + reg2); // sub dword[reg2], reg1
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opINC1B:
|
|
UnOp(reg1);
|
|
OutByte2(0FEH, reg1); // inc byte[reg1]
|
|
drop
|
|
|
|
|CODE.opDEC1B:
|
|
UnOp(reg1);
|
|
OutByte2(0FEH, 08H + reg1); // dec byte[reg1]
|
|
drop
|
|
|
|
|CODE.opINCCB:
|
|
UnOp(reg1);
|
|
OutByte3(80H, reg1, Byte(param2)); // add byte[reg1], n
|
|
drop
|
|
|
|
|CODE.opDECCB:
|
|
UnOp(reg1);
|
|
OutByte3(80H, 28H + reg1, Byte(param2)); // sub byte[reg1], n
|
|
drop
|
|
|
|
|CODE.opINCB, CODE.opDECB:
|
|
BinOp(reg1, reg2);
|
|
IF cmd.opcode = CODE.opINCB THEN
|
|
OutByte2(00H, reg1 * 8 + reg2) // add byte[reg2], reg1
|
|
ELSE
|
|
OutByte2(28H, reg1 * 8 + reg2) // sub byte[reg2], reg1
|
|
END;
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opMULS:
|
|
BinOp(reg1, reg2);
|
|
OutByte2(21H, 0C0H + reg2 * 8 + reg1); // and reg1, reg2
|
|
drop
|
|
|
|
|CODE.opMULSC:
|
|
UnOp(reg1);
|
|
andrc(reg1, param2)
|
|
|
|
|CODE.opDIVS:
|
|
BinOp(reg1, reg2);
|
|
OutByte2(31H, 0C0H + reg2 * 8 + reg1); // xor reg1, reg2
|
|
drop
|
|
|
|
|CODE.opDIVSC:
|
|
UnOp(reg1);
|
|
OutByte2(81H + short(param2), 0F0H + reg1); // xor reg1, n
|
|
OutIntByte(param2)
|
|
|
|
|CODE.opADDS:
|
|
BinOp(reg1, reg2);
|
|
OutByte2(9H, 0C0H + reg2 * 8 + reg1); // or reg1, reg2
|
|
drop
|
|
|
|
|CODE.opSUBS:
|
|
BinOp(reg1, reg2);
|
|
not(reg2);
|
|
OutByte2(21H, 0C0H + reg2 * 8 + reg1); // and reg1, reg2
|
|
drop
|
|
|
|
|CODE.opADDSL, CODE.opADDSR:
|
|
UnOp(reg1);
|
|
orrc(reg1, param2)
|
|
|
|
|CODE.opSUBSL:
|
|
UnOp(reg1);
|
|
not(reg1);
|
|
andrc(reg1, param2)
|
|
|
|
|CODE.opSUBSR:
|
|
UnOp(reg1);
|
|
andrc(reg1, ORD(-BITS(param2)));
|
|
|
|
|CODE.opUMINS:
|
|
UnOp(reg1);
|
|
not(reg1)
|
|
|
|
|CODE.opLENGTH:
|
|
PushAll(2);
|
|
CallRTL(pic, CODE._length);
|
|
GetRegA
|
|
|
|
|CODE.opLENGTHW:
|
|
PushAll(2);
|
|
CallRTL(pic, CODE._lengthw);
|
|
GetRegA
|
|
|
|
|CODE.opCHR:
|
|
UnOp(reg1);
|
|
andrc(reg1, 255)
|
|
|
|
|CODE.opWCHR:
|
|
UnOp(reg1);
|
|
andrc(reg1, 65535)
|
|
|
|
|CODE.opASR, CODE.opROR, CODE.opLSL, CODE.opLSR:
|
|
UnOp(reg1);
|
|
IF reg1 # ecx THEN
|
|
ASSERT(REG.GetReg(R, ecx));
|
|
ASSERT(REG.Exchange(R, reg1, ecx));
|
|
drop
|
|
END;
|
|
|
|
BinOp(reg1, reg2);
|
|
ASSERT(reg2 = ecx);
|
|
OutByte(0D3H);
|
|
shift(cmd.opcode, reg1); // shift reg1, cl
|
|
drop
|
|
|
|
|CODE.opASR1, CODE.opROR1, CODE.opLSL1, CODE.opLSR1:
|
|
UnOp(reg1);
|
|
IF reg1 # ecx THEN
|
|
ASSERT(REG.GetReg(R, ecx));
|
|
ASSERT(REG.Exchange(R, reg1, ecx));
|
|
drop
|
|
END;
|
|
|
|
reg1 := REG.GetAnyReg(R);
|
|
movrc(reg1, param2);
|
|
BinOp(reg1, reg2);
|
|
ASSERT(reg1 = ecx);
|
|
OutByte(0D3H);
|
|
shift(cmd.opcode, reg2); // shift reg2, cl
|
|
drop;
|
|
drop;
|
|
ASSERT(REG.GetReg(R, reg2))
|
|
|
|
|CODE.opASR2, CODE.opROR2, CODE.opLSL2, CODE.opLSR2:
|
|
UnOp(reg1);
|
|
n := ORD(BITS(param2) * {0..4});
|
|
IF n # 1 THEN
|
|
OutByte(0C1H)
|
|
ELSE
|
|
OutByte(0D1H)
|
|
END;
|
|
shift(cmd.opcode, reg1); // shift reg1, n
|
|
IF n # 1 THEN
|
|
OutByte(n)
|
|
END
|
|
|
|
|CODE.opMIN:
|
|
BinOp(reg1, reg2);
|
|
cmprr(reg1, reg2);
|
|
OutByte2(07EH, 002H); // jle @f
|
|
mov(reg1, reg2); // mov reg1, reg2
|
|
// @@:
|
|
drop
|
|
|
|
|CODE.opMAX:
|
|
BinOp(reg1, reg2);
|
|
cmprr(reg1, reg2);
|
|
OutByte2(07DH, 002H); // jge @f
|
|
mov(reg1, reg2); // mov reg1, reg2
|
|
// @@:
|
|
drop
|
|
|
|
|CODE.opMINC:
|
|
UnOp(reg1);
|
|
cmprc(reg1, param2);
|
|
OutByte2(07EH, 005H); // jle @f
|
|
movrc(reg1, param2); // mov reg1, param2
|
|
// @@:
|
|
|
|
|CODE.opMAXC:
|
|
UnOp(reg1);
|
|
cmprc(reg1, param2);
|
|
OutByte2(07DH, 005H); // jge @f
|
|
movrc(reg1, param2); // mov reg1, param2
|
|
// @@:
|
|
|
|
|CODE.opIN:
|
|
label := NewLabel();
|
|
BinOp(reg1, reg2);
|
|
cmprc(reg1, 32);
|
|
OutByte2(72H, 4); // jb L
|
|
OutByte2(31H, 0C0H + reg1 * 9); // xor reg1, reg1
|
|
jmp(label);
|
|
//L:
|
|
OutByte3(0FH, 0A3H, 0C0H + reg2 + 8 * reg1); // bt reg2, reg1
|
|
setcc(setc, reg1);
|
|
andrc(reg1, 1);
|
|
SetLabel(label);
|
|
drop
|
|
|
|
|CODE.opINR:
|
|
label := NewLabel();
|
|
UnOp(reg1);
|
|
reg2 := REG.GetAnyReg(R);
|
|
cmprc(reg1, 32);
|
|
OutByte2(72H, 4); // jb L
|
|
OutByte2(31H, 0C0H + reg1 * 9); // xor reg1, reg1
|
|
jmp(label);
|
|
//L:
|
|
movrc(reg2, param2);
|
|
OutByte3(0FH, 0A3H, 0C0H + reg2 + 8 * reg1); // bt reg2, reg1
|
|
setcc(setc, reg1);
|
|
andrc(reg1, 1);
|
|
SetLabel(label);
|
|
drop
|
|
|
|
|CODE.opINL:
|
|
UnOp(reg1);
|
|
OutByte3(0FH, 0BAH, 0E0H + reg1); OutByte(param2); // bt reg1, param2
|
|
setcc(setc, reg1);
|
|
andrc(reg1, 1)
|
|
|
|
|CODE.opRSET:
|
|
PushAll(2);
|
|
CallRTL(pic, CODE._set);
|
|
GetRegA
|
|
|
|
|CODE.opRSETR:
|
|
PushAll(1);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._set);
|
|
GetRegA
|
|
|
|
|CODE.opRSETL:
|
|
PushAll(1);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._set2);
|
|
GetRegA
|
|
|
|
|CODE.opRSET1:
|
|
UnOp(reg1);
|
|
PushAll(1);
|
|
push(reg1);
|
|
CallRTL(pic, CODE._set);
|
|
GetRegA
|
|
|
|
|CODE.opINCL, CODE.opEXCL:
|
|
BinOp(reg1, reg2);
|
|
cmprc(reg1, 32);
|
|
OutByte2(73H, 03H); // jnb L
|
|
OutByte(0FH);
|
|
IF cmd.opcode = CODE.opINCL THEN
|
|
OutByte(0ABH) // bts dword[reg2], reg1
|
|
ELSE
|
|
OutByte(0B3H) // btr dword[reg2], reg1
|
|
END;
|
|
OutByte(reg2 + 8 * reg1);
|
|
//L:
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opINCLC:
|
|
UnOp(reg1);
|
|
OutByte3(0FH, 0BAH, 28H + reg1); OutByte(param2); //bts dword[reg1],param2
|
|
drop
|
|
|
|
|CODE.opEXCLC:
|
|
UnOp(reg1);
|
|
OutByte3(0FH, 0BAH, 30H + reg1); OutByte(param2); //btr dword[reg1],param2
|
|
drop
|
|
|
|
|CODE.opDIV:
|
|
PushAll(2);
|
|
CallRTL(pic, CODE._div);
|
|
GetRegA
|
|
|
|
|CODE.opDIVR:
|
|
a := param2;
|
|
IF a > 1 THEN
|
|
n := log2(a)
|
|
ELSIF a < -1 THEN
|
|
n := log2(-a)
|
|
ELSE
|
|
n := -1
|
|
END;
|
|
|
|
IF a = 1 THEN
|
|
|
|
ELSIF a = -1 THEN
|
|
UnOp(reg1);
|
|
neg(reg1)
|
|
ELSE
|
|
IF n > 0 THEN
|
|
UnOp(reg1);
|
|
|
|
IF a < 0 THEN
|
|
reg2 := REG.GetAnyReg(R);
|
|
mov(reg2, reg1);
|
|
IF n # 1 THEN
|
|
OutByte3(0C1H, 0F8H + reg1, n) // sar reg1, n
|
|
ELSE
|
|
OutByte2(0D1H, 0F8H + reg1) // sar reg1, 1
|
|
END;
|
|
OutByte2(29H, 0C0H + reg2 * 8 + reg1); // sub reg1, reg2
|
|
drop
|
|
ELSE
|
|
IF n # 1 THEN
|
|
OutByte3(0C1H, 0F8H + reg1, n) // sar reg1, n
|
|
ELSE
|
|
OutByte2(0D1H, 0F8H + reg1) // sar reg1, 1
|
|
END
|
|
END
|
|
|
|
ELSE
|
|
PushAll(1);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._div);
|
|
GetRegA
|
|
END
|
|
END
|
|
|
|
|CODE.opDIVL:
|
|
PushAll(1);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._div2);
|
|
GetRegA
|
|
|
|
|CODE.opMOD:
|
|
PushAll(2);
|
|
CallRTL(pic, CODE._mod);
|
|
GetRegA
|
|
|
|
|CODE.opMODR:
|
|
a := param2;
|
|
IF a > 1 THEN
|
|
n := log2(a)
|
|
ELSIF a < -1 THEN
|
|
n := log2(-a)
|
|
ELSE
|
|
n := -1
|
|
END;
|
|
|
|
IF ABS(a) = 1 THEN
|
|
UnOp(reg1);
|
|
OutByte2(31H, 0C0H + reg1 * 9) // xor reg1, reg1
|
|
ELSE
|
|
IF n > 0 THEN
|
|
UnOp(reg1);
|
|
andrc(reg1, ABS(a) - 1);
|
|
|
|
IF a < 0 THEN
|
|
test(reg1);
|
|
OutByte(74H); // je @f
|
|
IF isByte(a) THEN
|
|
OutByte(3)
|
|
ELSE
|
|
OutByte(6)
|
|
END;
|
|
addrc(reg1, a)
|
|
// @@:
|
|
END
|
|
|
|
ELSE
|
|
PushAll(1);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._mod);
|
|
GetRegA
|
|
END
|
|
END
|
|
|
|
|CODE.opMODL:
|
|
PushAll(1);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._mod2);
|
|
GetRegA
|
|
|
|
|CODE.opERR:
|
|
CallRTL(pic, CODE._error)
|
|
|
|
|CODE.opABS:
|
|
UnOp(reg1);
|
|
test(reg1);
|
|
OutByte2(07DH, 002H); // jge @f
|
|
neg(reg1); // neg reg1
|
|
// @@:
|
|
|
|
|CODE.opCOPY:
|
|
PushAll(2);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._move2)
|
|
|
|
|CODE.opMOVE:
|
|
PushAll(3);
|
|
CallRTL(pic, CODE._move2)
|
|
|
|
|CODE.opCOPYA:
|
|
PushAll(4);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._arrcpy);
|
|
GetRegA
|
|
|
|
|CODE.opCOPYS:
|
|
PushAll(4);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._strcpy)
|
|
|
|
|CODE.opCOPYS2:
|
|
PushAll(4);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._strcpy2)
|
|
|
|
|CODE.opROT:
|
|
PushAll(0);
|
|
push(esp);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._rot)
|
|
|
|
|CODE.opNEW:
|
|
PushAll(1);
|
|
n := param2 + 8;
|
|
ASSERT(MACHINE.Align(n, 32));
|
|
pushc(n);
|
|
pushc(param1);
|
|
CallRTL(pic, CODE._new)
|
|
|
|
|CODE.opDISP:
|
|
PushAll(1);
|
|
CallRTL(pic, CODE._dispose)
|
|
|
|
|CODE.opEQS .. CODE.opGES:
|
|
PushAll(4);
|
|
pushc(cmd.opcode - CODE.opEQS);
|
|
CallRTL(pic, CODE._strcmp);
|
|
GetRegA
|
|
|
|
|CODE.opEQS2 .. CODE.opGES2:
|
|
PushAll(4);
|
|
pushc(cmd.opcode - CODE.opEQS2);
|
|
CallRTL(pic, CODE._strcmp2);
|
|
GetRegA
|
|
|
|
|CODE.opEQSW .. CODE.opGESW:
|
|
PushAll(4);
|
|
pushc(cmd.opcode - CODE.opEQSW);
|
|
CallRTL(pic, CODE._strcmpw);
|
|
GetRegA
|
|
|
|
|CODE.opEQSW2 .. CODE.opGESW2:
|
|
PushAll(4);
|
|
pushc(cmd.opcode - CODE.opEQSW2);
|
|
CallRTL(pic, CODE._strcmpw2);
|
|
GetRegA
|
|
|
|
|CODE.opEQP, CODE.opNEP, CODE.opEQIP, CODE.opNEIP:
|
|
UnOp(reg1);
|
|
CASE cmd.opcode OF
|
|
|CODE.opEQP, CODE.opNEP:
|
|
IF pic THEN
|
|
reg2 := REG.GetAnyReg(R);
|
|
Pic(reg2, BIN.PICCODE, param1);
|
|
cmprr(reg1, reg2);
|
|
drop
|
|
ELSE
|
|
OutByte2(081H, 0F8H + reg1); // cmp reg1, L
|
|
Reloc(BIN.RCODE, param1)
|
|
END
|
|
|
|
|CODE.opEQIP, CODE.opNEIP:
|
|
IF pic THEN
|
|
reg2 := REG.GetAnyReg(R);
|
|
Pic(reg2, BIN.PICIMP, param1);
|
|
OutByte2(03BH, reg1 * 8 + reg2); //cmp reg1, dword [reg2]
|
|
drop
|
|
ELSE
|
|
OutByte2(3BH, 05H + reg1 * 8); // cmp reg1, dword[L]
|
|
Reloc(BIN.RIMP, param1)
|
|
END
|
|
|
|
END;
|
|
drop;
|
|
reg1 := REG.GetAnyReg(R);
|
|
|
|
CASE cmd.opcode OF
|
|
|CODE.opEQP, CODE.opEQIP: setcc(sete, reg1)
|
|
|CODE.opNEP, CODE.opNEIP: setcc(setne, reg1)
|
|
END;
|
|
|
|
andrc(reg1, 1)
|
|
|
|
|CODE.opPUSHT:
|
|
UnOp(reg1);
|
|
reg2 := REG.GetAnyReg(R);
|
|
OutByte3(8BH, 40H + reg2 * 8 + reg1, 0FCH) // mov reg2, dword[reg1 - 4]
|
|
|
|
|CODE.opISREC:
|
|
PushAll(2);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._isrec);
|
|
GetRegA
|
|
|
|
|CODE.opIS:
|
|
PushAll(1);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._is);
|
|
GetRegA
|
|
|
|
|CODE.opTYPEGR:
|
|
PushAll(1);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._guardrec);
|
|
GetRegA
|
|
|
|
|CODE.opTYPEGP:
|
|
UnOp(reg1);
|
|
PushAll(0);
|
|
push(reg1);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._guard);
|
|
GetRegA
|
|
|
|
|CODE.opTYPEGD:
|
|
UnOp(reg1);
|
|
PushAll(0);
|
|
OutByte3(0FFH, 070H + reg1, 0FCH); // push dword[reg1 - 4]
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._guardrec);
|
|
GetRegA
|
|
|
|
|CODE.opCASET:
|
|
push(ecx);
|
|
push(ecx);
|
|
pushc(param2);
|
|
CallRTL(pic, CODE._guardrec);
|
|
pop(ecx);
|
|
test(eax);
|
|
jcc(jne, param1)
|
|
|
|
|CODE.opPACK:
|
|
BinOp(reg1, reg2);
|
|
push(reg2);
|
|
OutByte3(0DBH, 004H, 024H); // fild dword[esp]
|
|
OutByte2(0DDH, reg1); // fld qword[reg1]
|
|
OutByte2(0D9H, 0FDH); // fscale
|
|
OutByte2(0DDH, 018H + reg1); // fstp qword[reg1]
|
|
OutByte3(0DBH, 01CH, 024H); // fistp dword[esp]
|
|
pop(reg2);
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opPACKC:
|
|
UnOp(reg1);
|
|
pushc(param2);
|
|
OutByte3(0DBH, 004H, 024H); // fild dword[esp]
|
|
OutByte2(0DDH, reg1); // fld qword[reg1]
|
|
OutByte2(0D9H, 0FDH); // fscale
|
|
OutByte2(0DDH, 018H + reg1); // fstp qword[reg1]
|
|
OutByte3(0DBH, 01CH, 024H); // fistp dword[esp]
|
|
pop(reg1);
|
|
drop
|
|
|
|
|CODE.opUNPK:
|
|
BinOp(reg1, reg2);
|
|
OutByte2(0DDH, reg1); // fld qword[reg1]
|
|
OutByte2(0D9H, 0F4H); // fxtract
|
|
OutByte2(0DDH, 018H + reg1); // fstp qword[reg1]
|
|
OutByte2(0DBH, 018H + reg2); // fistp dword[reg2]
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opPUSHF:
|
|
subrc(esp, 8);
|
|
OutByte3(0DDH, 01CH, 024H) // fstp qword[esp]
|
|
|
|
|CODE.opLOADF:
|
|
UnOp(reg1);
|
|
OutByte2(0DDH, reg1); // fld qword[reg1]
|
|
drop
|
|
|
|
|CODE.opCONSTF:
|
|
float := cmd.float;
|
|
IF float = 0.0 THEN
|
|
OutByte2(0D9H, 0EEH) // fldz
|
|
ELSIF float = 1.0 THEN
|
|
OutByte2(0D9H, 0E8H) // fld1
|
|
ELSIF float = -1.0 THEN
|
|
OutByte2(0D9H, 0E8H); // fld1
|
|
OutByte2(0D9H, 0E0H) // fchs
|
|
ELSE
|
|
n := UTILS.splitf(float, a, b);
|
|
pushc(b);
|
|
pushc(a);
|
|
OutByte3(0DDH, 004H, 024H); // fld qword[esp]
|
|
addrc(esp, 8)
|
|
END
|
|
|
|
|CODE.opSAVEF:
|
|
UnOp(reg1);
|
|
OutByte2(0DDH, 018H + reg1); // fstp qword[reg1]
|
|
drop
|
|
|
|
|CODE.opADDF, CODE.opADDFI:
|
|
OutByte2(0DEH, 0C1H) // faddp st1, st
|
|
|
|
|CODE.opSUBF:
|
|
OutByte2(0DEH, 0E9H) // fsubp st1, st
|
|
|
|
|CODE.opSUBFI:
|
|
OutByte2(0DEH, 0E1H) // fsubrp st1, st
|
|
|
|
|CODE.opMULF:
|
|
OutByte2(0DEH, 0C9H) // fmulp st1, st
|
|
|
|
|CODE.opDIVF:
|
|
OutByte2(0DEH, 0F9H) // fdivp st1, st
|
|
|
|
|CODE.opDIVFI:
|
|
OutByte2(0DEH, 0F1H) // fdivrp st1, st
|
|
|
|
|CODE.opUMINF:
|
|
OutByte2(0D9H, 0E0H) // fchs
|
|
|
|
|CODE.opFABS:
|
|
OutByte2(0D9H, 0E1H) // fabs
|
|
|
|
|CODE.opFLT:
|
|
UnOp(reg1);
|
|
push(reg1);
|
|
OutByte3(0DBH, 004H, 024H); // fild dword[esp]
|
|
pop(reg1);
|
|
drop
|
|
|
|
|CODE.opFLOOR:
|
|
reg1 := REG.GetAnyReg(R);
|
|
subrc(esp, 8);
|
|
OutByte2(09BH, 0D9H); OutByte3(07CH, 024H, 004H); // fstcw word[esp+4]
|
|
OutByte2(09BH, 0D9H); OutByte3(07CH, 024H, 006H); // fstcw word[esp+6]
|
|
OutByte2(066H, 081H); OutByte3(064H, 024H, 004H); OutWord(0F3FFH); // and word[esp+4], 1111001111111111b
|
|
OutByte2(066H, 081H); OutByte3(04CH, 024H, 004H); OutWord(00400H); // or word[esp+4], 0000010000000000b
|
|
OutByte2(0D9H, 06CH); OutByte2(024H, 004H); // fldcw word[esp+4]
|
|
OutByte2(0D9H, 0FCH); // frndint
|
|
OutByte3(0DBH, 01CH, 024H); // fistp dword[esp]
|
|
pop(reg1);
|
|
OutByte2(0D9H, 06CH); OutByte2(024H, 002H); // fldcw word[esp+2]
|
|
addrc(esp, 4)
|
|
|
|
|CODE.opEQF, CODE.opEQFI:
|
|
GetRegA;
|
|
OutByte2(0DAH, 0E9H); // fucompp
|
|
OutByte3(09BH, 0DFH, 0E0H); // fstsw ax
|
|
OutByte(09EH); // sahf
|
|
movrc(eax, 0);
|
|
OutByte2(07AH, 003H); // jp L
|
|
setcc(sete, al)
|
|
// L:
|
|
|
|
|CODE.opNEF, CODE.opNEFI:
|
|
GetRegA;
|
|
OutByte2(0DAH, 0E9H); // fucompp
|
|
OutByte3(09BH, 0DFH, 0E0H); // fstsw ax
|
|
OutByte(09EH); // sahf
|
|
movrc(eax, 0);
|
|
OutByte2(07AH, 003H); // jp L
|
|
setcc(setne, al)
|
|
// L:
|
|
|
|
|CODE.opLTF, CODE.opGTFI:
|
|
GetRegA;
|
|
OutByte2(0DAH, 0E9H); // fucompp
|
|
OutByte3(09BH, 0DFH, 0E0H); // fstsw ax
|
|
OutByte(09EH); // sahf
|
|
movrc(eax, 0);
|
|
OutByte2(07AH, 00EH); // jp L
|
|
setcc(setc, al);
|
|
setcc(sete, ah);
|
|
test(eax);
|
|
setcc(sete, al);
|
|
andrc(eax, 1)
|
|
// L:
|
|
|
|
|CODE.opGTF, CODE.opLTFI:
|
|
GetRegA;
|
|
OutByte2(0DAH, 0E9H); // fucompp
|
|
OutByte3(09BH, 0DFH, 0E0H); // fstsw ax
|
|
OutByte(09EH); // sahf
|
|
movrc(eax, 0);
|
|
OutByte2(07AH, 00FH); // jp L
|
|
setcc(setc, al);
|
|
setcc(sete, ah);
|
|
cmprc(eax, 1);
|
|
setcc(sete, al);
|
|
andrc(eax, 1)
|
|
// L:
|
|
|
|
|CODE.opLEF, CODE.opGEFI:
|
|
GetRegA;
|
|
OutByte2(0DAH, 0E9H); // fucompp
|
|
OutByte3(09BH, 0DFH, 0E0H); // fstsw ax
|
|
OutByte(09EH); // sahf
|
|
movrc(eax, 0);
|
|
OutByte2(07AH, 003H); // jp L
|
|
setcc(setnc, al)
|
|
// L:
|
|
|
|
|CODE.opGEF, CODE.opLEFI:
|
|
GetRegA;
|
|
OutByte2(0DAH, 0E9H); // fucompp
|
|
OutByte3(09BH, 0DFH, 0E0H); // fstsw ax
|
|
OutByte(09EH); // sahf
|
|
movrc(eax, 0);
|
|
OutByte2(07AH, 010H); // jp L
|
|
setcc(setc, al);
|
|
setcc(sete, ah);
|
|
OutByte2(000H, 0E0H); // add al,ah
|
|
OutByte2(03CH, 001H); // cmp al,1
|
|
setcc(sete, al);
|
|
andrc(eax, 1)
|
|
// L:
|
|
|
|
|CODE.opINF:
|
|
pushc(7FF00000H);
|
|
pushc(0);
|
|
OutByte3(0DDH, 004H, 024H); // fld qword[esp]
|
|
addrc(esp, 8)
|
|
|
|
|CODE.opLADR_UNPK:
|
|
n := param2 * 4;
|
|
reg1 := REG.GetAnyReg(R);
|
|
OutByte2(8DH, 45H + reg1 * 8 + long(n)); // lea reg1, dword[ebp + n]
|
|
OutIntByte(n);
|
|
BinOp(reg1, reg2);
|
|
OutByte2(0DDH, reg1); // fld qword[reg1]
|
|
OutByte2(0D9H, 0F4H); // fxtract
|
|
OutByte2(0DDH, 018H + reg1); // fstp qword[reg1]
|
|
OutByte2(0DBH, 018H + reg2); // fistp dword[reg2]
|
|
drop;
|
|
drop
|
|
|
|
|CODE.opSADR_PARAM:
|
|
IF pic THEN
|
|
reg1 := REG.GetAnyReg(R);
|
|
Pic(reg1, BIN.PICDATA, stroffs + param2);
|
|
push(reg1);
|
|
drop
|
|
ELSE
|
|
OutByte(068H); // push _data + stroffs + param2
|
|
Reloc(BIN.RDATA, stroffs + param2)
|
|
END
|
|
|
|
|CODE.opVADR_PARAM:
|
|
n := param2 * 4;
|
|
OutByte2(0FFH, 75H + long(n)); // push dword[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opCONST_PARAM:
|
|
pushc(param2)
|
|
|
|
|CODE.opGLOAD32_PARAM:
|
|
IF pic THEN
|
|
reg1 := REG.GetAnyReg(R);
|
|
Pic(reg1, BIN.PICBSS, param2);
|
|
OutByte2(0FFH, 30H + reg1); // push dword[reg1]
|
|
drop
|
|
ELSE
|
|
OutByte2(0FFH, 035H); // push dword[_bss + param2]
|
|
Reloc(BIN.RBSS, param2)
|
|
END
|
|
|
|
|CODE.opLLOAD32_PARAM:
|
|
n := param2 * 4;
|
|
OutByte2(0FFH, 75H + long(n)); // push dword[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opLOAD32_PARAM:
|
|
UnOp(reg1);
|
|
OutByte2(0FFH, 30H + reg1); // push dword[reg1]
|
|
drop
|
|
|
|
|CODE.opGADR_SAVEC:
|
|
IF pic THEN
|
|
reg1 := REG.GetAnyReg(R);
|
|
Pic(reg1, BIN.PICBSS, param1);
|
|
OutByte2(0C7H, reg1); // mov dword[reg1], param2
|
|
OutInt(param2);
|
|
drop
|
|
ELSE
|
|
OutByte2(0C7H, 05H); // mov dword[_bss + param2], param2
|
|
Reloc(BIN.RBSS, param1);
|
|
OutInt(param2)
|
|
END
|
|
|
|
|CODE.opLADR_SAVEC:
|
|
n := param1 * 4;
|
|
OutByte2(0C7H, 45H + long(n)); // mov dword[ebp + n], param2
|
|
OutIntByte(n);
|
|
OutInt(param2)
|
|
|
|
|CODE.opLADR_SAVE:
|
|
n := param2 * 4;
|
|
UnOp(reg1);
|
|
OutByte2(89H, 45H + reg1 * 8 + long(n)); // mov dword[ebp + n], reg1
|
|
OutIntByte(n);
|
|
drop
|
|
|
|
|CODE.opLADR_INC1:
|
|
n := param2 * 4;
|
|
OutByte2(0FFH, 45H + long(n)); // inc dword[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opLADR_DEC1:
|
|
n := param2 * 4;
|
|
OutByte2(0FFH, 4DH + long(n)); // dec dword[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opLADR_INCC:
|
|
n := param1 * 4;
|
|
OutByte2(81H + short(param2), 45H + long(n)); // add dword[ebp + n], param2
|
|
OutIntByte(n);
|
|
OutIntByte(param2)
|
|
|
|
|CODE.opLADR_DECC:
|
|
n := param1 * 4;
|
|
OutByte2(81H + short(param2), 6DH + long(n)); // sub dword[ebp + n], param2
|
|
OutIntByte(n);
|
|
OutIntByte(param2)
|
|
|
|
|CODE.opLADR_INC1B:
|
|
n := param2 * 4;
|
|
OutByte2(0FEH, 45H + long(n)); // inc byte[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opLADR_DEC1B:
|
|
n := param2 * 4;
|
|
OutByte2(0FEH, 4DH + long(n)); // dec byte[ebp + n]
|
|
OutIntByte(n)
|
|
|
|
|CODE.opLADR_INCCB:
|
|
n := param1 * 4;
|
|
OutByte2(80H, 45H + long(n)); // add byte[ebp + n], param2
|
|
OutIntByte(n);
|
|
OutByte(param2 MOD 256)
|
|
|
|
|CODE.opLADR_DECCB:
|
|
n := param1 * 4;
|
|
OutByte2(80H, 6DH + long(n)); // sub byte[ebp + n], param2
|
|
OutIntByte(n);
|
|
OutByte(param2 MOD 256)
|
|
|
|
|CODE.opLADR_INC:
|
|
n := param2 * 4;
|
|
UnOp(reg1);
|
|
OutByte2(01H, 45H + long(n) + reg1 * 8); // add dword[ebp + n], reg1
|
|
OutIntByte(n);
|
|
drop
|
|
|
|
|CODE.opLADR_DEC:
|
|
n := param2 * 4;
|
|
UnOp(reg1);
|
|
OutByte2(29H, 45H + long(n) + reg1 * 8); // sub dword[ebp + n], reg1
|
|
OutIntByte(n);
|
|
drop
|
|
|
|
|CODE.opLADR_INCB:
|
|
n := param2 * 4;
|
|
UnOp(reg1);
|
|
OutByte2(00H, 45H + long(n) + reg1 * 8); // add byte[ebp + n], reg1
|
|
OutIntByte(n);
|
|
drop
|
|
|
|
|CODE.opLADR_DECB:
|
|
n := param2 * 4;
|
|
UnOp(reg1);
|
|
OutByte2(28H, 45H + long(n) + reg1 * 8); // sub byte[ebp + n], reg1
|
|
OutIntByte(n);
|
|
drop
|
|
|
|
|CODE.opLADR_INCL, CODE.opLADR_EXCL:
|
|
n := param2 * 4;
|
|
UnOp(reg1);
|
|
cmprc(reg1, 32);
|
|
label := NewLabel();
|
|
jcc(jnb, label);
|
|
OutByte3(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opLADR_EXCL), 45H + long(n) + reg1 * 8); // bts(r) dword[ebp + n], reg1
|
|
OutIntByte(n);
|
|
SetLabel(label);
|
|
drop
|
|
|
|
|CODE.opLADR_INCLC, CODE.opLADR_EXCLC:
|
|
n := param1 * 4;
|
|
OutByte3(0FH, 0BAH, 6DH + long(n) + 8 * ORD(cmd.opcode = CODE.opLADR_EXCLC)); // bts(r) dword[ebp + n], param2
|
|
OutIntByte(n);
|
|
OutByte(param2)
|
|
|
|
|CODE.opLOOP, CODE.opENDLOOP:
|
|
|
|
END;
|
|
|
|
cmd := cmd.next(COMMAND)
|
|
END;
|
|
|
|
ASSERT(R.pushed = 0);
|
|
ASSERT(R.top = -1)
|
|
|
|
END translate;
|
|
|
|
|
|
PROCEDURE prolog (code: CODE.CODES; pic: BOOLEAN; target, stack, dllinit, dllret: INTEGER);
|
|
VAR
|
|
reg1, entry, tcount, dcount: INTEGER;
|
|
|
|
BEGIN
|
|
|
|
entry := NewLabel();
|
|
SetLabel(entry);
|
|
|
|
IF target = mConst.Target_iDLL THEN
|
|
push(ebp);
|
|
mov(ebp, esp);
|
|
OutByte3(0FFH, 75H, 16); // push dword[ebp+16]
|
|
OutByte3(0FFH, 75H, 12); // push dword[ebp+12]
|
|
OutByte3(0FFH, 75H, 8); // push dword[ebp+8]
|
|
CallRTL(pic, CODE._dllentry);
|
|
test(eax);
|
|
jcc(je, dllret)
|
|
ELSIF target = mConst.Target_iObject THEN
|
|
SetLabel(dllinit)
|
|
END;
|
|
|
|
IF target = mConst.Target_iKolibri THEN
|
|
reg1 := REG.GetAnyReg(R);
|
|
Pic(reg1, BIN.IMPTAB, 0);
|
|
push(reg1); // push IMPORT
|
|
drop
|
|
ELSIF target = mConst.Target_iObject THEN
|
|
OutByte(68H); // push IMPORT
|
|
Reloc(BIN.IMPTAB, 0)
|
|
ELSIF target = mConst.Target_iELF32 THEN
|
|
push(esp)
|
|
ELSE
|
|
pushc(0)
|
|
END;
|
|
|
|
IF pic THEN
|
|
reg1 := REG.GetAnyReg(R);
|
|
Pic(reg1, BIN.PICCODE, entry);
|
|
push(reg1); // push CODE
|
|
drop
|
|
ELSE
|
|
OutByte(68H); // push CODE
|
|
Reloc(BIN.RCODE, entry)
|
|
END;
|
|
|
|
IF pic THEN
|
|
reg1 := REG.GetAnyReg(R);
|
|
Pic(reg1, BIN.PICDATA, 0);
|
|
push(reg1); // push _data
|
|
drop
|
|
ELSE
|
|
OutByte(68H); // push _data
|
|
Reloc(BIN.RDATA, 0)
|
|
END;
|
|
|
|
tcount := CHL.Length(code.types);
|
|
dcount := CHL.Length(code.data);
|
|
|
|
pushc(tcount);
|
|
|
|
IF pic THEN
|
|
reg1 := REG.GetAnyReg(R);
|
|
Pic(reg1, BIN.PICDATA, tcount * 4 + dcount);
|
|
push(reg1); // push _data + tcount * 4 + dcount
|
|
drop
|
|
ELSE
|
|
OutByte(68H); // push _data
|
|
Reloc(BIN.RDATA, tcount * 4 + dcount)
|
|
END;
|
|
|
|
CallRTL(pic, CODE._init)
|
|
END prolog;
|
|
|
|
|
|
PROCEDURE epilog (code: CODE.CODES; pic: BOOLEAN; modname: ARRAY OF CHAR; target, stack, ver, dllinit, dllret: INTEGER);
|
|
VAR
|
|
i, n: INTEGER;
|
|
exp: CODE.EXPORT_PROC;
|
|
path, name, ext: PATHS.PATH;
|
|
|
|
tcount, dcount: INTEGER;
|
|
|
|
|
|
PROCEDURE import (imp: LISTS.LIST);
|
|
VAR
|
|
lib: CODE.IMPORT_LIB;
|
|
proc: CODE.IMPORT_PROC;
|
|
|
|
BEGIN
|
|
|
|
lib := imp.first(CODE.IMPORT_LIB);
|
|
WHILE lib # NIL DO
|
|
BIN.Import(program, lib.name, 0);
|
|
proc := lib.procs.first(CODE.IMPORT_PROC);
|
|
WHILE proc # NIL DO
|
|
BIN.Import(program, proc.name, proc.label);
|
|
proc := proc.next(CODE.IMPORT_PROC)
|
|
END;
|
|
lib := lib.next(CODE.IMPORT_LIB)
|
|
END
|
|
|
|
END import;
|
|
|
|
|
|
BEGIN
|
|
|
|
IF target IN {mConst.Target_iConsole, mConst.Target_iGUI, mConst.Target_iKolibri, mConst.Target_iELF32} THEN
|
|
pushc(0);
|
|
CallRTL(pic, CODE._exit);
|
|
ELSIF target = mConst.Target_iDLL THEN
|
|
SetLabel(dllret);
|
|
movrc(eax, 1);
|
|
OutByte(0C9H); // leave
|
|
OutByte3(0C2H, 0CH, 0) // ret 12
|
|
ELSIF target = mConst.Target_iObject THEN
|
|
movrc(eax, 1);
|
|
OutByte(0C3H) // ret
|
|
END;
|
|
|
|
fixup;
|
|
|
|
tcount := CHL.Length(code.types);
|
|
dcount := CHL.Length(code.data);
|
|
|
|
FOR i := 0 TO tcount - 1 DO
|
|
BIN.PutData32LE(program, CHL.GetInt(code.types, i))
|
|
END;
|
|
|
|
FOR i := 0 TO dcount - 1 DO
|
|
BIN.PutData(program, CHL.GetByte(code.data, i))
|
|
END;
|
|
|
|
program.modname := CHL.Length(program.data);
|
|
|
|
PATHS.split(modname, path, name, ext);
|
|
BIN.PutDataStr(program, name);
|
|
BIN.PutDataStr(program, ext);
|
|
BIN.PutData(program, 0);
|
|
|
|
IF target = mConst.Target_iObject THEN
|
|
BIN.Export(program, "lib_init", dllinit);
|
|
END;
|
|
|
|
exp := code.export.first(CODE.EXPORT_PROC);
|
|
WHILE exp # NIL DO
|
|
BIN.Export(program, exp.name, exp.label);
|
|
exp := exp.next(CODE.EXPORT_PROC)
|
|
END;
|
|
|
|
import(code.import);
|
|
|
|
n := code.dmin - CHL.Length(code.data);
|
|
IF n > 0 THEN
|
|
INC(code.bss, n)
|
|
END;
|
|
|
|
BIN.SetParams(program, MAX(code.bss, 4), stack * (1024 * 1024), WCHR(ver DIV 65536), WCHR(ver MOD 65536));
|
|
|
|
END epilog;
|
|
|
|
|
|
PROCEDURE CodeGen* (code: CODE.CODES; outname: ARRAY OF CHAR; target, stack, base, ver: INTEGER; pic: BOOLEAN);
|
|
VAR
|
|
dllret, dllinit: INTEGER;
|
|
|
|
BEGIN
|
|
|
|
CodeList := LISTS.create(NIL);
|
|
|
|
program := BIN.create(code.lcount);
|
|
|
|
dllinit := NewLabel();
|
|
dllret := NewLabel();
|
|
|
|
IF target = mConst.Target_iObject THEN
|
|
pic := FALSE
|
|
END;
|
|
|
|
IF target IN {mConst.Target_iConsole, mConst.Target_iGUI, mConst.Target_iDLL, mConst.Target_iELF32} THEN
|
|
pic := TRUE
|
|
END;
|
|
|
|
R := REG.Create(push, pop, mov, xchg, NIL, NIL, {eax, ecx, edx}, {});
|
|
|
|
prolog(code, pic, target, stack, dllinit, dllret);
|
|
translate(code, pic, CHL.Length(code.types) * 4);
|
|
epilog(code, pic, outname, target, stack, ver, dllinit, dllret);
|
|
|
|
BIN.fixup(program);
|
|
|
|
IF target IN {mConst.Target_iConsole, mConst.Target_iGUI, mConst.Target_iDLL} THEN
|
|
PE32.write(program, outname, base, target = mConst.Target_iConsole, target = mConst.Target_iDLL, FALSE)
|
|
ELSIF target = mConst.Target_iKolibri THEN
|
|
KOS.write(program, outname)
|
|
ELSIF target = mConst.Target_iObject THEN
|
|
MSCOFF.write(program, outname, ver)
|
|
ELSIF target = mConst.Target_iELF32 THEN
|
|
ELF.write(program, outname, FALSE)
|
|
END
|
|
|
|
END CodeGen;
|
|
|
|
|
|
PROCEDURE SetProgram* (prog: BIN.PROGRAM);
|
|
BEGIN
|
|
program := prog;
|
|
CodeList := LISTS.create(NIL)
|
|
END SetProgram;
|
|
|
|
|
|
END X86. |