396 lines
7.7 KiB
Plaintext
396 lines
7.7 KiB
Plaintext
|
(*
|
||
|
BSD 2-Clause License
|
||
|
|
||
|
Copyright (c) 2018, 2019, Anton Krotov
|
||
|
All rights reserved.
|
||
|
*)
|
||
|
|
||
|
MODULE BIN;
|
||
|
|
||
|
IMPORT LISTS, MACHINE, CHL := CHUNKLISTS, ARITH, UTILS;
|
||
|
|
||
|
|
||
|
CONST
|
||
|
|
||
|
RCODE* = 1;
|
||
|
RDATA* = 2;
|
||
|
RBSS* = 3;
|
||
|
RIMP* = 4;
|
||
|
|
||
|
PICCODE* = 5;
|
||
|
PICDATA* = 6;
|
||
|
PICBSS* = 7;
|
||
|
PICIMP* = 8;
|
||
|
|
||
|
IMPTAB* = 9;
|
||
|
|
||
|
|
||
|
TYPE
|
||
|
|
||
|
RELOC* = POINTER TO RECORD (LISTS.ITEM)
|
||
|
|
||
|
opcode*: INTEGER;
|
||
|
offset*: INTEGER
|
||
|
|
||
|
END;
|
||
|
|
||
|
IMPRT* = POINTER TO RECORD (LISTS.ITEM)
|
||
|
|
||
|
nameoffs*: INTEGER;
|
||
|
label*: INTEGER;
|
||
|
|
||
|
OriginalFirstThunk*,
|
||
|
FirstThunk*: INTEGER
|
||
|
|
||
|
END;
|
||
|
|
||
|
EXPRT* = POINTER TO RECORD (LISTS.ITEM)
|
||
|
|
||
|
nameoffs*: INTEGER;
|
||
|
label*: INTEGER
|
||
|
|
||
|
END;
|
||
|
|
||
|
PROGRAM* = POINTER TO RECORD
|
||
|
|
||
|
code*: CHL.BYTELIST;
|
||
|
data*: CHL.BYTELIST;
|
||
|
labels: CHL.INTLIST;
|
||
|
bss*: INTEGER;
|
||
|
stack*: INTEGER;
|
||
|
vmajor*,
|
||
|
vminor*: WCHAR;
|
||
|
modname*: INTEGER;
|
||
|
import*: CHL.BYTELIST;
|
||
|
export*: CHL.BYTELIST;
|
||
|
rel_list*: LISTS.LIST;
|
||
|
imp_list*: LISTS.LIST;
|
||
|
exp_list*: LISTS.LIST
|
||
|
|
||
|
END;
|
||
|
|
||
|
|
||
|
PROCEDURE create* (NumberOfLabels: INTEGER): PROGRAM;
|
||
|
VAR
|
||
|
program: PROGRAM;
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
NEW(program);
|
||
|
|
||
|
program.bss := 0;
|
||
|
|
||
|
program.labels := CHL.CreateIntList();
|
||
|
FOR i := 0 TO NumberOfLabels - 1 DO
|
||
|
CHL.PushInt(program.labels, 0)
|
||
|
END;
|
||
|
|
||
|
program.rel_list := LISTS.create(NIL);
|
||
|
program.imp_list := LISTS.create(NIL);
|
||
|
program.exp_list := LISTS.create(NIL);
|
||
|
|
||
|
program.data := CHL.CreateByteList();
|
||
|
program.code := CHL.CreateByteList();
|
||
|
program.import := CHL.CreateByteList();
|
||
|
program.export := CHL.CreateByteList()
|
||
|
|
||
|
RETURN program
|
||
|
END create;
|
||
|
|
||
|
|
||
|
PROCEDURE SetParams* (program: PROGRAM; bss, stack: INTEGER; vmajor, vminor: WCHAR);
|
||
|
BEGIN
|
||
|
program.bss := bss;
|
||
|
program.stack := stack;
|
||
|
program.vmajor := vmajor;
|
||
|
program.vminor := vminor
|
||
|
END SetParams;
|
||
|
|
||
|
|
||
|
PROCEDURE PutReloc* (program: PROGRAM; opcode: INTEGER);
|
||
|
VAR
|
||
|
cmd: RELOC;
|
||
|
|
||
|
BEGIN
|
||
|
NEW(cmd);
|
||
|
cmd.opcode := opcode;
|
||
|
cmd.offset := CHL.Length(program.code);
|
||
|
LISTS.push(program.rel_list, cmd)
|
||
|
END PutReloc;
|
||
|
|
||
|
|
||
|
PROCEDURE PutData* (program: PROGRAM; b: BYTE);
|
||
|
BEGIN
|
||
|
CHL.PushByte(program.data, b)
|
||
|
END PutData;
|
||
|
|
||
|
|
||
|
PROCEDURE get32le* (array: CHL.BYTELIST; idx: INTEGER): INTEGER;
|
||
|
VAR
|
||
|
i: INTEGER;
|
||
|
x: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
x := 0;
|
||
|
|
||
|
FOR i := 3 TO 0 BY -1 DO
|
||
|
x := LSL(x, 8) + CHL.GetByte(array, idx + i)
|
||
|
END;
|
||
|
|
||
|
IF UTILS.bit_depth = 64 THEN
|
||
|
x := MACHINE.Int32To64(x)
|
||
|
END
|
||
|
|
||
|
RETURN x
|
||
|
END get32le;
|
||
|
|
||
|
|
||
|
PROCEDURE put32le* (array: CHL.BYTELIST; idx: INTEGER; x: INTEGER);
|
||
|
VAR
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
FOR i := 0 TO 3 DO
|
||
|
CHL.SetByte(array, idx + i, MACHINE.Byte(x, i))
|
||
|
END
|
||
|
END put32le;
|
||
|
|
||
|
|
||
|
PROCEDURE PutData32LE* (program: PROGRAM; x: INTEGER);
|
||
|
VAR
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
FOR i := 0 TO 3 DO
|
||
|
CHL.PushByte(program.data, MACHINE.Byte(x, i))
|
||
|
END
|
||
|
END PutData32LE;
|
||
|
|
||
|
|
||
|
PROCEDURE PutData64LE* (program: PROGRAM; x: INTEGER);
|
||
|
VAR
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
FOR i := 0 TO 7 DO
|
||
|
CHL.PushByte(program.data, MACHINE.Byte(x, i))
|
||
|
END
|
||
|
END PutData64LE;
|
||
|
|
||
|
|
||
|
PROCEDURE PutDataStr* (program: PROGRAM; s: ARRAY OF CHAR);
|
||
|
VAR
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
i := 0;
|
||
|
WHILE s[i] # 0X DO
|
||
|
PutData(program, ORD(s[i]));
|
||
|
INC(i)
|
||
|
END
|
||
|
END PutDataStr;
|
||
|
|
||
|
|
||
|
PROCEDURE PutCode* (program: PROGRAM; b: BYTE);
|
||
|
BEGIN
|
||
|
CHL.PushByte(program.code, b)
|
||
|
END PutCode;
|
||
|
|
||
|
|
||
|
PROCEDURE PutCode32LE* (program: PROGRAM; x: INTEGER);
|
||
|
VAR
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
FOR i := 0 TO 3 DO
|
||
|
CHL.PushByte(program.code, MACHINE.Byte(x, i))
|
||
|
END
|
||
|
END PutCode32LE;
|
||
|
|
||
|
|
||
|
PROCEDURE SetLabel* (program: PROGRAM; label, offset: INTEGER);
|
||
|
BEGIN
|
||
|
CHL.SetInt(program.labels, label, offset)
|
||
|
END SetLabel;
|
||
|
|
||
|
|
||
|
PROCEDURE Import* (program: PROGRAM; name: ARRAY OF CHAR; label: INTEGER);
|
||
|
VAR
|
||
|
imp: IMPRT;
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
CHL.PushByte(program.import, 0);
|
||
|
CHL.PushByte(program.import, 0);
|
||
|
|
||
|
IF ODD(CHL.Length(program.import)) THEN
|
||
|
CHL.PushByte(program.import, 0)
|
||
|
END;
|
||
|
|
||
|
NEW(imp);
|
||
|
imp.nameoffs := CHL.Length(program.import);
|
||
|
imp.label := label;
|
||
|
LISTS.push(program.imp_list, imp);
|
||
|
|
||
|
i := 0;
|
||
|
WHILE name[i] # 0X DO
|
||
|
CHL.PushByte(program.import, ORD(name[i]));
|
||
|
INC(i)
|
||
|
END;
|
||
|
CHL.PushByte(program.import, 0)
|
||
|
END Import;
|
||
|
|
||
|
|
||
|
PROCEDURE less (bytes: CHL.BYTELIST; a, b: EXPRT): BOOLEAN;
|
||
|
VAR
|
||
|
i, j: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
i := a.nameoffs;
|
||
|
j := b.nameoffs;
|
||
|
|
||
|
WHILE (CHL.GetByte(bytes, i) # 0) & (CHL.GetByte(bytes, j) # 0) &
|
||
|
(CHL.GetByte(bytes, i) = CHL.GetByte(bytes, j)) DO
|
||
|
INC(i);
|
||
|
INC(j)
|
||
|
END
|
||
|
|
||
|
RETURN CHL.GetByte(bytes, i) < CHL.GetByte(bytes, j)
|
||
|
END less;
|
||
|
|
||
|
|
||
|
PROCEDURE Export* (program: PROGRAM; name: ARRAY OF CHAR; label: INTEGER);
|
||
|
VAR
|
||
|
exp, cur: EXPRT;
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
NEW(exp);
|
||
|
exp.nameoffs := CHL.Length(program.export);
|
||
|
exp.label := CHL.GetInt(program.labels, label);
|
||
|
|
||
|
i := 0;
|
||
|
WHILE name[i] # 0X DO
|
||
|
CHL.PushByte(program.export, ORD(name[i]));
|
||
|
INC(i)
|
||
|
END;
|
||
|
CHL.PushByte(program.export, 0);
|
||
|
|
||
|
cur := program.exp_list.first(EXPRT);
|
||
|
WHILE (cur # NIL) & less(program.export, cur, exp) DO
|
||
|
cur := cur.next(EXPRT)
|
||
|
END;
|
||
|
|
||
|
IF cur # NIL THEN
|
||
|
IF cur.prev # NIL THEN
|
||
|
LISTS.insert(program.exp_list, cur.prev, exp)
|
||
|
ELSE
|
||
|
LISTS.insertL(program.exp_list, cur, exp)
|
||
|
END
|
||
|
ELSE
|
||
|
LISTS.push(program.exp_list, exp)
|
||
|
END
|
||
|
|
||
|
END Export;
|
||
|
|
||
|
|
||
|
PROCEDURE GetIProc* (program: PROGRAM; n: INTEGER): IMPRT;
|
||
|
VAR
|
||
|
import: IMPRT;
|
||
|
res: IMPRT;
|
||
|
|
||
|
BEGIN
|
||
|
import := program.imp_list.first(IMPRT);
|
||
|
|
||
|
res := NIL;
|
||
|
WHILE (import # NIL) & (n >= 0) DO
|
||
|
IF import.label # 0 THEN
|
||
|
res := import;
|
||
|
DEC(n)
|
||
|
END;
|
||
|
import := import.next(IMPRT)
|
||
|
END;
|
||
|
|
||
|
ASSERT(n = -1)
|
||
|
RETURN res
|
||
|
END GetIProc;
|
||
|
|
||
|
|
||
|
PROCEDURE GetLabel* (program: PROGRAM; label: INTEGER): INTEGER;
|
||
|
RETURN CHL.GetInt(program.labels, label)
|
||
|
END GetLabel;
|
||
|
|
||
|
|
||
|
PROCEDURE NewLabel* (program: PROGRAM);
|
||
|
BEGIN
|
||
|
CHL.PushInt(program.labels, 0)
|
||
|
END NewLabel;
|
||
|
|
||
|
|
||
|
PROCEDURE fixup* (program: PROGRAM);
|
||
|
VAR
|
||
|
rel: RELOC;
|
||
|
imp: IMPRT;
|
||
|
nproc: INTEGER;
|
||
|
L: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
|
||
|
nproc := 0;
|
||
|
imp := program.imp_list.first(IMPRT);
|
||
|
WHILE imp # NIL DO
|
||
|
IF imp.label # 0 THEN
|
||
|
CHL.SetInt(program.labels, imp.label, nproc);
|
||
|
INC(nproc)
|
||
|
END;
|
||
|
imp := imp.next(IMPRT)
|
||
|
END;
|
||
|
|
||
|
rel := program.rel_list.first(RELOC);
|
||
|
WHILE rel # NIL DO
|
||
|
|
||
|
IF rel.opcode IN {RIMP, PICIMP} THEN
|
||
|
L := get32le(program.code, rel.offset);
|
||
|
put32le(program.code, rel.offset, GetLabel(program, L))
|
||
|
END;
|
||
|
|
||
|
rel := rel.next(RELOC)
|
||
|
END
|
||
|
|
||
|
END fixup;
|
||
|
|
||
|
|
||
|
PROCEDURE InitArray* (VAR array: ARRAY OF BYTE; VAR idx: INTEGER; hex: ARRAY OF CHAR);
|
||
|
VAR
|
||
|
i, k: INTEGER;
|
||
|
|
||
|
|
||
|
PROCEDURE hexdgt (dgt: CHAR): INTEGER;
|
||
|
VAR
|
||
|
res: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
IF dgt < "A" THEN
|
||
|
res := ORD(dgt) - ORD("0")
|
||
|
ELSE
|
||
|
res := ORD(dgt) - ORD("A") + 10
|
||
|
END
|
||
|
|
||
|
RETURN res
|
||
|
END hexdgt;
|
||
|
|
||
|
|
||
|
BEGIN
|
||
|
k := LENGTH(hex);
|
||
|
ASSERT(~ODD(k));
|
||
|
k := k DIV 2;
|
||
|
|
||
|
FOR i := 0 TO k - 1 DO
|
||
|
array[i + idx] := hexdgt(hex[2 * i]) * 16 + hexdgt(hex[2 * i + 1])
|
||
|
END;
|
||
|
|
||
|
idx := idx + k
|
||
|
END InitArray;
|
||
|
|
||
|
|
||
|
END BIN.
|