Subversion Repositories Kolibri OS

Rev

Rev 7983 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2018-2020, Anton Krotov
  5.     All rights reserved.
  6. *)
  7.  
  8. MODULE BIN;
  9.  
  10. IMPORT LISTS, CHL := CHUNKLISTS, ARITH, UTILS;
  11.  
  12.  
  13. CONST
  14.  
  15.     RCODE*  = 0;  PICCODE* = RCODE + 1;
  16.     RDATA*  = 2;  PICDATA* = RDATA + 1;
  17.     RBSS*   = 4;  PICBSS*  = RBSS + 1;
  18.     RIMP*   = 6;  PICIMP*  = RIMP + 1;
  19.  
  20.     IMPTAB* = 8;
  21.  
  22.  
  23. TYPE
  24.  
  25.     RELOC* = POINTER TO RECORD (LISTS.ITEM)
  26.  
  27.         opcode*: INTEGER;
  28.         offset*: INTEGER
  29.  
  30.     END;
  31.  
  32.     IMPRT* = POINTER TO RECORD (LISTS.ITEM)
  33.  
  34.         nameoffs*: INTEGER;
  35.         label*:    INTEGER;
  36.  
  37.         OriginalFirstThunk*,
  38.         FirstThunk*: INTEGER
  39.  
  40.     END;
  41.  
  42.     EXPRT* = POINTER TO RECORD (LISTS.ITEM)
  43.  
  44.         nameoffs*: INTEGER;
  45.         label*:    INTEGER
  46.  
  47.     END;
  48.  
  49.     PROGRAM* = POINTER TO RECORD
  50.  
  51.         code*:      CHL.BYTELIST;
  52.         data*:      CHL.BYTELIST;
  53.         labels:     CHL.INTLIST;
  54.         bss*:       INTEGER;
  55.         stack*:     INTEGER;
  56.         vmajor*,
  57.         vminor*:    WCHAR;
  58.         modname*:   INTEGER;
  59.         _import*:   CHL.BYTELIST;
  60.         export*:    CHL.BYTELIST;
  61.         rel_list*:  LISTS.LIST;
  62.         imp_list*:  LISTS.LIST;
  63.         exp_list*:  LISTS.LIST
  64.  
  65.     END;
  66.  
  67.  
  68. PROCEDURE create* (NumberOfLabels: INTEGER): PROGRAM;
  69. VAR
  70.     program:  PROGRAM;
  71.     i:        INTEGER;
  72.  
  73. BEGIN
  74.     NEW(program);
  75.  
  76.     program.bss := 0;
  77.  
  78.     program.labels := CHL.CreateIntList();
  79.     FOR i := 0 TO NumberOfLabels - 1 DO
  80.         CHL.PushInt(program.labels, 0)
  81.     END;
  82.  
  83.     program.rel_list := LISTS.create(NIL);
  84.     program.imp_list := LISTS.create(NIL);
  85.     program.exp_list := LISTS.create(NIL);
  86.  
  87.     program.data    := CHL.CreateByteList();
  88.     program.code    := CHL.CreateByteList();
  89.     program._import := CHL.CreateByteList();
  90.     program.export  := CHL.CreateByteList()
  91.  
  92.     RETURN program
  93. END create;
  94.  
  95.  
  96. PROCEDURE SetParams* (program: PROGRAM; bss, stack: INTEGER; vmajor, vminor: WCHAR);
  97. BEGIN
  98.     program.bss    := bss;
  99.     program.stack  := stack;
  100.     program.vmajor := vmajor;
  101.     program.vminor := vminor
  102. END SetParams;
  103.  
  104.  
  105. PROCEDURE PutReloc* (program: PROGRAM; opcode: INTEGER);
  106. VAR
  107.     cmd: RELOC;
  108.  
  109. BEGIN
  110.     NEW(cmd);
  111.     cmd.opcode := opcode;
  112.     cmd.offset := CHL.Length(program.code);
  113.     LISTS.push(program.rel_list, cmd)
  114. END PutReloc;
  115.  
  116.  
  117. PROCEDURE PutData* (program: PROGRAM; b: BYTE);
  118. BEGIN
  119.     CHL.PushByte(program.data, b)
  120. END PutData;
  121.  
  122.  
  123. PROCEDURE get32le* (_array: CHL.BYTELIST; idx: INTEGER): INTEGER;
  124. VAR
  125.     i: INTEGER;
  126.     x: INTEGER;
  127.  
  128. BEGIN
  129.     x := 0;
  130.  
  131.     FOR i := 3 TO 0 BY -1 DO
  132.         x := LSL(x, 8) + CHL.GetByte(_array, idx + i)
  133.     END;
  134.  
  135.     IF UTILS.bit_depth = 64 THEN
  136.         x := LSL(x, 16);
  137.         x := LSL(x, 16);
  138.         x := ASR(x, 16);
  139.         x := ASR(x, 16)
  140.     END
  141.  
  142.     RETURN x
  143. END get32le;
  144.  
  145.  
  146. PROCEDURE put32le* (_array: CHL.BYTELIST; idx: INTEGER; x: INTEGER);
  147. VAR
  148.     i: INTEGER;
  149.  
  150. BEGIN
  151.     FOR i := 0 TO 3 DO
  152.         CHL.SetByte(_array, idx + i, UTILS.Byte(x, i))
  153.     END
  154. END put32le;
  155.  
  156.  
  157. PROCEDURE PutData32LE* (program: PROGRAM; x: INTEGER);
  158. VAR
  159.     i: INTEGER;
  160.  
  161. BEGIN
  162.     FOR i := 0 TO 3 DO
  163.         CHL.PushByte(program.data, UTILS.Byte(x, i))
  164.     END
  165. END PutData32LE;
  166.  
  167.  
  168. PROCEDURE PutData64LE* (program: PROGRAM; x: INTEGER);
  169. VAR
  170.     i: INTEGER;
  171.  
  172. BEGIN
  173.     FOR i := 0 TO 7 DO
  174.         CHL.PushByte(program.data, UTILS.Byte(x, i))
  175.     END
  176. END PutData64LE;
  177.  
  178.  
  179. PROCEDURE PutDataStr* (program: PROGRAM; s: ARRAY OF CHAR);
  180. VAR
  181.     i: INTEGER;
  182.  
  183. BEGIN
  184.     i := 0;
  185.     WHILE s[i] # 0X DO
  186.         PutData(program, ORD(s[i]));
  187.         INC(i)
  188.     END
  189. END PutDataStr;
  190.  
  191.  
  192. PROCEDURE PutCode* (program: PROGRAM; b: BYTE);
  193. BEGIN
  194.     CHL.PushByte(program.code, b)
  195. END PutCode;
  196.  
  197.  
  198. PROCEDURE PutCode32LE* (program: PROGRAM; x: INTEGER);
  199. VAR
  200.     i: INTEGER;
  201.  
  202. BEGIN
  203.     FOR i := 0 TO 3 DO
  204.         CHL.PushByte(program.code, UTILS.Byte(x, i))
  205.     END
  206. END PutCode32LE;
  207.  
  208.  
  209. PROCEDURE PutCode16LE* (program: PROGRAM; x: INTEGER);
  210. BEGIN
  211.     CHL.PushByte(program.code, UTILS.Byte(x, 0));
  212.     CHL.PushByte(program.code, UTILS.Byte(x, 1))
  213. END PutCode16LE;
  214.  
  215.  
  216. PROCEDURE SetLabel* (program: PROGRAM; label, offset: INTEGER);
  217. BEGIN
  218.     CHL.SetInt(program.labels, label, offset)
  219. END SetLabel;
  220.  
  221.  
  222. PROCEDURE Import* (program: PROGRAM; name: ARRAY OF CHAR; label: INTEGER);
  223. VAR
  224.     imp: IMPRT;
  225.  
  226. BEGIN
  227.     CHL.PushByte(program._import, 0);
  228.     CHL.PushByte(program._import, 0);
  229.  
  230.     IF ODD(CHL.Length(program._import)) THEN
  231.         CHL.PushByte(program._import, 0)
  232.     END;
  233.  
  234.     NEW(imp);
  235.     imp.nameoffs := CHL.PushStr(program._import, name);
  236.     imp.label := label;
  237.     LISTS.push(program.imp_list, imp)
  238. END Import;
  239.  
  240.  
  241. PROCEDURE less (bytes: CHL.BYTELIST; a, b: EXPRT): BOOLEAN;
  242. VAR
  243.     i, j: INTEGER;
  244.  
  245. BEGIN
  246.     i := a.nameoffs;
  247.     j := b.nameoffs;
  248.  
  249.     WHILE (CHL.GetByte(bytes, i) # 0) & (CHL.GetByte(bytes, j) # 0) &
  250.           (CHL.GetByte(bytes, i) = CHL.GetByte(bytes, j)) DO
  251.         INC(i);
  252.         INC(j)
  253.     END
  254.  
  255.     RETURN CHL.GetByte(bytes, i) < CHL.GetByte(bytes, j)
  256. END less;
  257.  
  258.  
  259. PROCEDURE Export* (program: PROGRAM; name: ARRAY OF CHAR; label: INTEGER);
  260. VAR
  261.     exp, cur: EXPRT;
  262.  
  263. BEGIN
  264.     NEW(exp);
  265.     exp.label := CHL.GetInt(program.labels, label);
  266.     exp.nameoffs := CHL.PushStr(program.export, name);
  267.  
  268.     cur := program.exp_list.first(EXPRT);
  269.     WHILE (cur # NIL) & less(program.export, cur, exp) DO
  270.         cur := cur.next(EXPRT)
  271.     END;
  272.  
  273.     IF cur # NIL THEN
  274.         IF cur.prev # NIL THEN
  275.             LISTS.insert(program.exp_list, cur.prev, exp)
  276.         ELSE
  277.             LISTS.insertL(program.exp_list, cur, exp)
  278.         END
  279.     ELSE
  280.         LISTS.push(program.exp_list, exp)
  281.     END
  282.  
  283. END Export;
  284.  
  285.  
  286. PROCEDURE GetIProc* (program: PROGRAM; n: INTEGER): IMPRT;
  287. VAR
  288.     _import, res: IMPRT;
  289.  
  290. BEGIN
  291.     _import  := program.imp_list.first(IMPRT);
  292.  
  293.     res := NIL;
  294.     WHILE (_import # NIL) & (n >= 0) DO
  295.         IF _import.label # 0 THEN
  296.             res := _import;
  297.             DEC(n)
  298.         END;
  299.         _import := _import.next(IMPRT)
  300.     END;
  301.  
  302.     ASSERT(n = -1)
  303.     RETURN res
  304. END GetIProc;
  305.  
  306.  
  307. PROCEDURE GetLabel* (program: PROGRAM; label: INTEGER): INTEGER;
  308.     RETURN CHL.GetInt(program.labels, label)
  309. END GetLabel;
  310.  
  311.  
  312. PROCEDURE NewLabel* (program: PROGRAM);
  313. BEGIN
  314.     CHL.PushInt(program.labels, 0)
  315. END NewLabel;
  316.  
  317.  
  318. PROCEDURE fixup* (program: PROGRAM);
  319. VAR
  320.     rel:    RELOC;
  321.     imp:    IMPRT;
  322.     nproc:  INTEGER;
  323.     L:      INTEGER;
  324.  
  325. BEGIN
  326.  
  327.     nproc := 0;
  328.     imp := program.imp_list.first(IMPRT);
  329.     WHILE imp # NIL DO
  330.         IF imp.label # 0 THEN
  331.             CHL.SetInt(program.labels, imp.label, nproc);
  332.             INC(nproc)
  333.         END;
  334.         imp := imp.next(IMPRT)
  335.     END;
  336.  
  337.     rel := program.rel_list.first(RELOC);
  338.     WHILE rel # NIL DO
  339.  
  340.         IF rel.opcode IN {RIMP, PICIMP} THEN
  341.             L := get32le(program.code, rel.offset);
  342.             put32le(program.code, rel.offset, GetLabel(program, L))
  343.         END;
  344.  
  345.         rel := rel.next(RELOC)
  346.     END
  347.  
  348. END fixup;
  349.  
  350.  
  351. PROCEDURE InitArray* (VAR _array: ARRAY OF BYTE; VAR idx: INTEGER; hex: ARRAY OF CHAR);
  352. VAR
  353.     i, k: INTEGER;
  354.  
  355.  
  356.     PROCEDURE hexdgt (dgt: CHAR): INTEGER;
  357.     VAR
  358.         res: INTEGER;
  359.  
  360.     BEGIN
  361.         IF dgt < "A" THEN
  362.             res := ORD(dgt) - ORD("0")
  363.         ELSE
  364.             res := ORD(dgt) - ORD("A") + 10
  365.         END
  366.  
  367.         RETURN res
  368.     END hexdgt;
  369.  
  370.  
  371. BEGIN
  372.     k := LENGTH(hex);
  373.     ASSERT(~ODD(k));
  374.     k := k DIV 2;
  375.  
  376.     FOR i := 0 TO k - 1 DO
  377.         _array[i + idx] := hexdgt(hex[2 * i]) * 16 + hexdgt(hex[2 * i + 1])
  378.     END;
  379.  
  380.     INC(idx, k)
  381. END InitArray;
  382.  
  383.  
  384. END BIN.