Subversion Repositories Kolibri OS

Rev

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

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2018-2019, 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: IMPRT;
  289.     res:    IMPRT;
  290.  
  291. BEGIN
  292.     import  := program.imp_list.first(IMPRT);
  293.  
  294.     res := NIL;
  295.     WHILE (import # NIL) & (n >= 0) DO
  296.         IF import.label # 0 THEN
  297.             res := import;
  298.             DEC(n)
  299.         END;
  300.         import := import.next(IMPRT)
  301.     END;
  302.  
  303.     ASSERT(n = -1)
  304.     RETURN res
  305. END GetIProc;
  306.  
  307.  
  308. PROCEDURE GetLabel* (program: PROGRAM; label: INTEGER): INTEGER;
  309.     RETURN CHL.GetInt(program.labels, label)
  310. END GetLabel;
  311.  
  312.  
  313. PROCEDURE NewLabel* (program: PROGRAM);
  314. BEGIN
  315.     CHL.PushInt(program.labels, 0)
  316. END NewLabel;
  317.  
  318.  
  319. PROCEDURE fixup* (program: PROGRAM);
  320. VAR
  321.     rel:    RELOC;
  322.     imp:    IMPRT;
  323.     nproc:  INTEGER;
  324.     L:      INTEGER;
  325.  
  326. BEGIN
  327.  
  328.     nproc := 0;
  329.     imp := program.imp_list.first(IMPRT);
  330.     WHILE imp # NIL DO
  331.         IF imp.label # 0 THEN
  332.             CHL.SetInt(program.labels, imp.label, nproc);
  333.             INC(nproc)
  334.         END;
  335.         imp := imp.next(IMPRT)
  336.     END;
  337.  
  338.     rel := program.rel_list.first(RELOC);
  339.     WHILE rel # NIL DO
  340.  
  341.         IF rel.opcode IN {RIMP, PICIMP} THEN
  342.             L := get32le(program.code, rel.offset);
  343.             put32le(program.code, rel.offset, GetLabel(program, L))
  344.         END;
  345.  
  346.         rel := rel.next(RELOC)
  347.     END
  348.  
  349. END fixup;
  350.  
  351.  
  352. PROCEDURE InitArray* (VAR array: ARRAY OF BYTE; VAR idx: INTEGER; hex: ARRAY OF CHAR);
  353. VAR
  354.     i, k: INTEGER;
  355.  
  356.  
  357.     PROCEDURE hexdgt (dgt: CHAR): INTEGER;
  358.     VAR
  359.         res: INTEGER;
  360.  
  361.     BEGIN
  362.         IF dgt < "A" THEN
  363.             res := ORD(dgt) - ORD("0")
  364.         ELSE
  365.             res := ORD(dgt) - ORD("A") + 10
  366.         END
  367.  
  368.         RETURN res
  369.     END hexdgt;
  370.  
  371.  
  372. BEGIN
  373.     k := LENGTH(hex);
  374.     ASSERT(~ODD(k));
  375.     k := k DIV 2;
  376.  
  377.     FOR i := 0 TO k - 1 DO
  378.         array[i + idx] := hexdgt(hex[2 * i]) * 16 + hexdgt(hex[2 * i + 1])
  379.     END;
  380.  
  381.     INC(idx, k)
  382. END InitArray;
  383.  
  384.  
  385. END BIN.