Name

Nasm::X86 - Generate X86 assembler code using Perl as a macro pre-processor.

Synopsis

Write and execute x64 Avx512 assembler code from perl using perl as a macro assembler. The generated code can be run under the Intel emulator to obtain execution trace and instruction counts.

Examples

Avx512 instructions

Use Avx512 instructions to perform 64 comparisons in parallel.

  my $P = "2F";                                                                 # Value to test for
  my $l = Rb 0;  Rb $_ for 1..RegisterSize zmm0;                                # 0..63
  Vmovdqu8 zmm0, "[$l]";                                                        # Load data to test
  PrintOutRegisterInHex zmm0;

  Mov rax, "0x$P";                                                              # Broadcast the value to be tested
  Vpbroadcastb zmm1, rax;
  PrintOutRegisterInHex zmm1;

  for my $c(0..7)                                                               # Each possible test
   {my $m = "k$c";
    Vpcmpub $m, zmm1, zmm0, $c;
    PrintOutRegisterInHex $m;
   }

  Kmovq rax, k0;                                                                # Count the number of trailing zeros in k0
  Tzcnt rax, rax;
  PrintOutRegisterInHex rax;

  is_deeply Assemble, <<END;                                                    # Assemble and test
  zmm0: 3F3E 3D3C 3B3A 3938   3736 3534 3332 3130   2F2E 2D2C 2B2A 2928   2726 2524 2322 2120   1F1E 1D1C 1B1A 1918   1716 1514 1312 1110   0F0E 0D0C 0B0A 0908   0706 0504 0302 0100
  zmm1: 2F2F 2F2F 2F2F 2F2F   2F2F 2F2F 2F2F 2F2F   2F2F 2F2F 2F2F 2F2F   2F2F 2F2F 2F2F 2F2F   2F2F 2F2F 2F2F 2F2F   2F2F 2F2F 2F2F 2F2F   2F2F 2F2F 2F2F 2F2F   2F2F 2F2F 2F2F 2F2F
    k0: 0000 8000 0000 0000
    k1: FFFF 0000 0000 0000
    k2: FFFF 8000 0000 0000
    k3: 0000 0000 0000 0000
    k4: FFFF 7FFF FFFF FFFF
    k5: 0000 FFFF FFFF FFFF
    k6: 0000 7FFF FFFF FFFF
    k7: FFFF FFFF FFFF FFFF
   rax: 0000 0000 0000 002F
END

With the print statements removed, the Intel Emulator indicates that 26 instructions were executed:

  CALL_NEAR                                                              1
  ENTER                                                                  2
  JMP                                                                    1
  KMOVQ                                                                  1
  MOV                                                                    5
  POP                                                                    1
  PUSH                                                                   3
  SYSCALL                                                                1
  TZCNT                                                                  1
  VMOVDQU8                                                               1
  VPBROADCASTB                                                           1
  VPCMPUB                                                                8

  *total                                                                26

Create a library

Create a library with three subroutines in it and save the library to a file:

  my $library = CreateLibrary          # Library definition
   (subroutines =>                     # Sub routines in libray
     {inc => sub {Inc rax},            # Increment rax
      dup => sub {Shl rax, 1},         # Double rax
      put => sub {PrintOutRaxInDecNL}, # Print rax in decimal
     },
    file => q(library),
   );

Reload the library and call its subroutines from a separate assembly:

  my ($dup, $inc, $put) = $library->load; # Load the library into variables

  Mov rax, 1; &$put;
  &$inc;      &$put;                      # Use the subroutines from the library
  &$dup;      &$put;
  &$dup;      &$put;
  &$inc;      &$put;

  ok Assemble eq => <<END;
1
2
4
8
9
END

Read a character

Read a character from stdin and place it in rax:

  for(1..4)
   {ReadChar;
    PrintOutRegisterInHex rax;
   }

  Assemble keep => "readChar";

  my $r = qx(echo "ABCD" | ./readChar);
  is_deeply $r, <<END;
   rax: 0000 0000 0000 0041
   rax: 0000 0000 0000 0042
   rax: 0000 0000 0000 0043
   rax: 0000 0000 0000 0044
END

Read a file

Read this file:

  ReadFile(V(file, Rs($0)), (my $s = V(size)), my $a = V(address));          # Read file
  $a->setReg(rax);                                                              # Address of file in memory
  $s->setReg(rdi);                                                              # Length  of file in memory
  PrintOutMemory;                                                               # Print contents of memory to stdout

  my $r = Assemble(1 => (my $f = temporaryFile));                               # Assemble and execute
  ok fileMd5Sum($f) eq fileMd5Sum($0);                                          # Output contains this file

Call functions in Libc

Call C functions by naming them as external and including their library:

  my $format = Rs "Hello %s\n";
  my $data   = Rs "World";

  Extern qw(printf exit malloc strcpy); Link 'c';

  CallC 'malloc', length($format)+1;
  Mov r15, rax;
  CallC 'strcpy', r15, $format;
  CallC 'printf', r15, $data;
  CallC 'exit', 0;

  ok Assemble eq => <<END;
Hello World
END

Debug your programs with powerful print statements:

  Mov rax, 0x2a;
  PrintOutRaxInDecNL;

  ok Assemble eq => <<END;
42
END

Process management

Start a child process and wait for it, printing out the process identifiers of each process involved:

   Fork;                                     # Fork

   Test rax,rax;
   IfNz                                      # Parent
   Then
    {Mov rbx, rax;
     WaitPid;
     GetPid;                                 # Pid of parent as seen in parent
     Mov rcx,rax;
     PrintOutRegisterInHex rax, rbx, rcx;
    },
   Else                                      # Child
    {Mov r8,rax;
     GetPid;                                 # Child pid as seen in child
     Mov r9,rax;
     GetPPid;                                # Parent pid as seen in child
     Mov r10,rax;
     PrintOutRegisterInHex r8, r9, r10;
    };

   my $r = Assemble;

 #    r8: 0000 0000 0000 0000   #1 Return from fork as seen by child
 #    r9: 0000 0000 0003 0C63   #2 Pid of child
 #   r10: 0000 0000 0003 0C60   #3 Pid of parent from child
 #   rax: 0000 0000 0003 0C63   #4 Return from fork as seen by parent
 #   rbx: 0000 0000 0003 0C63   #5 Wait for child pid result
 #   rcx: 0000 0000 0003 0C60   #6 Pid of parent

Dynamic arena

Arenas are resizeable, relocatable blocks of memory that hold other dynamic data structures. Arenas can be transferred between processes and relocated as needed as all addressing is relative to the start of the block of memory containing each arena.

Create two dynamic arenas, add some content to them, write each arena to stdout:

  my $a = CreateArena;

  my $b = CreateArena;
  $a->q('aa');
  $b->q('bb');
  $a->q('AA');
  $b->q('BB');
  $a->q('aa');
  $b->q('bb');

  $a->out;
  $b->out;

  PrintOutNL;

  is_deeply Assemble, <<END;
aaAAaabbBBbb
END

Dynamic string held in an arena

Create a dynamic string within an arena and add some content to it:

  my $s = Rb(0..255);
  my $A = CreateArena;
  my $S = $A->CreateString;

  $S->append(V(source, $s), K(size, 256));
  $S->len->outNL;
  $S->clear;

  $S->append(V(source, $s), K(size,  16));
  $S->len->outNL;
  $S->dump;

  ok Assemble(debug => 0, eq => <<END);
size: 0000 0000 0000 0100
size: 0000 0000 0000 0010
string Dump
Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0010
 zmm31: 0000 0018 0000 0018   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 000F   0E0D 0C0B 0A09 0807   0605 0403 0201 0010

END

Dynamic array held in an arena

Create a dynamic array within an arena, push some content on to it then pop it off again:

  my $N = 15;
  my $A = CreateArena;
  my $a = $A->CreateArray;

  $a->push(V(element, $_)) for 1..$N;

  K(loop, $N)->for(sub
   {my ($start, $end, $next) = @_;
    my $l = $a->size;
    If $l == 0, Then {Jmp $end};
    $a->pop(my $e = V(element));
    $e->outNL;
   });

  ok Assemble(debug => 0, eq => <<END);
element: 0000 0000 0000 000F
element: 0000 0000 0000 000E
element: 0000 0000 0000 000D
element: 0000 0000 0000 000C
element: 0000 0000 0000 000B
element: 0000 0000 0000 000A
element: 0000 0000 0000 0009
element: 0000 0000 0000 0008
element: 0000 0000 0000 0007
element: 0000 0000 0000 0006
element: 0000 0000 0000 0005
element: 0000 0000 0000 0004
element: 0000 0000 0000 0003
element: 0000 0000 0000 0002
element: 0000 0000 0000 0001
END

Create a multi way tree in an arena using SIMD instructions

Create a multiway tree as in Tree::Multi using Avx512 instructions and iterate through it:

  my $N = 12;
  my $b = CreateArena;                   # Resizable memory block
  my $t = $b->CreateTree;        # Multi way tree in memory block

  K(count, $N)->for(sub                      # Add some entries to the tree
   {my ($index, $start, $next, $end) = @_;
    my $k = $index + 1;
    $t->insert($k,      $k + 0x100);
    $t->insert($k + $N, $k + 0x200);
   });

  $t->by(sub                                  # Iterate through the tree
   {my ($iter, $end) = @_;
    $iter->key ->out('key: ');
    $iter->data->out(' data: ');
    $iter->tree->depth($iter->node, my $D = V(depth));

    $t->find($iter->key);
    $t->found->out(' found: '); $t->data->out(' data: '); $D->outNL(' depth: ');
   });

  $t->find(K(key, 0xffff));  $t->found->outNL('Found: ');  # Find some entries
  $t->find(K(key, 0xd));     $t->found->outNL('Found: ');

  If ($t->found,
  Then
   {$t->data->outNL("Data : ");
   });

  ok Assemble(debug => 0, eq => <<END);
key: 0000 0000 0000 0001 data: 0000 0000 0000 0101 found: 0000 0000 0000 0001 data: 0000 0000 0000 0101 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0002 data: 0000 0000 0000 0102 found: 0000 0000 0000 0001 data: 0000 0000 0000 0102 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0003 data: 0000 0000 0000 0103 found: 0000 0000 0000 0001 data: 0000 0000 0000 0103 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0004 data: 0000 0000 0000 0104 found: 0000 0000 0000 0001 data: 0000 0000 0000 0104 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0005 data: 0000 0000 0000 0105 found: 0000 0000 0000 0001 data: 0000 0000 0000 0105 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0006 data: 0000 0000 0000 0106 found: 0000 0000 0000 0001 data: 0000 0000 0000 0106 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0007 data: 0000 0000 0000 0107 found: 0000 0000 0000 0001 data: 0000 0000 0000 0107 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0008 data: 0000 0000 0000 0108 found: 0000 0000 0000 0001 data: 0000 0000 0000 0108 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0009 data: 0000 0000 0000 0109 found: 0000 0000 0000 0001 data: 0000 0000 0000 0109 depth: 0000 0000 0000 0002
key: 0000 0000 0000 000A data: 0000 0000 0000 010A found: 0000 0000 0000 0001 data: 0000 0000 0000 010A depth: 0000 0000 0000 0002
key: 0000 0000 0000 000B data: 0000 0000 0000 010B found: 0000 0000 0000 0001 data: 0000 0000 0000 010B depth: 0000 0000 0000 0002
key: 0000 0000 0000 000C data: 0000 0000 0000 010C found: 0000 0000 0000 0001 data: 0000 0000 0000 010C depth: 0000 0000 0000 0002
key: 0000 0000 0000 000D data: 0000 0000 0000 0201 found: 0000 0000 0000 0001 data: 0000 0000 0000 0201 depth: 0000 0000 0000 0001
key: 0000 0000 0000 000E data: 0000 0000 0000 0202 found: 0000 0000 0000 0001 data: 0000 0000 0000 0202 depth: 0000 0000 0000 0002
key: 0000 0000 0000 000F data: 0000 0000 0000 0203 found: 0000 0000 0000 0001 data: 0000 0000 0000 0203 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0010 data: 0000 0000 0000 0204 found: 0000 0000 0000 0001 data: 0000 0000 0000 0204 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0011 data: 0000 0000 0000 0205 found: 0000 0000 0000 0001 data: 0000 0000 0000 0205 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0012 data: 0000 0000 0000 0206 found: 0000 0000 0000 0001 data: 0000 0000 0000 0206 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0013 data: 0000 0000 0000 0207 found: 0000 0000 0000 0001 data: 0000 0000 0000 0207 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0014 data: 0000 0000 0000 0208 found: 0000 0000 0000 0001 data: 0000 0000 0000 0208 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0015 data: 0000 0000 0000 0209 found: 0000 0000 0000 0001 data: 0000 0000 0000 0209 depth: 0000 0000 0000 0002
key: 0000 0000 0000 0016 data: 0000 0000 0000 020A found: 0000 0000 0000 0001 data: 0000 0000 0000 020A depth: 0000 0000 0000 0002
key: 0000 0000 0000 0017 data: 0000 0000 0000 020B found: 0000 0000 0000 0001 data: 0000 0000 0000 020B depth: 0000 0000 0000 0002
key: 0000 0000 0000 0018 data: 0000 0000 0000 020C found: 0000 0000 0000 0001 data: 0000 0000 0000 020C depth: 0000 0000 0000 0002
Found: 0000 0000 0000 0000
Found: 0000 0000 0000 0001
Data : 0000 0000 0000 0201
END

Quarks held in an arena

Quarks replace unique strings with unique numbers and in doing so unite all that is best and brightest in dynamic trees, arrays, strings and short strings, all written in X86 assembler, all generated by Perl:

  my $N = 5;
  my $a = CreateArena;                      # Arena containing quarks
  my $Q = $a->CreateQuarks;                 # Quarks

  my $s = CreateShortString(0);             # Short string used to load and unload quarks
  my $d = Rb(1..63);

  for my $i(1..$N)                          # Load a set of quarks
   {my $j = $i - 1;
    $s->load(K(address, $d), K(size, 4+$i));
    my $q = $Q->quarkFromShortString($s);
    $q->outNL("New quark    $j: ");         # New quark, new number
   }
  PrintOutNL;

  for my $i(reverse 1..$N)                  # Reload a set of quarks
   {my $j = $i - 1;
    $s->load(K(address, $d), K(size, 4+$i));
    my $q = $Q->quarkFromShortString($s);
    $q->outNL("Old quark    $j: ");         # Old quark, old number
   }
  PrintOutNL;

  for my $i(1..$N)                          # Dump quarks
   {my $j = $i - 1;
     $s->clear;
    $Q->shortStringFromQuark(K(quark, $j), $s);
    PrintOutString "Quark string $j: ";
    PrintOutRegisterInHex xmm0;
   }

  ok Assemble(debug => 0, trace => 0, eq => <<END);
  New quark    0: 0000 0000 0000 0000
  New quark    1: 0000 0000 0000 0001
  New quark    2: 0000 0000 0000 0002
  New quark    3: 0000 0000 0000 0003
  New quark    4: 0000 0000 0000 0004

  Old quark    4: 0000 0000 0000 0004
  Old quark    3: 0000 0000 0000 0003
  Old quark    2: 0000 0000 0000 0002
  Old quark    1: 0000 0000 0000 0001
  Old quark    0: 0000 0000 0000 0000

  Quark string 0:   xmm0: 0000 0000 0000 0000   0000 0504 0302 0105
  Quark string 1:   xmm0: 0000 0000 0000 0000   0006 0504 0302 0106
  Quark string 2:   xmm0: 0000 0000 0000 0000   0706 0504 0302 0107
  Quark string 3:   xmm0: 0000 0000 0000 0008   0706 0504 0302 0108
  Quark string 4:   xmm0: 0000 0000 0000 0908   0706 0504 0302 0109
  END

Recursion with stack and parameter tracing

Call a subroutine recursively and get a trace back showing the procedure calls and parameters passed to each call. Parameters are passed by reference not value.

  my $d = V depth, 3;                           # Create a variable on the stack

  my $s = Subroutine
   {my ($p, $s) = @_;                           # Parameters, subroutine descriptor
    PrintOutTraceBack;

    my $d = $$p{depth}->copy($$p{depth} - 1);   # Modify the variable referenced by the parameter

    If ($d > 0,
    Then
     {$s->call($d);                             # Recurse
     });

    PrintOutTraceBack;
   } [qw(depth)], name => 'ref';

  $s->call($d);                                 # Call the subroutine

  ok Assemble(debug => 0, eq => <<END);

  Subroutine trace back, depth: 0000 0000 0000 0001
  0000 0000 0000 0003    ref


  Subroutine trace back, depth: 0000 0000 0000 0002
  0000 0000 0000 0002    ref
  0000 0000 0000 0002    ref


  Subroutine trace back, depth: 0000 0000 0000 0003
  0000 0000 0000 0001    ref
  0000 0000 0000 0001    ref
  0000 0000 0000 0001    ref


  Subroutine trace back, depth: 0000 0000 0000 0003
  0000 0000 0000 0000    ref
  0000 0000 0000 0000    ref
  0000 0000 0000 0000    ref


  Subroutine trace back, depth: 0000 0000 0000 0002
  0000 0000 0000 0000    ref
  0000 0000 0000 0000    ref


  Subroutine trace back, depth: 0000 0000 0000 0001
  0000 0000 0000 0000    ref

END

Installation

The Intel Software Development Emulator will be required if you do not have a computer with the avx512 instruction set and wish to execute code containing these instructions. For details see:

https://software.intel.com/content/dam/develop/external/us/en/documents/downloads/sde-external-8.63.0-2021-01-18-lin.tar.bz2

The Networkwide Assembler is required to assemble the code produced For full details see:

https://github.com/philiprbrenan/NasmX86/blob/main/.github/workflows/main.yml

Execution Options

The "Assemble(%)" function takes the keywords described below to control assembly and execution of the assembled code:

"Assemble(%)" runs the generated program after a successful assembly unless the keep option is specified. The output on stdout is captured in file zzzOut.txt and that on stderr is captured in file zzzErr.txt.

The amount of output displayed is controlled by the debug keyword.

The eq keyword can be used to test that the output by the run.

The output produced by the program execution is returned as the result of the "Assemble(%)" function.

Keep

To produce a named executable without running it, specify:

 keep=>"executable file name"

Library

To produce a shared library file:

 library=>"library.so"

Emulator

To run the executable produced by "Assemble(%)" without the Intel emulator, which is used by default if it is present, specify:

 emulator=>0

eq

The eq keyword supplies the expected output from the execution of the assembled program. If the expected output is not obtained on stdout then we confess and stop further testing. Output on stderr is ignored for test purposes.

The point at which the wanted output diverges from the output actually got is displayed to assist debugging as in:

  Comparing wanted with got failed at line: 4, character: 22
  Start:
      k7: 0000 0000 0000 0001
      k6: 0000 0000 0000 0003
      k5: 0000 0000 0000 0007
      k4: 0000 0000 000
  Want ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1 0002
      k3: 0000 0000 0000 0006
      k2: 0000 0000 0000 000E
      k1: 0000 0000
  Got  ________________________________________________________________________________
  0 0002
      k3: 0000 0000 0000 0006
      k2: 0000 0000 0000 000E
      k1: 0000 0000

Debug

The debug keyword controls how much output is printed after each assemble and run.

  debug => 0

produces no output unless the eq keyword was specified and the actual output fails to match the expected output. If such a test fails we Carp::confess.

  debug => 1

shows all the output produces and conducts the test specified by the eq is present. If the test fails we Carp::confess.

  debug => 2

shows all the output produces and conducts the test specified by the eq is present. If the test fails we continue rather than calling Carp::confess.

Description

Generate X86 assembler code using Perl as a macro pre-processor.

Version "20211123".

The following sections describe the methods in each functional area of this module. For an alphabetic listing of all methods by name see Index.

Data

Layout data

SetLabel($l)

Create (if necessary) and set a label in the code section returning the label so set.

     Parameter  Description
  1  $l         Label

Example:

    Mov rax, 1;
    Mov rdi, 1;
    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSeven;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFour;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRax;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRax;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;

    SetLabel $l;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END

    ok 8 == RegisterSize rax;

Ds(@d)

Layout bytes in memory and return their label.

     Parameter  Description
  1  @d         Data to be laid out

Example:

    my $q = Rs('a'..'z');

    Mov rax, Ds('0'x64);                                                          # Output area  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Vmovdqu32(xmm0, "[$q]");                                                      # Load
    Vprolq   (xmm0,   xmm0, 32);                                                  # Rotate double words in quad words
    Vmovdqu32("[rax]", xmm0);                                                     # Save
    Mov rdi, 16;
    PrintOutMemory;

    ok Assemble =~ m(efghabcdmnopijkl)s;

Rs(@d)

Layout bytes in read only memory and return their label.

     Parameter  Description
  1  @d         Data to be laid out

Example:

    Comment "Print a string from memory";
    my $s = "Hello World";

    Mov rax, Rs($s);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rdi, length $s;
    PrintOutMemory;
    Exit(0);

    ok Assemble =~ m(Hello World);


    my $q = Rs('abababab');  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov(rax, 1);
    Mov(rbx, 2);
    Mov(rcx, 3);
    Mov(rdx, 4);
    Mov(r8,  5);
    Lea r9,  "[rax+rbx]";
    PrintOutRegistersInHex;

    my $r = Assemble;
    ok $r =~ m( r8: 0000 0000 0000 0005.* r9: 0000 0000 0000 0003.*rax: 0000 0000 0000 0001)s;
    ok $r =~ m(rbx: 0000 0000 0000 0002.*rcx: 0000 0000 0000 0003.*rdx: 0000 0000 0000 0004)s;

Rutf8(@d)

Layout a utf8 encoded string as bytes in read only memory and return their label.

     Parameter  Description
  1  @d         Data to be laid out

Db(@bytes)

Layout bytes in the data segment and return their label.

     Parameter  Description
  1  @bytes     Bytes to layout

Example:

    my $s = Rb 0; Rb 1; Rw 2; Rd 3;  Rq 4;

    my $t = Db 0; Db 1; Dw 2; Dd 3;  Dq 4;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Vmovdqu8 xmm0, "[$s]";
    Vmovdqu8 xmm1, "[$t]";
    PrintOutRegisterInHex xmm0;
    PrintOutRegisterInHex xmm1;
    Sub rsp, 16;

    Mov rax, rsp;                                                                 # Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi
    Mov rdi, 16;
    Mov rsi, $s;
    CopyMemory(V(source, rsi), V(target, rax), V(size, rdi));
    PrintOutMemoryInHex;

    my $r = Assemble;
    ok $r =~ m(xmm0: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(xmm1: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(0001 0200 0300 00000400 0000 0000 0000);

Dw(@words)

Layout words in the data segment and return their label.

     Parameter  Description
  1  @words     Words to layout

Example:

    my $s = Rb 0; Rb 1; Rw 2; Rd 3;  Rq 4;

    my $t = Db 0; Db 1; Dw 2; Dd 3;  Dq 4;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Vmovdqu8 xmm0, "[$s]";
    Vmovdqu8 xmm1, "[$t]";
    PrintOutRegisterInHex xmm0;
    PrintOutRegisterInHex xmm1;
    Sub rsp, 16;

    Mov rax, rsp;                                                                 # Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi
    Mov rdi, 16;
    Mov rsi, $s;
    CopyMemory(V(source, rsi), V(target, rax), V(size, rdi));
    PrintOutMemoryInHex;

    my $r = Assemble;
    ok $r =~ m(xmm0: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(xmm1: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(0001 0200 0300 00000400 0000 0000 0000);

Dd(@dwords)

Layout double words in the data segment and return their label.

     Parameter  Description
  1  @dwords    Double words to layout

Example:

    my $s = Rb 0; Rb 1; Rw 2; Rd 3;  Rq 4;

    my $t = Db 0; Db 1; Dw 2; Dd 3;  Dq 4;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Vmovdqu8 xmm0, "[$s]";
    Vmovdqu8 xmm1, "[$t]";
    PrintOutRegisterInHex xmm0;
    PrintOutRegisterInHex xmm1;
    Sub rsp, 16;

    Mov rax, rsp;                                                                 # Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi
    Mov rdi, 16;
    Mov rsi, $s;
    CopyMemory(V(source, rsi), V(target, rax), V(size, rdi));
    PrintOutMemoryInHex;

    my $r = Assemble;
    ok $r =~ m(xmm0: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(xmm1: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(0001 0200 0300 00000400 0000 0000 0000);

Dq(@qwords)

Layout quad words in the data segment and return their label.

     Parameter  Description
  1  @qwords    Quad words to layout

Example:

    my $s = Rb 0; Rb 1; Rw 2; Rd 3;  Rq 4;

    my $t = Db 0; Db 1; Dw 2; Dd 3;  Dq 4;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Vmovdqu8 xmm0, "[$s]";
    Vmovdqu8 xmm1, "[$t]";
    PrintOutRegisterInHex xmm0;
    PrintOutRegisterInHex xmm1;
    Sub rsp, 16;

    Mov rax, rsp;                                                                 # Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi
    Mov rdi, 16;
    Mov rsi, $s;
    CopyMemory(V(source, rsi), V(target, rax), V(size, rdi));
    PrintOutMemoryInHex;

    my $r = Assemble;
    ok $r =~ m(xmm0: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(xmm1: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(0001 0200 0300 00000400 0000 0000 0000);

Rb(@bytes)

Layout bytes in the data segment and return their label.

     Parameter  Description
  1  @bytes     Bytes to layout

Example:

    my $s = Rb 0; Rb 1; Rw 2; Rd 3;  Rq 4;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $t = Db 0; Db 1; Dw 2; Dd 3;  Dq 4;

    Vmovdqu8 xmm0, "[$s]";
    Vmovdqu8 xmm1, "[$t]";
    PrintOutRegisterInHex xmm0;
    PrintOutRegisterInHex xmm1;
    Sub rsp, 16;

    Mov rax, rsp;                                                                 # Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi
    Mov rdi, 16;
    Mov rsi, $s;
    CopyMemory(V(source, rsi), V(target, rax), V(size, rdi));
    PrintOutMemoryInHex;

    my $r = Assemble;
    ok $r =~ m(xmm0: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(xmm1: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(0001 0200 0300 00000400 0000 0000 0000);

Rw(@words)

Layout words in the data segment and return their label.

     Parameter  Description
  1  @words     Words to layout

Example:

    my $s = Rb 0; Rb 1; Rw 2; Rd 3;  Rq 4;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $t = Db 0; Db 1; Dw 2; Dd 3;  Dq 4;

    Vmovdqu8 xmm0, "[$s]";
    Vmovdqu8 xmm1, "[$t]";
    PrintOutRegisterInHex xmm0;
    PrintOutRegisterInHex xmm1;
    Sub rsp, 16;

    Mov rax, rsp;                                                                 # Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi
    Mov rdi, 16;
    Mov rsi, $s;
    CopyMemory(V(source, rsi), V(target, rax), V(size, rdi));
    PrintOutMemoryInHex;

    my $r = Assemble;
    ok $r =~ m(xmm0: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(xmm1: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(0001 0200 0300 00000400 0000 0000 0000);

Rd(@dwords)

Layout double words in the data segment and return their label.

     Parameter  Description
  1  @dwords    Double words to layout

Example:

    my $s = Rb 0; Rb 1; Rw 2; Rd 3;  Rq 4;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $t = Db 0; Db 1; Dw 2; Dd 3;  Dq 4;

    Vmovdqu8 xmm0, "[$s]";
    Vmovdqu8 xmm1, "[$t]";
    PrintOutRegisterInHex xmm0;
    PrintOutRegisterInHex xmm1;
    Sub rsp, 16;

    Mov rax, rsp;                                                                 # Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi
    Mov rdi, 16;
    Mov rsi, $s;
    CopyMemory(V(source, rsi), V(target, rax), V(size, rdi));
    PrintOutMemoryInHex;

    my $r = Assemble;
    ok $r =~ m(xmm0: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(xmm1: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(0001 0200 0300 00000400 0000 0000 0000);

Rq(@qwords)

Layout quad words in the data segment and return their label.

     Parameter  Description
  1  @qwords    Quad words to layout

Example:

    my $s = Rb 0; Rb 1; Rw 2; Rd 3;  Rq 4;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $t = Db 0; Db 1; Dw 2; Dd 3;  Dq 4;

    Vmovdqu8 xmm0, "[$s]";
    Vmovdqu8 xmm1, "[$t]";
    PrintOutRegisterInHex xmm0;
    PrintOutRegisterInHex xmm1;
    Sub rsp, 16;

    Mov rax, rsp;                                                                 # Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi
    Mov rdi, 16;
    Mov rsi, $s;
    CopyMemory(V(source, rsi), V(target, rax), V(size, rdi));
    PrintOutMemoryInHex;

    my $r = Assemble;
    ok $r =~ m(xmm0: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(xmm1: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(0001 0200 0300 00000400 0000 0000 0000);

Registers

Operations on registers

xmm(@r)

Add xmm to the front of a list of register expressions.

     Parameter  Description
  1  @r         Register numbers

ymm(@r)

Add ymm to the front of a list of register expressions.

     Parameter  Description
  1  @r         Register numbers

zmm(@r)

Add zmm to the front of a list of register expressions.

     Parameter  Description
  1  @r         Register numbers

Example:

    LoadZmm 0, 0..63;

    PrintOutRegisterInHex zmm 0;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 0, eq => <<END);
    zmm0: 3F3E 3D3C 3B3A 3938   3736 3534 3332 3130   2F2E 2D2C 2B2A 2928   2726 2524 2322 2120   1F1E 1D1C 1B1A 1918   1716 1514 1312 1110   0F0E 0D0C 0B0A 0908   0706 0504 0302 0100
  END

ChooseRegisters($number, @registers)

Choose the specified numbers of registers excluding those on the specified list.

     Parameter   Description
  1  $number     Number of registers needed
  2  @registers  Registers not to choose

RegistersAvailable(@reg)

Add a new set of registers that are available.

     Parameter  Description
  1  @reg       Registers known to be available at the moment

RegistersFree()

Remove the current set of registers known to be free.

CheckGeneralPurposeRegister($reg)

Check that a register is in fact a general purpose register.

     Parameter  Description
  1  $reg       Mask register to check

CheckNumberedGeneralPurposeRegister($reg)

Check that a register is in fact a numbered general purpose register.

     Parameter  Description
  1  $reg       Mask register to check

InsertZeroIntoRegisterAtPoint($point, $in)

Insert a zero into the specified register at the point indicated by another register.

     Parameter  Description
  1  $point     Register with a single 1 at the insertion point
  2  $in        Register to be inserted into.

Example:

    Mov r15, 0x100;                                                               # Given a register with a single one in it indicating the desired position,
    Mov r14, 0xFFDC;                                                              # Insert a zero into the register at that position shifting the bits above that position up left one to make space for the new zero.
    Mov r13, 0xF03F;
    PrintOutRegisterInHex         r14, r15;

    InsertZeroIntoRegisterAtPoint r15, r14;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex r14;
    Or r14, r15;                                                                  # Replace the inserted zero with a one
    PrintOutRegisterInHex r14;
    InsertOneIntoRegisterAtPoint r15, r13;
    PrintOutRegisterInHex r13;
    ok Assemble(debug => 0, eq => <<END);
     r14: 0000 0000 0000 FFDC
     r15: 0000 0000 0000 0100
     r14: 0000 0000 0001 FEDC
     r14: 0000 0000 0001 FFDC
     r13: 0000 0000 0001 E13F
  END

InsertOneIntoRegisterAtPoint($point, $in)

Insert a one into the specified register at the point indicated by another register.

     Parameter  Description
  1  $point     Register with a single 1 at the insertion point
  2  $in        Register to be inserted into.

Example:

    Mov r15, 0x100;                                                               # Given a register with a single one in it indicating the desired position,
    Mov r14, 0xFFDC;                                                              # Insert a zero into the register at that position shifting the bits above that position up left one to make space for the new zero.
    Mov r13, 0xF03F;
    PrintOutRegisterInHex         r14, r15;
    InsertZeroIntoRegisterAtPoint r15, r14;
    PrintOutRegisterInHex r14;
    Or r14, r15;                                                                  # Replace the inserted zero with a one
    PrintOutRegisterInHex r14;

    InsertOneIntoRegisterAtPoint r15, r13;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex r13;
    ok Assemble(debug => 0, eq => <<END);
     r14: 0000 0000 0000 FFDC
     r15: 0000 0000 0000 0100
     r14: 0000 0000 0001 FEDC
     r14: 0000 0000 0001 FFDC
     r13: 0000 0000 0001 E13F
  END

LoadZmm($zmm, @bytes)

Load a numbered zmm with the specified bytes.

     Parameter  Description
  1  $zmm       Numbered zmm
  2  @bytes     Bytes

Example:

    LoadZmm 0, 0..63;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex zmm 0;

    ok Assemble(debug => 0, eq => <<END);
    zmm0: 3F3E 3D3C 3B3A 3938   3736 3534 3332 3130   2F2E 2D2C 2B2A 2928   2726 2524 2322 2120   1F1E 1D1C 1B1A 1918   1716 1514 1312 1110   0F0E 0D0C 0B0A 0908   0706 0504 0302 0100
  END

Save and Restore

Saving and restoring registers via the stack

SaveFirstFour(@keep)

Save the first 4 parameter registers making any parameter registers read only.

     Parameter  Description
  1  @keep      Registers to mark as read only

Example:

    Mov rax, 1;
    Mov rdi, 1;

    SaveFirstFour;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSeven;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFour;
    PrintOutRegisterInHex rax, rdi;


    SaveFirstFour;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRax;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRax;
    PrintOutRegisterInHex rax, rdi;


    SaveFirstFour;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;
    SetLabel $l;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END

    ok 8 == RegisterSize rax;

RestoreFirstFour()

Restore the first 4 parameter registers.

Example:

    Mov rax, 1;
    Mov rdi, 1;
    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSeven;
    PrintOutRegisterInHex rax, rdi;

    RestoreFirstFour;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRax;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRax;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;
    SetLabel $l;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END

    ok 8 == RegisterSize rax;

RestoreFirstFourExceptRax()

Restore the first 4 parameter registers except rax so it can return its value.

Example:

    Mov rax, 1;
    Mov rdi, 1;
    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSeven;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFour;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRax;
    PrintOutRegisterInHex rax, rdi;

    RestoreFirstFourExceptRax;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;
    SetLabel $l;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END

    ok 8 == RegisterSize rax;

RestoreFirstFourExceptRaxAndRdi()

Restore the first 4 parameter registers except rax and rdi so we can return a pair of values.

Example:

    Mov rax, 1;
    Mov rdi, 1;
    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSeven;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFour;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRax;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRax;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    RestoreFirstFourExceptRaxAndRdi;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;
    SetLabel $l;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END

    ok 8 == RegisterSize rax;

SaveFirstSeven()

Save the first 7 parameter registers.

Example:

    Mov rax, 1;
    Mov rdi, 1;
    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;

    SaveFirstSeven;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSeven;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFour;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;

    SaveFirstSeven;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRax;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRax;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;

    SaveFirstSeven;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;
    SetLabel $l;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END

    ok 8 == RegisterSize rax;

RestoreFirstSeven()

Restore the first 7 parameter registers.

Example:

    Mov rax, 1;
    Mov rdi, 1;
    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;

    RestoreFirstSeven;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFour;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRax;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRax;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;
    SetLabel $l;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END

    ok 8 == RegisterSize rax;

RestoreFirstSevenExceptRax()

Restore the first 7 parameter registers except rax which is being used to return the result.

Example:

    Mov rax, 1;
    Mov rdi, 1;
    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSeven;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFour;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;

    RestoreFirstSevenExceptRax;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRax;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;
    SetLabel $l;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END

    ok 8 == RegisterSize rax;

RestoreFirstSevenExceptRaxAndRdi()

Restore the first 7 parameter registers except rax and rdi which are being used to return the results.

Example:

    Mov rax, 1;
    Mov rdi, 1;
    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSeven;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFour;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRax;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRax;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;

    RestoreFirstSevenExceptRaxAndRdi;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;
    SetLabel $l;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END

    ok 8 == RegisterSize rax;

ReorderSyscallRegisters(@registers)

Map the list of registers provided to the 64 bit system call sequence.

     Parameter   Description
  1  @registers  Registers

Example:

    Mov rax, 1;  Mov rdi, 2;  Mov rsi,  3;  Mov rdx,  4;
    Mov r8,  8;  Mov r9,  9;  Mov r10, 10;  Mov r11, 11;


    ReorderSyscallRegisters   r8,r9;                                              # Reorder the registers for syscall  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;
    PrintOutRegisterInHex rdi;

    UnReorderSyscallRegisters r8,r9;                                              # Unreorder the registers to recover their original values
    PrintOutRegisterInHex rax;
    PrintOutRegisterInHex rdi;

    ok Assemble =~ m(rax:.*08.*rdi:.*9.*rax:.*1.*rdi:.*2.*)s;

UnReorderSyscallRegisters(@registers)

Recover the initial values in registers that were reordered.

     Parameter   Description
  1  @registers  Registers

Example:

    Mov rax, 1;  Mov rdi, 2;  Mov rsi,  3;  Mov rdx,  4;
    Mov r8,  8;  Mov r9,  9;  Mov r10, 10;  Mov r11, 11;

    ReorderSyscallRegisters   r8,r9;                                              # Reorder the registers for syscall
    PrintOutRegisterInHex rax;
    PrintOutRegisterInHex rdi;


    UnReorderSyscallRegisters r8,r9;                                              # Unreorder the registers to recover their original values  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;
    PrintOutRegisterInHex rdi;

    ok Assemble =~ m(rax:.*08.*rdi:.*9.*rax:.*1.*rdi:.*2.*)s;

RegisterSize($r)

Return the size of a register.

     Parameter  Description
  1  $r         Register

Example:

    Mov rax, 1;
    Mov rdi, 1;
    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSeven;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFour;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRax;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRax;
    PrintOutRegisterInHex rax, rdi;

    SaveFirstFour;
    Mov rax, 2;
    Mov rdi, 2;
    SaveFirstSeven;
    Mov rax, 3;
    Mov rdi, 4;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstSevenExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;
    RestoreFirstFourExceptRaxAndRdi;
    PrintOutRegisterInHex rax, rdi;

    Bswap rax;
    PrintOutRegisterInHex rax;

    my $l = Label;
    Jmp $l;
    SetLabel $l;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0002
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0001
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0002
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0001
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0000 0000 0000 0003
     rdi: 0000 0000 0000 0004
     rax: 0300 0000 0000 0000
  END


    ok 8 == RegisterSize rax;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

ClearRegisters(@registers)

Clear registers by setting them to zero.

     Parameter   Description
  1  @registers  Registers

Example:

    Mov rax,1;
    Kmovq k0,  rax;
    Kaddb k0,  k0, k0;
    Kaddb k0,  k0, k0;
    Kaddb k0,  k0, k0;
    Kmovq rax, k0;
    PushR k0;

    ClearRegisters k0;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Kmovq k1, k0;
    PopR  k0;
    PrintOutRegisterInHex k0;
    PrintOutRegisterInHex k1;

    ok Assemble =~ m(k0: 0000 0000 0000 0008.*k1: 0000 0000 0000 0000)s;

SetMaskRegister($mask, $start, $length)

Set the mask register to ones starting at the specified position for the specified length and zeroes elsewhere.

     Parameter  Description
  1  $mask      Mask register to set
  2  $start     Register containing start position or 0 for position 0
  3  $length    Register containing end position

Example:

    Mov rax, 8;
    Mov rsi, -1;

    Inc rsi; SetMaskRegister(k0, rax, rsi); PrintOutRegisterInHex k0;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Inc rsi; SetMaskRegister(k1, rax, rsi); PrintOutRegisterInHex k1;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Inc rsi; SetMaskRegister(k2, rax, rsi); PrintOutRegisterInHex k2;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Inc rsi; SetMaskRegister(k3, rax, rsi); PrintOutRegisterInHex k3;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Inc rsi; SetMaskRegister(k4, rax, rsi); PrintOutRegisterInHex k4;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Inc rsi; SetMaskRegister(k5, rax, rsi); PrintOutRegisterInHex k5;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Inc rsi; SetMaskRegister(k6, rax, rsi); PrintOutRegisterInHex k6;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Inc rsi; SetMaskRegister(k7, rax, rsi); PrintOutRegisterInHex k7;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 0, eq => <<END);
      k0: 0000 0000 0000 0000
      k1: 0000 0000 0000 0100
      k2: 0000 0000 0000 0300
      k3: 0000 0000 0000 0700
      k4: 0000 0000 0000 0F00
      k5: 0000 0000 0000 1F00
      k6: 0000 0000 0000 3F00
      k7: 0000 0000 0000 7F00
  END

SetZF()

Set the zero flag.

Example:

    SetZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutZF;
    ClearZF;
    PrintOutZF;

    SetZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutZF;

    SetZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutZF;
    ClearZF;
    PrintOutZF;


    SetZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    IfZ  Then {PrintOutStringNL "Zero"},     Else {PrintOutStringNL "NOT zero"};
    ClearZF;
    IfNz Then {PrintOutStringNL "NOT zero"}, Else {PrintOutStringNL "Zero"};

    Mov r15, 5;
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};
    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};
    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};

    ok Assemble(debug => 0, eq => <<END);
  ZF=1
  ZF=0
  ZF=1
  ZF=1
  ZF=0
  Zero
  NOT zero
  Carry
  NO carry
  Carry
  NO carry
  END

ClearZF()

Clear the zero flag.

Example:

    SetZF;
    PrintOutZF;

    ClearZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutZF;
    SetZF;
    PrintOutZF;
    SetZF;
    PrintOutZF;

    ClearZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutZF;

    SetZF;
    IfZ  Then {PrintOutStringNL "Zero"},     Else {PrintOutStringNL "NOT zero"};

    ClearZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    IfNz Then {PrintOutStringNL "NOT zero"}, Else {PrintOutStringNL "Zero"};

    Mov r15, 5;
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};
    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};
    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};

    ok Assemble(debug => 0, eq => <<END);
  ZF=1
  ZF=0
  ZF=1
  ZF=1
  ZF=0
  Zero
  NOT zero
  Carry
  NO carry
  Carry
  NO carry
  END

Mask

Operations on mask registers

CheckMaskRegister($mask)

Check that a register is in fact a mask register.

     Parameter  Description
  1  $mask      Mask register to check

LoadConstantIntoMaskRegister($mask, $transfer, $value)

Set a mask register equal to a constant.

     Parameter  Description
  1  $mask      Mask register to load
  2  $transfer  Transfer register
  3  $value     Constant to load

Example:

    Mov r14, 0;
    Kmovq k0, r14;
    Ktestq k0, k0;
    IfZ Then {PrintOutStringNL "0 & 0 == 0"};
    PrintOutZF;


    LoadConstantIntoMaskRegister k1, r13, 1;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Ktestq k1, k1;
    IfNz Then {PrintOutStringNL "1 & 1 != 0"};
    PrintOutZF;


    LoadConstantIntoMaskRegister k2, r13, eval "0b".(('1'x4).('0'x4))x2;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    PrintOutRegisterInHex k0, k1, k2;

    Mov  r15, 0x89abcdef;
    Mov  r14, 0x01234567;
    Shl  r14, 32;
    Or r15, r14;
    Push r15;
    Push r15;
    PopEax;  PrintRaxInHex($stdout, 3); PrintOutNL;

    my $a = V('aaaa');
    $a->pop;
    $a->push;
    $a->outNL;

    PopEax;  PrintRaxInHex($stdout, 3); PrintOutNL;

    ok Assemble(debug => 0, eq => <<END);
  0 & 0 == 0
  ZF=1
  1 & 1 != 0
  ZF=0
      k0: 0000 0000 0000 0000
      k1: 0000 0000 0000 0001
      k2: 0000 0000 0000 F0F0
  89AB CDEF
  aaaa: 89AB CDEF 0123 4567
  0123 4567
  END

LoadBitsIntoMaskRegister($mask, $transfer, $prefix, @values)

Load a bit string specification into a mask register.

     Parameter  Description
  1  $mask      Mask register to load
  2  $transfer  Transfer register
  3  $prefix    Prefix bits
  4  @values    +n 1 bits -n 0 bits

Example:

    for (0..7)
     {ClearRegisters "k$_";
      K($_,$_)->setMaskBit("k$_");
      PrintOutRegisterInHex "k$_";
     }

    ClearRegisters k7;

    LoadBitsIntoMaskRegister(k7, r15, '1010', -4, +4, -2, +2, -1, +1, -1, +1);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex "k7";

    ok Assemble(debug => 0, eq => <<END);
      k0: 0000 0000 0000 0001
      k1: 0000 0000 0000 0002
      k2: 0000 0000 0000 0004
      k3: 0000 0000 0000 0008
      k4: 0000 0000 0000 0010
      k5: 0000 0000 0000 0020
      k6: 0000 0000 0000 0040
      k7: 0000 0000 0000 0080
      k7: 0000 0000 000A 0F35
  END

Structured Programming

Structured programming constructs

If($jump, $then, $else)

If.

     Parameter  Description
  1  $jump      Jump op code of variable
  2  $then      Then - required
  3  $else      Else - optional

Example:

    my $c = K(one,1);

    If ($c == 0,  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Then
     {PrintOutStringNL "1 == 0";
     },
    Else
     {PrintOutStringNL "1 != 0";
     });

    ok Assemble(debug => 0, eq => <<END);
  1 != 0
  END

Then($block)

Then block for an If statement.

     Parameter  Description
  1  $block     Then block

Example:

    my $a = V(a, 3);  $a->outNL;
    my $b = K(b, 2);  $b->outNL;
    my $c = $a +  $b; $c->outNL;
    my $d = $c -  $a; $d->outNL;
    my $g = $a *  $b; $g->outNL;
    my $h = $g /  $b; $h->outNL;
    my $i = $a %  $b; $i->outNL;

    If ($a == 3,

    Then  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {PrintOutStringNL "a == 3"
     },
    Else
     {PrintOutStringNL "a != 3"
     });

    ++$a; $a->outNL;
    --$a; $a->outNL;

    ok Assemble(debug => 0, eq => <<END);
  a: 0000 0000 0000 0003
  b: 0000 0000 0000 0002
  (a add b): 0000 0000 0000 0005
  ((a add b) sub a): 0000 0000 0000 0002
  (a times b): 0000 0000 0000 0006
  ((a times b) / b): 0000 0000 0000 0003
  (a % b): 0000 0000 0000 0001
  a == 3
  a: 0000 0000 0000 0004
  a: 0000 0000 0000 0003
  END

Else($block)

Else block for an If statement.

     Parameter  Description
  1  $block     Else block

Example:

    my $a = V(a, 3);  $a->outNL;
    my $b = K(b, 2);  $b->outNL;
    my $c = $a +  $b; $c->outNL;
    my $d = $c -  $a; $d->outNL;
    my $g = $a *  $b; $g->outNL;
    my $h = $g /  $b; $h->outNL;
    my $i = $a %  $b; $i->outNL;

    If ($a == 3,
    Then
     {PrintOutStringNL "a == 3"
     },

    Else  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {PrintOutStringNL "a != 3"
     });

    ++$a; $a->outNL;
    --$a; $a->outNL;

    ok Assemble(debug => 0, eq => <<END);
  a: 0000 0000 0000 0003
  b: 0000 0000 0000 0002
  (a add b): 0000 0000 0000 0005
  ((a add b) sub a): 0000 0000 0000 0002
  (a times b): 0000 0000 0000 0006
  ((a times b) / b): 0000 0000 0000 0003
  (a % b): 0000 0000 0000 0001
  a == 3
  a: 0000 0000 0000 0004
  a: 0000 0000 0000 0003
  END

Ef($condition, $then, $else)

Else if block for an If statement.

     Parameter   Description
  1  $condition  Condition
  2  $then       Then block
  3  $else       Else block

IfEq($then, $else)

If equal execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    my $cmp = sub
     {my ($a, $b) = @_;

      for my $op(qw(eq ne lt le gt ge))
       {Mov rax, $a;
        Cmp rax, $b;
        my $Op = ucfirst $op;
        eval qq(If$Op Then {PrintOutStringNL("$a $op $b")}, Else {PrintOutStringNL("$a NOT $op $b")});
        $@ and confess $@;
       }
     };
    &$cmp(1,1);
    &$cmp(1,2);
    &$cmp(3,2);
    Assemble(debug => 0, eq => <<END);
  1 eq 1
  1 NOT ne 1
  1 NOT lt 1
  1 le 1
  1 NOT gt 1
  1 ge 1
  1 NOT eq 2
  1 ne 2
  1 lt 2
  1 le 2
  1 NOT gt 2
  1 NOT ge 2
  3 NOT eq 2
  3 ne 2
  3 NOT lt 2
  3 NOT le 2
  3 gt 2
  3 ge 2
  END

IfNe($then, $else)

If not equal execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    my $cmp = sub
     {my ($a, $b) = @_;

      for my $op(qw(eq ne lt le gt ge))
       {Mov rax, $a;
        Cmp rax, $b;
        my $Op = ucfirst $op;
        eval qq(If$Op Then {PrintOutStringNL("$a $op $b")}, Else {PrintOutStringNL("$a NOT $op $b")});
        $@ and confess $@;
       }
     };
    &$cmp(1,1);
    &$cmp(1,2);
    &$cmp(3,2);
    Assemble(debug => 0, eq => <<END);
  1 eq 1
  1 NOT ne 1
  1 NOT lt 1
  1 le 1
  1 NOT gt 1
  1 ge 1
  1 NOT eq 2
  1 ne 2
  1 lt 2
  1 le 2
  1 NOT gt 2
  1 NOT ge 2
  3 NOT eq 2
  3 ne 2
  3 NOT lt 2
  3 NOT le 2
  3 gt 2
  3 ge 2
  END

IfNz($then, $else)

If the zero flag is not set then execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    Mov rax, 0;
    Test rax,rax;

    IfNz  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Then
     {PrintOutRegisterInHex rax;
     },
    Else
     {PrintOutRegisterInHex rbx;
     };
    Mov rax, 1;
    Test rax,rax;

    IfNz  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Then
     {PrintOutRegisterInHex rcx;
     },
    Else
     {PrintOutRegisterInHex rdx;
     };

    ok Assemble =~ m(rbx.*rcx)s;

IfZ($then, $else)

If the zero flag is set then execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    SetZF;
    PrintOutZF;
    ClearZF;
    PrintOutZF;
    SetZF;
    PrintOutZF;
    SetZF;
    PrintOutZF;
    ClearZF;
    PrintOutZF;

    SetZF;

    IfZ  Then {PrintOutStringNL "Zero"},     Else {PrintOutStringNL "NOT zero"};  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    ClearZF;
    IfNz Then {PrintOutStringNL "NOT zero"}, Else {PrintOutStringNL "Zero"};

    Mov r15, 5;
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};
    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};
    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};

    ok Assemble(debug => 0, eq => <<END);
  ZF=1
  ZF=0
  ZF=1
  ZF=1
  ZF=0
  Zero
  NOT zero
  Carry
  NO carry
  Carry
  NO carry
  END

IfC($then, $else)

If the carry flag is set then execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    SetZF;
    PrintOutZF;
    ClearZF;
    PrintOutZF;
    SetZF;
    PrintOutZF;
    SetZF;
    PrintOutZF;
    ClearZF;
    PrintOutZF;

    SetZF;
    IfZ  Then {PrintOutStringNL "Zero"},     Else {PrintOutStringNL "NOT zero"};
    ClearZF;
    IfNz Then {PrintOutStringNL "NOT zero"}, Else {PrintOutStringNL "Zero"};

    Mov r15, 5;

    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};
    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};

    ok Assemble(debug => 0, eq => <<END);
  ZF=1
  ZF=0
  ZF=1
  ZF=1
  ZF=0
  Zero
  NOT zero
  Carry
  NO carry
  Carry
  NO carry
  END

IfNc($then, $else)

If the carry flag is not set then execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    SetZF;
    PrintOutZF;
    ClearZF;
    PrintOutZF;
    SetZF;
    PrintOutZF;
    SetZF;
    PrintOutZF;
    ClearZF;
    PrintOutZF;

    SetZF;
    IfZ  Then {PrintOutStringNL "Zero"},     Else {PrintOutStringNL "NOT zero"};
    ClearZF;
    IfNz Then {PrintOutStringNL "NOT zero"}, Else {PrintOutStringNL "Zero"};

    Mov r15, 5;
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};

    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 0, eq => <<END);
  ZF=1
  ZF=0
  ZF=1
  ZF=1
  ZF=0
  Zero
  NOT zero
  Carry
  NO carry
  Carry
  NO carry
  END

IfLt($then, $else)

If less than execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    my $cmp = sub
     {my ($a, $b) = @_;

      for my $op(qw(eq ne lt le gt ge))
       {Mov rax, $a;
        Cmp rax, $b;
        my $Op = ucfirst $op;
        eval qq(If$Op Then {PrintOutStringNL("$a $op $b")}, Else {PrintOutStringNL("$a NOT $op $b")});
        $@ and confess $@;
       }
     };
    &$cmp(1,1);
    &$cmp(1,2);
    &$cmp(3,2);
    Assemble(debug => 0, eq => <<END);
  1 eq 1
  1 NOT ne 1
  1 NOT lt 1
  1 le 1
  1 NOT gt 1
  1 ge 1
  1 NOT eq 2
  1 ne 2
  1 lt 2
  1 le 2
  1 NOT gt 2
  1 NOT ge 2
  3 NOT eq 2
  3 ne 2
  3 NOT lt 2
  3 NOT le 2
  3 gt 2
  3 ge 2
  END

IfLe($then, $else)

If less than or equal execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    my $cmp = sub
     {my ($a, $b) = @_;

      for my $op(qw(eq ne lt le gt ge))
       {Mov rax, $a;
        Cmp rax, $b;
        my $Op = ucfirst $op;
        eval qq(If$Op Then {PrintOutStringNL("$a $op $b")}, Else {PrintOutStringNL("$a NOT $op $b")});
        $@ and confess $@;
       }
     };
    &$cmp(1,1);
    &$cmp(1,2);
    &$cmp(3,2);
    Assemble(debug => 0, eq => <<END);
  1 eq 1
  1 NOT ne 1
  1 NOT lt 1
  1 le 1
  1 NOT gt 1
  1 ge 1
  1 NOT eq 2
  1 ne 2
  1 lt 2
  1 le 2
  1 NOT gt 2
  1 NOT ge 2
  3 NOT eq 2
  3 ne 2
  3 NOT lt 2
  3 NOT le 2
  3 gt 2
  3 ge 2
  END

IfGt($then, $else)

If greater than execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    my $cmp = sub
     {my ($a, $b) = @_;

      for my $op(qw(eq ne lt le gt ge))
       {Mov rax, $a;
        Cmp rax, $b;
        my $Op = ucfirst $op;
        eval qq(If$Op Then {PrintOutStringNL("$a $op $b")}, Else {PrintOutStringNL("$a NOT $op $b")});
        $@ and confess $@;
       }
     };
    &$cmp(1,1);
    &$cmp(1,2);
    &$cmp(3,2);
    Assemble(debug => 0, eq => <<END);
  1 eq 1
  1 NOT ne 1
  1 NOT lt 1
  1 le 1
  1 NOT gt 1
  1 ge 1
  1 NOT eq 2
  1 ne 2
  1 lt 2
  1 le 2
  1 NOT gt 2
  1 NOT ge 2
  3 NOT eq 2
  3 ne 2
  3 NOT lt 2
  3 NOT le 2
  3 gt 2
  3 ge 2
  END

IfGe($then, $else)

If greater than or equal execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Example:

    my $cmp = sub
     {my ($a, $b) = @_;

      for my $op(qw(eq ne lt le gt ge))
       {Mov rax, $a;
        Cmp rax, $b;
        my $Op = ucfirst $op;
        eval qq(If$Op Then {PrintOutStringNL("$a $op $b")}, Else {PrintOutStringNL("$a NOT $op $b")});
        $@ and confess $@;
       }
     };
    &$cmp(1,1);
    &$cmp(1,2);
    &$cmp(3,2);
    Assemble(debug => 0, eq => <<END);
  1 eq 1
  1 NOT ne 1
  1 NOT lt 1
  1 le 1
  1 NOT gt 1
  1 ge 1
  1 NOT eq 2
  1 ne 2
  1 lt 2
  1 le 2
  1 NOT gt 2
  1 NOT ge 2
  3 NOT eq 2
  3 ne 2
  3 NOT lt 2
  3 NOT le 2
  3 gt 2
  3 ge 2
  END

IfS($then, $else)

If signed greater than or equal execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

IfNs($then, $else)

If signed less than execute the then block else the else block.

     Parameter  Description
  1  $then      Then - required
  2  $else      Else - optional

Pass($block)

Pass block for an OrBlock.

     Parameter  Description
  1  $block     Block

Example:

    Mov rax, 1;
    OrBlock
     {my ($pass, $end, $start) = @_;
      Cmp rax, 1;
      Je  $pass;
      Cmp rax, 2;
      Je  $pass;
      PrintOutStringNL "Fail";
     }

    Pass  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($end, $pass, $start) = @_;

      PrintOutStringNL "Pass";  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     };

    ok Assemble(debug => 0, eq => <<END);

  Pass  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  END

Fail($block)

Fail block for an AndBlock.

     Parameter  Description
  1  $block     Block

Example:

    Mov rax, 1; Mov rdx, 2;
    AndBlock
     {my ($fail, $end, $start) = @_;
      Cmp rax, 1;
      Jne $fail;
      Cmp rdx, 2;
      Jne $fail;
      PrintOutStringNL "Pass";
     }

    Fail  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($end, $fail, $start) = @_;

      PrintOutStringNL "Fail";  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     };

    ok Assemble(debug => 0, eq => <<END);
  Pass
  END

AndBlock($test, $fail)

Short circuit and: execute a block of code to test conditions which, if all of them pass, allows the first block to continue successfully else if one of the conditions fails we execute the optional fail block.

     Parameter  Description
  1  $test      Block
  2  $fail      Optional failure block

Example:

    Mov rax, 1; Mov rdx, 2;

    AndBlock  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($fail, $end, $start) = @_;
      Cmp rax, 1;
      Jne $fail;
      Cmp rdx, 2;
      Jne $fail;
      PrintOutStringNL "Pass";
     }
    Fail
     {my ($end, $fail, $start) = @_;
      PrintOutStringNL "Fail";
     };

    ok Assemble(debug => 0, eq => <<END);
  Pass
  END

OrBlock($test, $pass)

Short circuit or: execute a block of code to test conditions which, if one of them is met, leads on to the execution of the pass block, if all of the tests fail we continue withe the test block.

     Parameter  Description
  1  $test      Tests
  2  $pass      Optional block to execute on success

Example:

    Mov rax, 1;

    OrBlock  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($pass, $end, $start) = @_;
      Cmp rax, 1;
      Je  $pass;
      Cmp rax, 2;
      Je  $pass;
      PrintOutStringNL "Fail";
     }
    Pass
     {my ($end, $pass, $start) = @_;
      PrintOutStringNL "Pass";
     };

    ok Assemble(debug => 0, eq => <<END);
  Pass
  END

For($block, $register, $limit, $increment)

For - iterate the block as long as register is less than limit incrementing by increment each time. Nota Bene: The register is not explicitly set to zero as you might want to start at some other number.

     Parameter   Description
  1  $block      Block
  2  $register   Register
  3  $limit      Limit on loop
  4  $increment  Increment on each iteration

Example:

    For  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($start, $end, $next) = @_;
      Cmp rax, 3;
      Jge $end;
      PrintOutRegisterInHex rax;
     } rax, 16, 1;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0000
     rax: 0000 0000 0000 0001
     rax: 0000 0000 0000 0002
  END

ForIn($full, $last, $register, $limitRegister, $increment)

For - iterate the full block as long as register plus increment is less than than limit incrementing by increment each time then increment the last block for the last non full block.

     Parameter       Description
  1  $full           Block for full block
  2  $last           Block for last block
  3  $register       Register
  4  $limitRegister  Register containing upper limit of loop
  5  $increment      Increment on each iteration

ForEver($block)

Iterate for ever.

     Parameter  Description
  1  $block     Block to iterate

Macro($block, %options)

Create a sub with optional parameters name=> the name of the subroutine so it can be reused rather than regenerated, comment=> a comment describing the sub.

     Parameter  Description
  1  $block     Block
  2  %options   Options.

Call

Call a subroutine

SubroutineStartStack()

Initialize a new stack frame. The first quad of each frame has the address of the name of the sub in the low dword, and the parameter count in the upper byte of the quad. This field is all zeroes in the initial frame.

Subroutine($block, $parameters, %options)

Create a subroutine that can be called in assembler code.

     Parameter    Description
  1  $block       Block
  2  $parameters  [parameters  names]
  3  %options     Options.

Example:

    my $g = G g, 3;

    my $s = Subroutine  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($p, $s) = @_;
      $g->copy($g - 1);
      $g->outNL;
      If ($g > 0,
      Then
       {$s->call;
       });
     } [], name => 'ref';

    $s->call;

    ok Assemble(debug => 0, eq => <<END);
  g: 0000 0000 0000 0002
  g: 0000 0000 0000 0001
  g: 0000 0000 0000 0000
  END

    my $g = G g, 2;

    my $u = Subroutine  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($p, $s) = @_;
      PrintOutTraceBack;
      $$p{g}->copy(K gg, 1);
      PrintOutTraceBack;
     } [qw(g)], name => 'uuuu';

    my $t = Subroutine  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($p, $s) = @_;
      $u->call($$p{g});
     } [qw(g)], name => 'tttt';

    my $s = Subroutine  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($p, $s) = @_;
      $t->call($$p{g});
     } [qw(g)], name => 'ssss';

    $g->outNL;
    $s->call($g);
    $g->outNL;

    ok Assemble(debug => 0, eq => <<END);
  g: 0000 0000 0000 0002


  Subroutine trace back, depth: 0000 0000 0000 0003  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  0000 0000 0000 0002    uuuu
  0000 0000 0000 0002    tttt
  0000 0000 0000 0002    ssss



  Subroutine trace back, depth: 0000 0000 0000 0003  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  0000 0000 0000 0001    uuuu
  0000 0000 0000 0001    tttt
  0000 0000 0000 0001    ssss

  g: 0000 0000 0000 0001
  END

    my $r = G r, 2;


    my $u = Subroutine  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($p, $s) = @_;
      PrintOutTraceBack;
      $$p{u}->copy(K gg, 1);
      PrintOutTraceBack;
     } [qw(u)], name => 'uuuu';


    my $t = Subroutine  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($p, $s) = @_;
      $u->call(u => $$p{t});
     } [qw(t)], name => 'tttt';


    my $s = Subroutine  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my ($p, $s) = @_;
     $t->call(t => $$p{s});
     } [qw(s)], name => 'ssss';

    $r->outNL;
    $s->call(s=>$r);
    $r->outNL;

    ok Assemble(debug => 0, eq => <<END);
  r: 0000 0000 0000 0002


  Subroutine trace back, depth: 0000 0000 0000 0003  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  0000 0000 0000 0002    uuuu
  0000 0000 0000 0002    tttt
  0000 0000 0000 0002    ssss



  Subroutine trace back, depth: 0000 0000 0000 0003  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  0000 0000 0000 0001    uuuu
  0000 0000 0000 0001    tttt
  0000 0000 0000 0001    ssss

  r: 0000 0000 0000 0001
  END

Nasm::X86::Sub::call($sub, @parameters)

Call a sub passing it some parameters.

     Parameter    Description
  1  $sub         Subroutine descriptor
  2  @parameters  Parameter variables

Example:

    my $s = Subroutine
     {my ($p) = @_;
      $$p{in}->outNL;
     } [qw(in)], name => 'sss';

    my $t = Subroutine
     {my ($p) = @_;
      $s->call($$p{in});
     } [qw(in)], name => 'ttt';

    my $c = Subroutine
     {my ($p) = @_;
      $t->via($$p{call}, $$p{in});
     } [qw(call in)], name => 'ccc';

    $c->call($t->V, V(in, 42));

    ok Assemble(debug => 0, eq => <<END);
  in: 0000 0000 0000 002A
  END

Nasm::X86::Sub::via($sub, $ref, @parameters)

Call a sub by reference passing it some parameters.

     Parameter    Description
  1  $sub         Subroutine descriptor
  2  $ref         Variable containing a reference to the sub
  3  @parameters  Parameter variables

Example:

    my $s = Subroutine
     {my ($p) = @_;
      $$p{in}->outNL;
     } [qw(in)], name => 'sss';

    my $t = Subroutine
     {my ($p) = @_;
      $s->call($$p{in});
     } [qw(in)], name => 'ttt';

    my $c = Subroutine
     {my ($p) = @_;
      $t->via($$p{call}, $$p{in});
     } [qw(call in)], name => 'ccc';

    $c->call($t->V, V(in, 42));

    ok Assemble(debug => 0, eq => <<END);
  in: 0000 0000 0000 002A
  END

Nasm::X86::Sub::V($sub)

Put the address of a subroutine into a stack variable so that it can be passed as a parameter.

     Parameter  Description
  1  $sub       Subroutine descriptor

Nasm::X86::Sub::dispatch($sub, $transfer)

Jump into the specified subroutine so that code of the target subroutine is executed instead of the code of the current subroutine allowing the target subroutine to be dispatched to process the parameter list of the current subroutine. When the target subroutine returns it returns to the caller of the current sub, not to the current subroutine.

     Parameter  Description
  1  $sub       Subroutine descriptor of target subroutine
  2  $transfer  Transfer register

Example:

    my $p = Subroutine                                                            # Prototype subroutine to establish parameter list
     {} [qw(p)], name => 'prototype';

    my $a = Subroutine                                                            # Subroutine we are actually going to call
     {$p->variables->{p}->outNL;
     } [], name => 'actual', with => $p;

    my $d = Subroutine                                                            # Dispatcher
     {my ($p, $s) = @_;
      $a->dispatch(r15);
      PrintOutStringNL "This should NOT happen!";
     } [], name => 'dispatch', with => $p;

    $d->call(p => 0xcc);
    PrintOutStringNL "This should happen!";

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  p: 0000 0000 0000 00CC
  This should happen!
  END

Nasm::X86::Sub::dispatchV($sub, $reference, $transfer)

Dispatch the variable subroutine using the specified register.

     Parameter   Description
  1  $sub        Subroutine descriptor
  2  $reference  Variable referring to the target subroutine
  3  $transfer   Transfer register

Example:

    my $s = Subroutine                                                            # Containing sub
     {my ($parameters, $sub) = @_;

      my $p = Subroutine                                                          # Prototype subroutine with cascading parameter lists
       {} [qw(q)], with => $sub, name => 'prototype';

      my $a = Subroutine                                                          # Subroutine we are actually going to call with extended parameter list
       {$p->variables->{p}->outNL;
        $p->variables->{q}->outNL;
       } [], name => 'actual', with => $p;

      my $d = Subroutine                                                          # Dispatcher
       {my ($p, $s) = @_;
        $a->dispatchV($a->V, r15);
        PrintOutStringNL "This should NOT happen!";
       } [], name => 'dispatch', with => $p;

      $d->call(q => 0xdd) ;                                                       # Extend cascading parameter list
     } [qw(p)], name => 'outer';

    $s->call(p => 0xcc);                                                          # Start cascading parameter list
    PrintOutStringNL "This should happen!";

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  p: 0000 0000 0000 00CC
  q: 0000 0000 0000 00DD
  This should happen!
  END

PrintTraceBack($channel)

Trace the call stack.

     Parameter  Description
  1  $channel   Channel to write on

PrintErrTraceBack()

Print sub routine track back on stderr.

PrintOutTraceBack()

Print sub routine track back on stdout.

Example:

    my $d = V depth, 3;                                                           # Create a variable on the stack

    my $s = Subroutine
     {my ($p, $s) = @_;                                                           # Parameters, subroutine descriptor

      PrintOutTraceBack;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


      my $d = $$p{depth}->copy($$p{depth} - 1);                                   # Modify the variable referenced by the parameter

      If ($d > 0,
      Then
       {$s->call($d);                                                             # Recurse
       });


      PrintOutTraceBack;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     } [qw(depth)], name => 'ref';

    $s->call($d);                                                                 # Call the subroutine

    ok Assemble(debug => 0, eq => <<END);

  Subroutine trace back, depth: 0000 0000 0000 0001
  0000 0000 0000 0003    ref


  Subroutine trace back, depth: 0000 0000 0000 0002
  0000 0000 0000 0002    ref
  0000 0000 0000 0002    ref


  Subroutine trace back, depth: 0000 0000 0000 0003
  0000 0000 0000 0001    ref
  0000 0000 0000 0001    ref
  0000 0000 0000 0001    ref


  Subroutine trace back, depth: 0000 0000 0000 0003
  0000 0000 0000 0000    ref
  0000 0000 0000 0000    ref
  0000 0000 0000 0000    ref


  Subroutine trace back, depth: 0000 0000 0000 0002
  0000 0000 0000 0000    ref
  0000 0000 0000 0000    ref


  Subroutine trace back, depth: 0000 0000 0000 0001
  0000 0000 0000 0000    ref

  END

OnSegv()

Request a trace back followed by exit on a segv signal.

Example:

    OnSegv();                                                                     # Request a trace back followed by exit on a segv signal.  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    my $t = Subroutine                                                            # Subroutine that will cause an error to occur to force a trace back to be printed
     {Mov r15, 0;
      Mov r15, "[r15]";                                                           # Try to read an unmapped memory location
     } [qw(in)], name => 'sub that causes a segv';                                # The name that will appear in the trace back

    $t->call(K(in, 42));

    ok Assemble(debug => 0, keep2 => 'signal', emulator=>0, eq => <<END);         # Cannot use the emulator because it does not understand signals

  Subroutine trace back, depth: 0000 0000 0000 0001
  0000 0000 0000 002A    sub that causes a segv

  END

cr($block, @registers)

Call a subroutine with a reordering of the registers.

     Parameter   Description
  1  $block      Code to execute with reordered registers
  2  @registers  Registers to reorder

Comments

Inserts comments into the generated assember code.

CommentWithTraceBack(@comment)

Insert a comment into the assembly code with a traceback showing how it was generated.

     Parameter  Description
  1  @comment   Text of comment

Comment(@comment)

Insert a comment into the assembly code.

     Parameter  Description
  1  @comment   Text of comment

Example:

    Comment "Print a string from memory";  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $s = "Hello World";
    Mov rax, Rs($s);
    Mov rdi, length $s;
    PrintOutMemory;
    Exit(0);

    ok Assemble =~ m(Hello World);

DComment(@comment)

Insert a comment into the data segment.

     Parameter  Description
  1  @comment   Text of comment

RComment(@comment)

Insert a comment into the read only data segment.

     Parameter  Description
  1  @comment   Text of comment

Print

Print

PrintNL($channel)

Print a new line to stdout or stderr.

     Parameter  Description
  1  $channel   Channel to write on

PrintErrNL()

Print a new line to stderr.

PrintOutNL()

Print a new line to stderr.

Example:

    my $q = Rs('abababab');
    Mov(rax, "[$q]");
    PrintOutString "rax: ";
    PrintOutRaxInHex;

    PrintOutNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Xor rax, rax;
    PrintOutString "rax: ";
    PrintOutRaxInHex;

    PrintOutNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble =~ m(rax: 6261 6261 6261 6261.*rax: 0000 0000 0000 0000)s;

PrintString($channel, @string)

Print a constant string to the specified channel.

     Parameter  Description
  1  $channel   Channel
  2  @string    Strings

PrintStringNL($channel, @string)

Print a constant string to the specified channel followed by a new line.

     Parameter  Description
  1  $channel   Channel
  2  @string    Strings

PrintErrString(@string)

Print a constant string to stderr.

     Parameter  Description
  1  @string    String

PrintOutString(@string)

Print a constant string to stdout.

     Parameter  Description
  1  @string    String

Example:

    my $q = Rs('abababab');
    Mov(rax, "[$q]");

    PrintOutString "rax: ";  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRaxInHex;
    PrintOutNL;
    Xor rax, rax;

    PrintOutString "rax: ";  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRaxInHex;
    PrintOutNL;

    ok Assemble =~ m(rax: 6261 6261 6261 6261.*rax: 0000 0000 0000 0000)s;

PrintSpace($channel, $spaces)

Print one or more spaces to the specified channel.

     Parameter  Description
  1  $channel   Channel
  2  $spaces    Number of spaces if not one.

PrintErrSpace($spaces)

Print one or more spaces to stderr.

     Parameter  Description
  1  $spaces    Number of spaces if not one.

PrintOutSpace($spaces)

Print one or more spaces to stdout.

     Parameter  Description
  1  $spaces    Number of spaces if not one.

PrintErrStringNL(@string)

Print a constant string followed by a new line to stderr.

     Parameter  Description
  1  @string    Strings

Example:

    PrintOutStringNL "Hello World";
    PrintOutStringNL "Hello
World";

    PrintErrStringNL "Hello World";  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 0, eq => <<END);
  Hello World
  Hello
  World
  END

PrintOutStringNL(@string)

Print a constant string followed by a new line to stdout.

     Parameter  Description
  1  @string    Strings

Example:

    PrintOutStringNL "Hello World";  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    PrintOutStringNL "Hello
World";  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintErrStringNL "Hello World";

    ok Assemble(debug => 0, eq => <<END);
  Hello World
  Hello
  World
  END

PrintRaxInHex($channel, $end)

Write the content of register rax in hexadecimal in big endian notation to the specified channel.

     Parameter  Description
  1  $channel   Channel
  2  $end       Optional end byte

PrintRaxInHex22($channel, $end)

Write the content of register rax in hexadecimal in big endian notation to the specified channel.

     Parameter  Description
  1  $channel   Channel
  2  $end       Optional end byte

PrintErrRaxInHex()

Write the content of register rax in hexadecimal in big endian notation to stderr.

PrintErrRaxInHexNL()

Write the content of register rax in hexadecimal in big endian notation to stderr followed by a new line.

PrintOutRaxInHex()

Write the content of register rax in hexadecimal in big endian notation to stout.

Example:

    my $q = Rs('abababab');
    Mov(rax, "[$q]");
    PrintOutString "rax: ";

    PrintOutRaxInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutNL;
    Xor rax, rax;
    PrintOutString "rax: ";

    PrintOutRaxInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutNL;

    ok Assemble =~ m(rax: 6261 6261 6261 6261.*rax: 0000 0000 0000 0000)s;

PrintOutRaxInHexNL()

Write the content of register rax in hexadecimal in big endian notation to stdout followed by a new line

PrintOutRaxInReverseInHex()

Write the content of register rax to stderr in hexadecimal in little endian notation.

Example:

    Mov rax, 0x07654321;
    Shl rax, 32;
    Or  rax, 0x07654321;
    PushR rax;

    PrintOutRaxInHex;
    PrintOutNL;

    PrintOutRaxInReverseInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutNL;

    Mov rax, rsp;
    Mov rdi, 8;
    PrintOutMemoryInHex;
    PrintOutNL;
    PopR rax;

    Mov rax, 4096;
    PushR rax;
    Mov rax, rsp;
    Mov rdi, 8;
    PrintOutMemoryInHex;
    PrintOutNL;
    PopR rax;

    ok Assemble(debug => 0, eq => <<END);
  0765 4321 0765 4321
  2143 6507 2143 6507
  2143 6507 2143 6507
  0010 0000 0000 0000
  END

PrintOneRegisterInHex($channel, $r)

Print the named register as a hex string.

     Parameter  Description
  1  $channel   Channel to print on
  2  $r         Register to print

PrintRegisterInHex($channel, @r)

Print the named registers as hex strings.

     Parameter  Description
  1  $channel   Channel to print on
  2  @r         Names of the registers to print

PrintErrRegisterInHex(@r)

Print the named registers as hex strings on stderr.

     Parameter  Description
  1  @r         Names of the registers to print

PrintOutRegisterInHex(@r)

Print the named registers as hex strings on stdout.

     Parameter  Description
  1  @r         Names of the registers to print

Example:

    my $q = Rs(('a'..'p')x4);
    Mov r8,"[$q]";

    PrintOutRegisterInHex r8;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 0, eq => <<END);
      r8: 6867 6665 6463 6261
  END

PrintOutRegistersInHex()

Print the general purpose registers in hex.

Example:

    my $q = Rs('abababab');
    Mov(rax, 1);
    Mov(rbx, 2);
    Mov(rcx, 3);
    Mov(rdx, 4);
    Mov(r8,  5);
    Lea r9,  "[rax+rbx]";

    PrintOutRegistersInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    my $r = Assemble;
    ok $r =~ m( r8: 0000 0000 0000 0005.* r9: 0000 0000 0000 0003.*rax: 0000 0000 0000 0001)s;
    ok $r =~ m(rbx: 0000 0000 0000 0002.*rcx: 0000 0000 0000 0003.*rdx: 0000 0000 0000 0004)s;

PrintErrZF()

Print the zero flag without disturbing it on stderr.

PrintOutZF()

Print the zero flag without disturbing it on stdout.

Example:

    SetZF;

    PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    ClearZF;

    PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    SetZF;

    PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    SetZF;

    PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    ClearZF;

    PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    SetZF;
    IfZ  Then {PrintOutStringNL "Zero"},     Else {PrintOutStringNL "NOT zero"};
    ClearZF;
    IfNz Then {PrintOutStringNL "NOT zero"}, Else {PrintOutStringNL "Zero"};

    Mov r15, 5;
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};
    Shr r15, 1; IfC  Then {PrintOutStringNL "Carry"}   , Else {PrintOutStringNL "NO carry"};
    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};
    Shr r15, 1; IfNc Then {PrintOutStringNL "NO carry"}, Else {PrintOutStringNL "Carry"};

    ok Assemble(debug => 0, eq => <<END);
  ZF=1
  ZF=0
  ZF=1
  ZF=1
  ZF=0
  Zero
  NOT zero
  Carry
  NO carry
  Carry
  NO carry
  END

PrintUtf8Char($channel)

Print the utf 8 character addressed by rax to the specified channel. The character must be in little endian form.

     Parameter  Description
  1  $channel   Channel

PrintErrUtf8Char()

Print the utf 8 character addressed by rax to stderr.

PrintOutUtf8Char()

Print the utf 8 character addressed by rax to stdout.

Example:

    my $u = Rd(convertUtf32ToUtf8LE(ord('α')));
    Mov rax, $u;

    PrintOutUtf8Char;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutNL;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  α
  END

PrintErrUtf32($size, $address)

Print the utf 8 character addressed by rax to stderr.

     Parameter  Description
  1  $size      Variable: number of characters to print
  2  $address   Variable: address of memory

PrintOutUtf32($size, $address)

Print the utf 8 character addressed by rax to stdout.

     Parameter  Description
  1  $size      Variable: number of characters to print
  2  $address   Variable: address of memory

PrintRaxInDec($channel)

Print rax in decimal on the specified channel

     Parameter  Description
  1  $channel   Channel to write on

PrintOutRaxInDec()

Print rax in decimal on stdout

PrintOutRaxInDecNL()

Print rax in decimal on stdout followed by a new line

Example:

    Mov rax, 0;

    PrintOutRaxInDecNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Mov rax, 0x2a;

    PrintOutRaxInDecNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Mov rax, 1;

    PrintOutRaxInDecNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Mov rax, 255;

    PrintOutRaxInDecNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Mov rax, 123456;

    PrintOutRaxInDecNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Mov rax, 1234567890;

    PrintOutRaxInDecNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Mov rax, 0x2;
    Shl rax, 16;
    Mov rdx, 0xdfdc;
    Or rax, rdx;
    Shl rax, 16;
    Mov rdx, 0x1c35;
    Or rax, rdx;

    PrintOutRaxInDecNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


  # 1C BE99 1A14
    Mov rax, 0x1c;
    Shl rax, 16;
    Mov rdx, 0xbe99;
    Or rax, rdx;
    Shl rax, 16;
    Mov rdx, 0x1a14;
    Or rax, rdx;

    PrintOutRaxInDecNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


  # 2 EE33 3961
    Mov rax, 0x2;
    Shl rax, 16;
    Mov rdx, 0xee33;
    Or rax, rdx;
    Shl rax, 16;
    Mov rdx, 0x3961;
    Or rax, rdx;

    PrintOutRaxInDecNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble eq => <<END;
  0
  42
  1
  255
  123456
  1234567890
  12345678901
  123456789012
  12586269025
  END

PrintErrRaxInDec()

Print rax in decimal on stderr

PrintErrRaxInDecNL()

Print rax in decimal on stderr followed by a new line

Variables

Variable definitions and operations

Definitions

Variable definitions

Variable($name, $expr, %options)

Create a new variable with the specified name initialized via an optional expression.

     Parameter  Description
  1  $name      Name of variable
  2  $expr      Optional expression initializing variable
  3  %options   Options

G($name, $expr, %options)

Define a global variable. Global variables with the same name are not necessarily the same variable. Two global variables are identical iff they have have the same label field.

     Parameter  Description
  1  $name      Name of variable
  2  $expr      Initializing expression
  3  %options   Options

Example:

    my $s = Subroutine
     {my ($p) = @_;
      $$p{v}->copy($$p{v} + $$p{k} + $$p{g} + 1);
     } [qw(v k g)], name => 'add';

    my $v = V(v, 1);
    my $k = K(k, 2);

    my $g = G(g, 3);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $s->call($v, $k, $g);
    $v->outNL;

    ok Assemble(debug => 0, eq => <<END);
  v: 0000 0000 0000 0007
  END


    my $g = G g, 0;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $s = Subroutine
     {my ($p) = @_;
      $$p{g}->copy(K value, 1);
     } [qw(g)], name => 'ref2';

    my $t = Subroutine
     {my ($p) = @_;
      $s->call($$p{g});
     } [qw(g)], name => 'ref';

    $t->call($g);
    $g->outNL;

    ok Assemble(debug => 0, eq => <<END);
  g: 0000 0000 0000 0001
  END

K($name, $expr, %options)

Define a constant variable.

     Parameter  Description
  1  $name      Name of variable
  2  $expr      Initializing expression
  3  %options   Options

Example:

    my $s = Subroutine
     {my ($p) = @_;
      $$p{v}->copy($$p{v} + $$p{k} + $$p{g} + 1);
     } [qw(v k g)], name => 'add';

    my $v = V(v, 1);

    my $k = K(k, 2);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $g = G(g, 3);
    $s->call($v, $k, $g);
    $v->outNL;

    ok Assemble(debug => 0, eq => <<END);
  v: 0000 0000 0000 0007
  END

    my $g = G g, 0;
    my $s = Subroutine
     {my ($p) = @_;

      $$p{g}->copy(K value, 1);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     } [qw(g)], name => 'ref2';

    my $t = Subroutine
     {my ($p) = @_;
      $s->call($$p{g});
     } [qw(g)], name => 'ref';

    $t->call($g);
    $g->outNL;

    ok Assemble(debug => 0, eq => <<END);
  g: 0000 0000 0000 0001
  END

    my $a = V(a, 3);  $a->outNL;

    my $b = K(b, 2);  $b->outNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $c = $a +  $b; $c->outNL;
    my $d = $c -  $a; $d->outNL;
    my $g = $a *  $b; $g->outNL;
    my $h = $g /  $b; $h->outNL;
    my $i = $a %  $b; $i->outNL;

    If ($a == 3,
    Then
     {PrintOutStringNL "a == 3"
     },
    Else
     {PrintOutStringNL "a != 3"
     });

    ++$a; $a->outNL;
    --$a; $a->outNL;

    ok Assemble(debug => 0, eq => <<END);
  a: 0000 0000 0000 0003
  b: 0000 0000 0000 0002
  (a add b): 0000 0000 0000 0005
  ((a add b) sub a): 0000 0000 0000 0002
  (a times b): 0000 0000 0000 0006
  ((a times b) / b): 0000 0000 0000 0003
  (a % b): 0000 0000 0000 0001
  a == 3
  a: 0000 0000 0000 0004
  a: 0000 0000 0000 0003
  END

R($name)

Define a reference variable.

     Parameter  Description
  1  $name      Name of variable

V($name, $expr, %options)

Define a variable.

     Parameter  Description
  1  $name      Name of variable
  2  $expr      Initializing expression
  3  %options   Options

Example:

    my $s = Subroutine
     {my ($p) = @_;
      $$p{v}->copy($$p{v} + $$p{k} + $$p{g} + 1);
     } [qw(v k g)], name => 'add';


    my $v = V(v, 1);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $k = K(k, 2);
    my $g = G(g, 3);
    $s->call($v, $k, $g);
    $v->outNL;

    ok Assemble(debug => 0, eq => <<END);
  v: 0000 0000 0000 0007
  END

    my $g = G g, 0;
    my $s = Subroutine
     {my ($p) = @_;
      $$p{g}->copy(K value, 1);
     } [qw(g)], name => 'ref2';

    my $t = Subroutine
     {my ($p) = @_;
      $s->call($$p{g});
     } [qw(g)], name => 'ref';

    $t->call($g);
    $g->outNL;

    ok Assemble(debug => 0, eq => <<END);
  g: 0000 0000 0000 0001
  END


    my $a = V(a, 3);  $a->outNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $b = K(b, 2);  $b->outNL;
    my $c = $a +  $b; $c->outNL;
    my $d = $c -  $a; $d->outNL;
    my $g = $a *  $b; $g->outNL;
    my $h = $g /  $b; $h->outNL;
    my $i = $a %  $b; $i->outNL;

    If ($a == 3,
    Then
     {PrintOutStringNL "a == 3"
     },
    Else
     {PrintOutStringNL "a != 3"
     });

    ++$a; $a->outNL;
    --$a; $a->outNL;

    ok Assemble(debug => 0, eq => <<END);
  a: 0000 0000 0000 0003
  b: 0000 0000 0000 0002
  (a add b): 0000 0000 0000 0005
  ((a add b) sub a): 0000 0000 0000 0002
  (a times b): 0000 0000 0000 0006
  ((a times b) / b): 0000 0000 0000 0003
  (a % b): 0000 0000 0000 0001
  a == 3
  a: 0000 0000 0000 0004
  a: 0000 0000 0000 0003
  END

Print the values of variables or the memory addressed by them

Nasm::X86::Variable::err($left, $title1, $title2)

Dump the value of a variable on stderr.

     Parameter  Description
  1  $left      Left variable
  2  $title1    Optional leading title
  3  $title2    Optional trailing title

Nasm::X86::Variable::out($left, $title1, $title2)

Dump the value of a variable on stdout.

     Parameter  Description
  1  $left      Left variable
  2  $title1    Optional leading title
  3  $title2    Optional trailing title

Nasm::X86::Variable::errNL($left, $title1, $title2)

Dump the value of a variable on stderr and append a new line.

     Parameter  Description
  1  $left      Left variable
  2  $title1    Optional leading title
  3  $title2    Optional trailing title

Nasm::X86::Variable::d($left, $title1, $title2)

Dump the value of a variable on stderr and append a new line.

     Parameter  Description
  1  $left      Left variable
  2  $title1    Optional leading title
  3  $title2    Optional trailing title

Nasm::X86::Variable::outNL($left, $title1, $title2)

Dump the value of a variable on stdout and append a new line.

     Parameter  Description
  1  $left      Left variable
  2  $title1    Optional leading title
  3  $title2    Optional trailing title

Nasm::X86::Variable::debug($left)

Dump the value of a variable on stdout with an indication of where the dump came from.

     Parameter  Description
  1  $left      Left variable

Nasm::X86::Variable::printOutZeroString($address)

Print the variable addressed zero terminated string on stdout.

     Parameter  Description
  1  $address   Variable string address

Example:

    my $s = Rutf8 '𝝰𝝱𝝲𝝳';
    V(address, $s)->printOutZeroString;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  𝝰𝝱𝝲𝝳
  END

Operations

Variable operations

Nasm::X86::Variable::call($target, $Transfer)

Execute the call instruction for a target whose address is held in the specified variable

     Parameter  Description
  1  $target    Variable containing the address of the code to call
  2  $Transfer  Optional transfer register

Example:

    my $l = "aaa.so";
    Mov rax, 0x12345678;
    Ret;

    ok Assemble library => $l;                                                    # Create the library file
    ok -e $l;

    my ($address, $size) = ReadFile $l;                                           # Read library file into memory

    Mov rax, 0;
    PrintOutRaxInHexNL;

    $address->call;                                                               # Call code in memory loaded from library file

    PrintOutRaxInHexNL;                                                           # Print value set in library

    ok Assemble eq =><<END;
  0000 0000 0000 0000
  0000 0000 1234 5678
  END
    unlink $l;

Nasm::X86::Variable::address($left, $offset)

Get the address of a variable with an optional offset.

     Parameter  Description
  1  $left      Left variable
  2  $offset    Optional offset

Nasm::X86::Variable::clone($variable, $name, $transfer)

Clone a variable.

     Parameter  Description
  1  $variable  Variable to clone
  2  $name      Optional name for variable
  3  $transfer  Optional transfer register

Nasm::X86::Variable::copy($left, $right, $Transfer)

Copy one variable into another.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable
  3  $Transfer  Optional transfer register

Example:

    my $s = Subroutine
     {my ($p) = @_;
      $$p{v}->copy($$p{v} + $$p{k} + $$p{g} + 1);
     } [qw(v k g)], name => 'add';

    my $v = V(v, 1);
    my $k = K(k, 2);
    my $g = G(g, 3);
    $s->call($v, $k, $g);
    $v->outNL;

    ok Assemble(debug => 0, eq => <<END);
  v: 0000 0000 0000 0007
  END

    my $g = G g, 0;
    my $s = Subroutine
     {my ($p) = @_;
      $$p{g}->copy(K value, 1);
     } [qw(g)], name => 'ref2';

    my $t = Subroutine
     {my ($p) = @_;
      $s->call($$p{g});
     } [qw(g)], name => 'ref';

    $t->call($g);
    $g->outNL;

    ok Assemble(debug => 0, eq => <<END);
  g: 0000 0000 0000 0001
  END

Nasm::X86::Variable::copyRef($left, $right, $Transfer)

Copy a reference to a variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable
  3  $Transfer  Optional transfer register

Nasm::X86::Variable::copyZF($var)

Copy the current state of the zero flag into a variable.

     Parameter  Description
  1  $var       Variable

Example:

    Mov r15, 1;
    my $z = V(zf);
    Cmp r15, 1; $z->copyZF;         $z->outNL;
    Cmp r15, 2; $z->copyZF;         $z->outNL;
    Cmp r15, 1; $z->copyZFInverted; $z->outNL;
    Cmp r15, 2; $z->copyZFInverted; $z->outNL;

    ok Assemble(debug => 0, eq => <<END);
  zf: 0000 0000 0000 0001
  zf: 0000 0000 0000 0000
  zf: 0000 0000 0000 0000
  zf: 0000 0000 0000 0001
  END

Nasm::X86::Variable::copyZFInverted($var)

Copy the opposite of the current state of the zero flag into a variable.

     Parameter  Description
  1  $var       Variable

Example:

    Mov r15, 1;
    my $z = V(zf);
    Cmp r15, 1; $z->copyZF;         $z->outNL;
    Cmp r15, 2; $z->copyZF;         $z->outNL;
    Cmp r15, 1; $z->copyZFInverted; $z->outNL;
    Cmp r15, 2; $z->copyZFInverted; $z->outNL;

    ok Assemble(debug => 0, eq => <<END);
  zf: 0000 0000 0000 0001
  zf: 0000 0000 0000 0000
  zf: 0000 0000 0000 0000
  zf: 0000 0000 0000 0001
  END

Nasm::X86::Variable::equals($op, $left, $right)

Equals operator.

     Parameter  Description
  1  $op        Operator
  2  $left      Left variable
  3  $right     Right variable

Nasm::X86::Variable::assign($left, $op, $right)

Assign to the left hand side the value of the right hand side.

     Parameter  Description
  1  $left      Left variable
  2  $op        Operator
  3  $right     Right variable

Nasm::X86::Variable::plusAssign($left, $right)

Implement plus and assign.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::minusAssign($left, $right)

Implement minus and assign.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::arithmetic($op, $name, $left, $right)

Return a variable containing the result of an arithmetic operation on the left hand and right hand side variables.

     Parameter  Description
  1  $op        Operator
  2  $name      Operator name
  3  $left      Left variable
  4  $right     Right variable

Nasm::X86::Variable::add($left, $right)

Add the right hand variable to the left hand variable and return the result as a new variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::sub($left, $right)

Subtract the right hand variable from the left hand variable and return the result as a new variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::times($left, $right)

Multiply the left hand variable by the right hand variable and return the result as a new variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::division($op, $left, $right)

Return a variable containing the result or the remainder that occurs when the left hand side is divided by the right hand side.

     Parameter  Description
  1  $op        Operator
  2  $left      Left variable
  3  $right     Right variable

Nasm::X86::Variable::divide($left, $right)

Divide the left hand variable by the right hand variable and return the result as a new variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::mod($left, $right)

Divide the left hand variable by the right hand variable and return the remainder as a new variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::boolean($sub, $op, $left, $right)

Combine the left hand variable with the right hand variable via a boolean operator.

     Parameter  Description
  1  $sub       Operator
  2  $op        Operator name
  3  $left      Left variable
  4  $right     Right variable

Nasm::X86::Variable::booleanZF($sub, $op, $left, $right)

Combine the left hand variable with the right hand variable via a boolean operator and indicate the result by setting the zero flag if the result is true.

     Parameter  Description
  1  $sub       Operator
  2  $op        Operator name
  3  $left      Left variable
  4  $right     Right variable

Nasm::X86::Variable::booleanC($cmov, $op, $left, $right)

Combine the left hand variable with the right hand variable via a boolean operator using a conditional move instruction.

     Parameter  Description
  1  $cmov      Conditional move instruction name
  2  $op        Operator name
  3  $left      Left variable
  4  $right     Right variable

Nasm::X86::Variable::eq($left, $right)

Check whether the left hand variable is equal to the right hand variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::ne($left, $right)

Check whether the left hand variable is not equal to the right hand variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::ge($left, $right)

Check whether the left hand variable is greater than or equal to the right hand variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::gt($left, $right)

Check whether the left hand variable is greater than the right hand variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::le($left, $right)

Check whether the left hand variable is less than or equal to the right hand variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::lt($left, $right)

Check whether the left hand variable is less than the right hand variable.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::isRef($variable)

Check whether the specified variable is a reference to another variable.

     Parameter  Description
  1  $variable  Variable

Nasm::X86::Variable::setReg($variable, $register)

Set the named registers from the content of the variable.

     Parameter  Description
  1  $variable  Variable
  2  $register  Register to load

Nasm::X86::Variable::getReg($variable, $register, @registers)

Load the variable from the named registers.

     Parameter   Description
  1  $variable   Variable
  2  $register   Register to load
  3  @registers  Optional further registers to load from

Nasm::X86::Variable::getConst($variable, $constant, $transfer)

Load the variable from a constant in effect setting a variable to a specified value.

     Parameter  Description
  1  $variable  Variable
  2  $constant  Constant to load
  3  $transfer  Optional transfer register

Nasm::X86::Variable::incDec($left, $op)

Increment or decrement a variable.

     Parameter  Description
  1  $left      Left variable operator
  2  $op        Address of operator to perform inc or dec

Nasm::X86::Variable::inc($left)

Increment a variable.

     Parameter  Description
  1  $left      Variable

Nasm::X86::Variable::dec($left)

Decrement a variable.

     Parameter  Description
  1  $left      Variable

Nasm::X86::Variable::str($left)

The name of the variable.

     Parameter  Description
  1  $left      Variable

Nasm::X86::Variable::min($left, $right)

Minimum of two variables.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable or constant

Example:

    my $a = V("a", 1);
    my $b = V("b", 2);
    my $c = $a->min($b);
    my $d = $a->max($b);
    $a->outNL;
    $b->outNL;
    $c->outNL;
    $d->outNL;

    ok Assemble(debug => 0, eq => <<END);
  a: 0000 0000 0000 0001
  b: 0000 0000 0000 0002
  min: 0000 0000 0000 0001
  max: 0000 0000 0000 0002
  END

Nasm::X86::Variable::max($left, $right)

Maximum of two variables.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable or constant

Example:

    my $a = V("a", 1);
    my $b = V("b", 2);
    my $c = $a->min($b);
    my $d = $a->max($b);
    $a->outNL;
    $b->outNL;
    $c->outNL;
    $d->outNL;

    ok Assemble(debug => 0, eq => <<END);
  a: 0000 0000 0000 0001
  b: 0000 0000 0000 0002
  min: 0000 0000 0000 0001
  max: 0000 0000 0000 0002
  END

Nasm::X86::Variable::and($left, $right)

And two variables.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::or($left, $right)

Or two variables.

     Parameter  Description
  1  $left      Left variable
  2  $right     Right variable

Nasm::X86::Variable::setMask($start, $length, $mask)

Set the mask register to ones starting at the specified position for the specified length and zeroes elsewhere.

     Parameter  Description
  1  $start     Variable containing start of mask
  2  $length    Variable containing length of mask
  3  $mask      Mask register

Example:

    my $start  = V("Start",  7);
    my $length = V("Length", 3);
    $start->setMask($length, k7);
    PrintOutRegisterInHex k7;

    ok Assemble(debug => 0, eq => <<END);
      k7: 0000 0000 0000 0380
  END

    my $z = V('zero', 0);
    my $o = V('one',  1);
    my $t = V('two',  2);
    $z->setMask($o,       k7); PrintOutRegisterInHex k7;
    $z->setMask($t,       k6); PrintOutRegisterInHex k6;
    $z->setMask($o+$t,    k5); PrintOutRegisterInHex k5;
    $o->setMask($o,       k4); PrintOutRegisterInHex k4;
    $o->setMask($t,       k3); PrintOutRegisterInHex k3;
    $o->setMask($o+$t,    k2); PrintOutRegisterInHex k2;

    $t->setMask($o,       k1); PrintOutRegisterInHex k1;
    $t->setMask($t,       k0); PrintOutRegisterInHex k0;


    ok Assemble(debug => 0, eq => <<END);
      k7: 0000 0000 0000 0001
      k6: 0000 0000 0000 0003
      k5: 0000 0000 0000 0007
      k4: 0000 0000 0000 0002
      k3: 0000 0000 0000 0006
      k2: 0000 0000 0000 000E
      k1: 0000 0000 0000 0004
      k0: 0000 0000 0000 000C
  END

Nasm::X86::Variable::setMaskFirst($length, $mask)

Set the first bits in the specified mask register.

     Parameter  Description
  1  $length    Variable containing length to set
  2  $mask      Mask register

Nasm::X86::Variable::setMaskBit($index, $mask)

Set a bit in the specified mask register retaining the other bits.

     Parameter  Description
  1  $index     Variable containing bit position to set
  2  $mask      Mask register

Nasm::X86::Variable::clearMaskBit($index, $mask)

Clear a bit in the specified mask register retaining the other bits.

     Parameter  Description
  1  $index     Variable containing bit position to clear
  2  $mask      Mask register

Nasm::X86::Variable::setBit($index, $mask)

Set a bit in the specified register retaining the other bits.

     Parameter  Description
  1  $index     Variable containing bit position to set
  2  $mask      Mask register

Nasm::X86::Variable::clearBit($index, $mask)

Clear a bit in the specified mask register retaining the other bits.

     Parameter  Description
  1  $index     Variable containing bit position to clear
  2  $mask      Mask register

Nasm::X86::Variable::setZmm($source, $zmm, $offset, $length)

Load bytes from the memory addressed by specified source variable into the numbered zmm register at the offset in the specified offset moving the number of bytes in the specified variable.

     Parameter  Description
  1  $source    Variable containing the address of the source
  2  $zmm       Number of zmm to load
  3  $offset    Variable containing offset in zmm to move to
  4  $length    Variable containing length of move

Example:

    my $s = Rb(0..128);
    my $source = V(Source, $s);

    if (1)                                                                        # First block
     {my $offset = V(Offset, 7);
      my $length = V(Length, 3);
      $source->setZmm(0, $offset, $length);
     }

    if (1)                                                                        # Second block
     {my $offset = V(Offset, 33);
      my $length = V(Length, 12);
      $source->setZmm(0, $offset, $length);
     }

    PrintOutRegisterInHex zmm0;

    ok Assemble(debug => 0, eq => <<END);
    zmm0: 0000 0000 0000 0000   0000 0000 0000 0000   0000 000B 0A09 0807   0605 0403 0201 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0201   0000 0000 0000 0000
  END

Nasm::X86::Variable::loadZmm($source, $zmm, $Transfer)

Load bytes from the memory addressed by the specified source variable into the numbered zmm register.

     Parameter  Description
  1  $source    Variable containing the address of the source
  2  $zmm       Number of zmm to get
  3  $Transfer  Optional transfer register

loadFromZmm($register, $size, $zmm, $offset)

Load the specified register from the offset located in the numbered zmm.

     Parameter  Description
  1  $register  Register to load
  2  $size      "b|w|d|q" for size
  3  $zmm       Numbered zmm register to load from
  4  $offset    Constant offset in bytes

putIntoZmm($register, $size, $zmm, $offset)

Put the specified register into the numbered zmm at the specified offset in the zmm.

     Parameter  Description
  1  $register  Register to load
  2  $size      Bwdq for size
  3  $zmm       Numbered zmm register to load from
  4  $offset    Constant offset in bytes

LoadRegFromMm($mm, $offset, $reg)

Load the specified register from the numbered zmm at the quad offset specified as a constant number.

     Parameter  Description
  1  $mm        Mm register
  2  $offset    Offset in quads
  3  $reg       General purpose register to load

SaveRegIntoMm($mm, $offset, $reg)

Save the specified register into the numbered zmm at the quad offset specified as a constant number.

     Parameter  Description
  1  $mm        Mm register
  2  $offset    Offset in quads
  3  $reg       General purpose register to load

getBwdqFromMm($size, $mm, $offset, $Transfer, $target)

Get the numbered byte|word|double word|quad word from the numbered zmm register and return it in a variable.

     Parameter  Description
  1  $size      Size of get
  2  $mm        Mm register
  3  $offset    Offset in bytes either as a constant or as a variable
  4  $Transfer  Optional transfer register
  5  $target    Optional target variable - if none supplied we create a variable

getBFromXmm($xmm, $offset)

Get the byte from the numbered xmm register and return it in a variable.

     Parameter  Description
  1  $xmm       Numbered xmm
  2  $offset    Offset in bytes

getWFromXmm($xmm, $offset)

Get the word from the numbered xmm register and return it in a variable.

     Parameter  Description
  1  $xmm       Numbered xmm
  2  $offset    Offset in bytes

getDFromXmm($xmm, $offset)

Get the double word from the numbered xmm register and return it in a variable.

     Parameter  Description
  1  $xmm       Numbered xmm
  2  $offset    Offset in bytes

getQFromXmm($xmm, $offset)

Get the quad word from the numbered xmm register and return it in a variable.

     Parameter  Description
  1  $xmm       Numbered xmm
  2  $offset    Offset in bytes

getBFromZmm($zmm, $offset)

Get the byte from the numbered zmm register and return it in a variable.

     Parameter  Description
  1  $zmm       Numbered zmm
  2  $offset    Offset in bytes

getWFromZmm($zmm, $offset)

Get the word from the numbered zmm register and return it in a variable.

     Parameter  Description
  1  $zmm       Numbered zmm
  2  $offset    Offset in bytes

getDFromZmm($zmm, $offset, $transfer)

Get the double word from the numbered zmm register and return it in a variable.

     Parameter  Description
  1  $zmm       Numbered zmm
  2  $offset    Offset in bytes
  3  $transfer  Optional transfer register

Example:

    my $s = Rb(0..8);
    my $c = V("Content",   "[$s]");
       $c->putBIntoZmm(0,  4);
       $c->putWIntoZmm(0,  6);
       $c->putDIntoZmm(0, 10);
       $c->putQIntoZmm(0, 16);
    PrintOutRegisterInHex zmm0;
    getBFromZmm(0, 12)->outNL;
    getWFromZmm(0, 12)->outNL;

    getDFromZmm(0, 12, r15)->outNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    getQFromZmm(0, 12)->outNL;

    ok Assemble(debug => 0, eq => <<END);
    zmm0: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0706 0504 0302 0100   0000 0302 0100 0000   0100 0000 0000 0000
  b at offset 12 in zmm0: 0000 0000 0000 0002
  w at offset 12 in zmm0: 0000 0000 0000 0302
  d at offset 12 in zmm0: 0000 0000 0000 0302
  q at offset 12 in zmm0: 0302 0100 0000 0302
  END

getQFromZmm($zmm, $offset)

Get the quad word from the numbered zmm register and return it in a variable.

     Parameter  Description
  1  $zmm       Numbered zmm
  2  $offset    Offset in bytes

Nasm::X86::Variable::getBFromZmm($variable, $zmm, $offset)

Get the byte from the numbered zmm register and put it in a variable.

     Parameter  Description
  1  $variable  Variable
  2  $zmm       Numbered zmm
  3  $offset    Offset in bytes

Nasm::X86::Variable::getWFromZmm($variable, $zmm, $offset)

Get the word from the numbered zmm register and put it in a variable.

     Parameter  Description
  1  $variable  Variable
  2  $zmm       Numbered zmm
  3  $offset    Offset in bytes

Nasm::X86::Variable::getDFromZmm($variable, $zmm, $offset, $transfer)

Get the double word from the numbered zmm register and put it in a variable.

     Parameter  Description
  1  $variable  Variable
  2  $zmm       Numbered zmm
  3  $offset    Offset in bytes
  4  $transfer  Transfer register

Nasm::X86::Variable::getQFromZmm($variable, $zmm, $offset)

Get the quad word from the numbered zmm register and put it in a variable.

     Parameter  Description
  1  $variable  Variable
  2  $zmm       Numbered zmm
  3  $offset    Offset in bytes

Nasm::X86::Variable::putBwdqIntoMm($content, $size, $mm, $offset, $Transfer)

Place the value of the content variable at the byte|word|double word|quad word in the numbered zmm register.

     Parameter  Description
  1  $content   Variable with content
  2  $size      Size of put
  3  $mm        Numbered zmm
  4  $offset    Offset in bytes
  5  $Transfer  Optional transfer register

Nasm::X86::Variable::putBIntoXmm($content, $xmm, $offset)

Place the value of the content variable at the byte in the numbered xmm register.

     Parameter  Description
  1  $content   Variable with content
  2  $xmm       Numbered xmm
  3  $offset    Offset in bytes

Nasm::X86::Variable::putWIntoXmm($content, $xmm, $offset)

Place the value of the content variable at the word in the numbered xmm register.

     Parameter  Description
  1  $content   Variable with content
  2  $xmm       Numbered xmm
  3  $offset    Offset in bytes

Nasm::X86::Variable::putDIntoXmm($content, $xmm, $offset)

Place the value of the content variable at the double word in the numbered xmm register.

     Parameter  Description
  1  $content   Variable with content
  2  $xmm       Numbered xmm
  3  $offset    Offset in bytes

Nasm::X86::Variable::putQIntoXmm($content, $xmm, $offset)

Place the value of the content variable at the quad word in the numbered xmm register.

     Parameter  Description
  1  $content   Variable with content
  2  $xmm       Numbered xmm
  3  $offset    Offset in bytes

Nasm::X86::Variable::putBIntoZmm($content, $zmm, $offset)

Place the value of the content variable at the byte in the numbered zmm register.

     Parameter  Description
  1  $content   Variable with content
  2  $zmm       Numbered zmm
  3  $offset    Offset in bytes

Nasm::X86::Variable::putWIntoZmm($content, $zmm, $offset)

Place the value of the content variable at the word in the numbered zmm register.

     Parameter  Description
  1  $content   Variable with content
  2  $zmm       Numbered zmm
  3  $offset    Offset in bytes

Nasm::X86::Variable::putDIntoZmm($content, $zmm, $offset, $transfer)

Place the value of the content variable at the double word in the numbered zmm register.

     Parameter  Description
  1  $content   Variable with content
  2  $zmm       Numbered zmm
  3  $offset    Offset in bytes
  4  $transfer  Optional transfer register

Example:

    my $s = Rb(0..8);
    my $c = V("Content",   "[$s]");
       $c->putBIntoZmm(0,  4);
       $c->putWIntoZmm(0,  6);
       $c->putDIntoZmm(0, 10);
       $c->putQIntoZmm(0, 16);
    PrintOutRegisterInHex zmm0;
    getBFromZmm(0, 12)->outNL;
    getWFromZmm(0, 12)->outNL;
    getDFromZmm(0, 12, r15)->outNL;
    getQFromZmm(0, 12)->outNL;

    ok Assemble(debug => 0, eq => <<END);
    zmm0: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0706 0504 0302 0100   0000 0302 0100 0000   0100 0000 0000 0000
  b at offset 12 in zmm0: 0000 0000 0000 0002
  w at offset 12 in zmm0: 0000 0000 0000 0302
  d at offset 12 in zmm0: 0000 0000 0000 0302
  q at offset 12 in zmm0: 0302 0100 0000 0302
  END

Nasm::X86::Variable::putQIntoZmm($content, $zmm, $offset, $transfer)

Place the value of the content variable at the quad word in the numbered zmm register.

     Parameter  Description
  1  $content   Variable with content
  2  $zmm       Numbered zmm
  3  $offset    Offset in bytes
  4  $transfer  Optional transfer register

Broadcast

Broadcast from a variable into a zmm

Nasm::X86::Variable::zBroadCastD($variable, $zmm)

Broadcast a double word in a variable into the numbered zmm.

     Parameter  Description
  1  $variable  Variable containing value to broadcast
  2  $zmm       Numbered zmm to broadcast to

Stack

Push and pop variables to and from the stack

Nasm::X86::Variable::push($variable)

Push a variable onto the stack.

     Parameter  Description
  1  $variable  Variable

Nasm::X86::Variable::pop($variable)

Pop a variable from the stack.

     Parameter  Description
  1  $variable  Variable

Memory

Actions on memory described by variables

Nasm::X86::Variable::clearMemory($address, $size)

Clear the memory described in this variable.

     Parameter  Description
  1  $address   Address of memory to clear
  2  $size      Size of the memory to clear

Nasm::X86::Variable::copyMemory($target, $source, $size)

Copy from one block of memory to another.

     Parameter  Description
  1  $target    Address of target
  2  $source    Address of source
  3  $size      Length to copy

Nasm::X86::Variable::printMemoryInHexNL($address, $channel, $size)

Write, in hexadecimal, the memory addressed by a variable to stdout or stderr.

     Parameter  Description
  1  $address   Address of memory
  2  $channel   Channel to print on
  3  $size      Number of bytes to print

Nasm::X86::Variable::printErrMemoryInHexNL($address, $size)

Write the memory addressed by a variable to stderr.

     Parameter  Description
  1  $address   Address of memory
  2  $size      Number of bytes to print

Nasm::X86::Variable::printOutMemoryInHexNL($address, $size)

Write the memory addressed by a variable to stdout.

     Parameter  Description
  1  $address   Address of memory
  2  $size      Number of bytes to print

Example:

    my $u = Rd(ord('𝝰'), ord('𝝱'), ord('𝝲'), ord('𝝳'));
    Mov rax, $u;
    my $address = V(address)->getReg(rax);
    $address->printOutMemoryInHexNL(K(size, 16));

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  70D7 0100 71D7 010072D7 0100 73D7 0100
  END

    my $v = V(var, 2);

    If  $v == 0, Then {Mov rax, 0},
    Ef {$v == 1} Then {Mov rax, 1},
    Ef {$v == 2} Then {Mov rax, 2},
                 Else {Mov rax, 3};
    PrintOutRegisterInHex rax;
    ok Assemble(debug => 0, trace => 0, eq => <<END);
     rax: 0000 0000 0000 0002
  END

Nasm::X86::Variable::freeMemory($address, $size)

Free the memory addressed by this variable for the specified length.

     Parameter  Description
  1  $address   Address of memory to free
  2  $size      Size of the memory to free

Example:

    my $N = V(size, 2048);
    my $q = Rs('a'..'p');
    AllocateMemory($N, my $address = V(address));

    Vmovdqu8 xmm0, "[$q]";
    $address->setReg(rax);
    Vmovdqu8 "[rax]", xmm0;
    Mov rdi, 16;
    PrintOutMemory;
    PrintOutNL;

    FreeMemory(address => $address, size=> $N);

    ok Assemble(debug => 0, eq => <<END);
  abcdefghijklmnop
  END

Nasm::X86::Variable::allocateMemory($size)

Allocate the specified amount of memory via mmap and return its address.

     Parameter  Description
  1  $size      Size

Structured Programming with variables

Structured programming operations driven off variables.

Nasm::X86::Variable::for($limit, $block)

Iterate the block limit times.

     Parameter  Description
  1  $limit     Limit
  2  $block     Block

Example:

    V(limit,10)->for(sub
     {my ($i, $start, $next, $end) = @_;
      $i->outNL;
     });

    ok Assemble(debug => 0, eq => <<END);
  index: 0000 0000 0000 0000
  index: 0000 0000 0000 0001
  index: 0000 0000 0000 0002
  index: 0000 0000 0000 0003
  index: 0000 0000 0000 0004
  index: 0000 0000 0000 0005
  index: 0000 0000 0000 0006
  index: 0000 0000 0000 0007
  index: 0000 0000 0000 0008
  index: 0000 0000 0000 0009
  END

Stack

Manage data on the stack

Push, Pop, Peek

Generic versions of push, pop, peek

PopR(@r)

Pop registers from the stack. Use the last stored set if none explicitly supplied. Pops are done in reverse order to match the original pushing order.

     Parameter  Description
  1  @r         Register

Example:

    Mov rax, 0x11111111;
    Mov rbx, 0x22222222;
    PushR my @save = (rax, rbx);
    Mov rax, 0x33333333;

    PopR;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;
    PrintOutRegisterInHex rbx;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 1111 1111
     rbx: 0000 0000 2222 2222
  END

PopEax()

We cannot pop a double word from the stack in 64 bit long mode using pop so we improvise.

Example:

    Mov r14, 0;
    Kmovq k0, r14;
    Ktestq k0, k0;
    IfZ Then {PrintOutStringNL "0 & 0 == 0"};
    PrintOutZF;

    LoadConstantIntoMaskRegister k1, r13, 1;
    Ktestq k1, k1;
    IfNz Then {PrintOutStringNL "1 & 1 != 0"};
    PrintOutZF;

    LoadConstantIntoMaskRegister k2, r13, eval "0b".(('1'x4).('0'x4))x2;

    PrintOutRegisterInHex k0, k1, k2;

    Mov  r15, 0x89abcdef;
    Mov  r14, 0x01234567;
    Shl  r14, 32;
    Or r15, r14;
    Push r15;
    Push r15;

    PopEax;  PrintRaxInHex($stdout, 3); PrintOutNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    my $a = V('aaaa');
    $a->pop;
    $a->push;
    $a->outNL;


    PopEax;  PrintRaxInHex($stdout, 3); PrintOutNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 0, eq => <<END);
  0 & 0 == 0
  ZF=1
  1 & 1 != 0
  ZF=0
      k0: 0000 0000 0000 0000
      k1: 0000 0000 0000 0001
      k2: 0000 0000 0000 F0F0
  89AB CDEF
  aaaa: 89AB CDEF 0123 4567
  0123 4567
  END

PeekR($r)

Peek at register on stack.

     Parameter  Description
  1  $r         Register

PushZmm(@Z)

Push several zmm registers.

     Parameter  Description
  1  @Z         Zmm register numbers

PopZmm()

Pop zmm registers.

PushMask(@M)

Push several Mask registers.

     Parameter  Description
  1  @M         Mask register numbers

PopMask()

Pop Mask registers.

Declarations

Declare variables and structures

Structures

Declare a structure

Structure()

Create a structure addressed by a register.

Nasm::X86::Structure::field($structure, $length, $comment)

Add a field of the specified length with an optional comment.

     Parameter   Description
  1  $structure  Structure data descriptor
  2  $length     Length of data
  3  $comment    Optional comment

Nasm::X86::StructureField::addr($field, $register)

Address a field in a structure by either the default register or the named register.

     Parameter  Description
  1  $field     Field
  2  $register  Optional address register else rax

All8Structure($N)

Create a structure consisting of 8 byte fields.

     Parameter  Description
  1  $N         Number of variables required

Stack Frame

Declare local variables in a frame on the stack

LocalData()

Map local data.

Nasm::X86::LocalData::start($local)

Start a local data area on the stack.

     Parameter  Description
  1  $local     Local data descriptor

Nasm::X86::LocalData::free($local)

Free a local data area on the stack.

     Parameter  Description
  1  $local     Local data descriptor

Nasm::X86::LocalData::variable($local, $length, $comment)

Add a local variable.

     Parameter  Description
  1  $local     Local data descriptor
  2  $length    Length of data
  3  $comment   Optional comment

Nasm::X86::LocalVariable::stack($variable)

Address a local variable on the stack.

     Parameter  Description
  1  $variable  Variable

Nasm::X86::LocalData::allocate8($local, @comments)

Add some 8 byte local variables and return an array of variable definitions.

     Parameter  Description
  1  $local     Local data descriptor
  2  @comments  Optional comment

AllocateAll8OnStack($N)

Create a local data descriptor consisting of the specified number of 8 byte local variables and return an array: (local data descriptor, variable definitions...).

     Parameter  Description
  1  $N         Number of variables required

Operating system

Interacting with the operating system.

Processes

Create and manage processes

Fork()

Fork.

Example:

    Fork;                                                                         # Fork  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Test rax,rax;
    IfNz                                                                          # Parent
    Then
     {Mov rbx, rax;
      WaitPid;
      GetPid;                                                                     # Pid of parent as seen in parent
      Mov rcx,rax;
      PrintOutRegisterInHex rax, rbx, rcx;
     },
    Else                                                                          # Child
     {Mov r8,rax;
      GetPid;                                                                     # Child pid as seen in child
      Mov r9,rax;
      GetPPid;                                                                    # Parent pid as seen in child
      Mov r10,rax;
      PrintOutRegisterInHex r8, r9, r10;
     };

    my $r = Assemble;

  #    r8: 0000 0000 0000 0000   #1 Return from fork as seen by child
  #    r9: 0000 0000 0003 0C63   #2 Pid of child
  #   r10: 0000 0000 0003 0C60   #3 Pid of parent from child
  #   rax: 0000 0000 0003 0C63   #4 Return from fork as seen by parent
  #   rbx: 0000 0000 0003 0C63   #5 Wait for child pid result
  #   rcx: 0000 0000 0003 0C60   #6 Pid of parent

    if ($r =~ m(r8:( 0000){4}.*r9:(.*)\s{5,}r10:(.*)\s{5,}rax:(.*)\s{5,}rbx:(.*)\s{5,}rcx:(.*)\s{2,})s)
     {ok $2 eq $4;
      ok $2 eq $5;
      ok $3 eq $6;
      ok $2 gt $6;
     }

GetPid()

Get process identifier.

Example:

    Fork;                                                                         # Fork

    Test rax,rax;
    IfNz                                                                          # Parent
    Then
     {Mov rbx, rax;
      WaitPid;

      GetPid;                                                                     # Pid of parent as seen in parent  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

      Mov rcx,rax;
      PrintOutRegisterInHex rax, rbx, rcx;
     },
    Else                                                                          # Child
     {Mov r8,rax;

      GetPid;                                                                     # Child pid as seen in child  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

      Mov r9,rax;
      GetPPid;                                                                    # Parent pid as seen in child
      Mov r10,rax;
      PrintOutRegisterInHex r8, r9, r10;
     };

    my $r = Assemble;

  #    r8: 0000 0000 0000 0000   #1 Return from fork as seen by child
  #    r9: 0000 0000 0003 0C63   #2 Pid of child
  #   r10: 0000 0000 0003 0C60   #3 Pid of parent from child
  #   rax: 0000 0000 0003 0C63   #4 Return from fork as seen by parent
  #   rbx: 0000 0000 0003 0C63   #5 Wait for child pid result
  #   rcx: 0000 0000 0003 0C60   #6 Pid of parent

    if ($r =~ m(r8:( 0000){4}.*r9:(.*)\s{5,}r10:(.*)\s{5,}rax:(.*)\s{5,}rbx:(.*)\s{5,}rcx:(.*)\s{2,})s)
     {ok $2 eq $4;
      ok $2 eq $5;
      ok $3 eq $6;
      ok $2 gt $6;
     }

GetPidInHex()

Get process identifier in hex as 8 zero terminated bytes in rax.

Example:

    GetPidInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;

    ok Assemble =~ m(rax: 00);

GetPPid()

Get parent process identifier.

Example:

    Fork;                                                                         # Fork

    Test rax,rax;
    IfNz                                                                          # Parent
    Then
     {Mov rbx, rax;
      WaitPid;
      GetPid;                                                                     # Pid of parent as seen in parent
      Mov rcx,rax;
      PrintOutRegisterInHex rax, rbx, rcx;
     },
    Else                                                                          # Child
     {Mov r8,rax;
      GetPid;                                                                     # Child pid as seen in child
      Mov r9,rax;

      GetPPid;                                                                    # Parent pid as seen in child  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

      Mov r10,rax;
      PrintOutRegisterInHex r8, r9, r10;
     };

    my $r = Assemble;

  #    r8: 0000 0000 0000 0000   #1 Return from fork as seen by child
  #    r9: 0000 0000 0003 0C63   #2 Pid of child
  #   r10: 0000 0000 0003 0C60   #3 Pid of parent from child
  #   rax: 0000 0000 0003 0C63   #4 Return from fork as seen by parent
  #   rbx: 0000 0000 0003 0C63   #5 Wait for child pid result
  #   rcx: 0000 0000 0003 0C60   #6 Pid of parent

    if ($r =~ m(r8:( 0000){4}.*r9:(.*)\s{5,}r10:(.*)\s{5,}rax:(.*)\s{5,}rbx:(.*)\s{5,}rcx:(.*)\s{2,})s)
     {ok $2 eq $4;
      ok $2 eq $5;
      ok $3 eq $6;
      ok $2 gt $6;
     }

GetUid()

Get userid of current process.

Example:

    GetUid;                                                                       # Userid  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;

    my $r = Assemble;
    ok $r =~ m(rax:( 0000){3});

WaitPid()

Wait for the pid in rax to complete.

Example:

    Fork;                                                                         # Fork

    Test rax,rax;
    IfNz                                                                          # Parent
    Then
     {Mov rbx, rax;

      WaitPid;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

      GetPid;                                                                     # Pid of parent as seen in parent
      Mov rcx,rax;
      PrintOutRegisterInHex rax, rbx, rcx;
     },
    Else                                                                          # Child
     {Mov r8,rax;
      GetPid;                                                                     # Child pid as seen in child
      Mov r9,rax;
      GetPPid;                                                                    # Parent pid as seen in child
      Mov r10,rax;
      PrintOutRegisterInHex r8, r9, r10;
     };

    my $r = Assemble;

  #    r8: 0000 0000 0000 0000   #1 Return from fork as seen by child
  #    r9: 0000 0000 0003 0C63   #2 Pid of child
  #   r10: 0000 0000 0003 0C60   #3 Pid of parent from child
  #   rax: 0000 0000 0003 0C63   #4 Return from fork as seen by parent
  #   rbx: 0000 0000 0003 0C63   #5 Wait for child pid result
  #   rcx: 0000 0000 0003 0C60   #6 Pid of parent

    if ($r =~ m(r8:( 0000){4}.*r9:(.*)\s{5,}r10:(.*)\s{5,}rax:(.*)\s{5,}rbx:(.*)\s{5,}rcx:(.*)\s{2,})s)
     {ok $2 eq $4;
      ok $2 eq $5;
      ok $3 eq $6;
      ok $2 gt $6;
     }

ReadTimeStampCounter()

Read the time stamp counter and return the time in nanoseconds in rax.

Example:

    for(1..10)

     {ReadTimeStampCounter;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

      PrintOutRegisterInHex rax;
     }

    my @s = split /
/, Assemble;
    my @S = sort @s;
    is_deeply \@s, \@S;

Memory

Allocate and print memory

PrintMemoryInHex($channel)

Dump memory from the address in rax for the length in rdi on the specified channel. As this method prints in blocks of 8 up to 7 bytes will be missing from the end unless the length is a multiple of 8 .

     Parameter  Description
  1  $channel   Channel

PrintErrMemoryInHex()

Dump memory from the address in rax for the length in rdi on stderr.

PrintOutMemoryInHex()

Dump memory from the address in rax for the length in rdi on stdout.

Example:

    Mov rax, 0x07654321;
    Shl rax, 32;
    Or  rax, 0x07654321;
    PushR rax;

    PrintOutRaxInHex;
    PrintOutNL;
    PrintOutRaxInReverseInHex;
    PrintOutNL;

    Mov rax, rsp;
    Mov rdi, 8;

    PrintOutMemoryInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutNL;
    PopR rax;

    Mov rax, 4096;
    PushR rax;
    Mov rax, rsp;
    Mov rdi, 8;

    PrintOutMemoryInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutNL;
    PopR rax;

    ok Assemble(debug => 0, eq => <<END);
  0765 4321 0765 4321
  2143 6507 2143 6507
  2143 6507 2143 6507
  0010 0000 0000 0000
  END

PrintErrMemoryInHexNL()

Dump memory from the address in rax for the length in rdi and then print a new line.

PrintOutMemoryInHexNL()

Dump memory from the address in rax for the length in rdi and then print a new line.

Example:

    my $N = 256;
    my $s = Rb 0..$N-1;
    AllocateMemory(K(size, $N), my $a = V(address));
    CopyMemory(V(source, $s), V(size, $N), target => $a);

    AllocateMemory(K(size, $N), my $b = V(address));
    CopyMemory(source => $a, target => $b, K(size, $N));

    $b->setReg(rax);
    Mov rdi, $N;

    PrintOutMemoryInHexNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug=>0, eq => <<END);
  0001 0203 0405 06070809 0A0B 0C0D 0E0F1011 1213 1415 16171819 1A1B 1C1D 1E1F2021 2223 2425 26272829 2A2B 2C2D 2E2F3031 3233 3435 36373839 3A3B 3C3D 3E3F4041 4243 4445 46474849 4A4B 4C4D 4E4F5051 5253 5455 56575859 5A5B 5C5D 5E5F6061 6263 6465 66676869 6A6B 6C6D 6E6F7071 7273 7475 76777879 7A7B 7C7D 7E7F8081 8283 8485 86878889 8A8B 8C8D 8E8F9091 9293 9495 96979899 9A9B 9C9D 9E9FA0A1 A2A3 A4A5 A6A7A8A9 AAAB ACAD AEAFB0B1 B2B3 B4B5 B6B7B8B9 BABB BCBD BEBFC0C1 C2C3 C4C5 C6C7C8C9 CACB CCCD CECFD0D1 D2D3 D4D5 D6D7D8D9 DADB DCDD DEDFE0E1 E2E3 E4E5 E6E7E8E9 EAEB ECED EEEFF0F1 F2F3 F4F5 F6F7F8F9 FAFB FCFD FEFF
  END

PrintMemory($channel)

Print the memory addressed by rax for a length of rdi on the specified channel.

     Parameter  Description
  1  $channel   Channel

Example:

    my $file = V(file, Rs($0));
    my ($address, $size) = ReadFile $file;                                        # Read file into memory
    $address->setReg(rax);                                                        # Address of file in memory
    $size   ->setReg(rdi);                                                        # Length  of file in memory
    PrintOutMemory;                                                               # Print contents of memory to stdout

    my $r = Assemble;                                                             # Assemble and execute
    ok stringMd5Sum($r) eq fileMd5Sum($0);                                        # Output contains this file

PrintMemoryNL()

Print the memory addressed by rax for a length of rdi on the specified channel followed by a new line.

PrintErrMemory()

Print the memory addressed by rax for a length of rdi on stderr.

PrintOutMemory()

Print the memory addressed by rax for a length of rdi on stdout.

Example:

    Comment "Print a string from memory";
    my $s = "Hello World";
    Mov rax, Rs($s);
    Mov rdi, length $s;

    PrintOutMemory;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Exit(0);

    ok Assemble =~ m(Hello World);

PrintErrMemoryNL()

Print the memory addressed by rax for a length of rdi followed by a new line on stderr.

PrintOutMemoryNL()

Print the memory addressed by rax for a length of rdi followed by a new line on stdout.

Example:

    my $s = Rs("Hello World

Hello Skye"); Mov rax, $s; Cstrlen; Mov rdi, r15;

    PrintOutMemoryNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 0, eq => <<END);
  Hello World

  Hello Skye
  END

AllocateMemory(@variables)

Allocate the specified amount of memory via mmap and return its address.

     Parameter   Description
  1  @variables  Parameters

Example:

    my $N = V(size, 2048);
    my $q = Rs('a'..'p');

    AllocateMemory($N, my $address = V(address));  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    Vmovdqu8 xmm0, "[$q]";
    $address->setReg(rax);
    Vmovdqu8 "[rax]", xmm0;
    Mov rdi, 16;
    PrintOutMemory;
    PrintOutNL;

    FreeMemory(address => $address, size=> $N);

    ok Assemble(debug => 0, eq => <<END);
  abcdefghijklmnop
  END

    my $N = V(size, 4096);                                                        # Size of the initial allocation which should be one or more pages


    AllocateMemory($N, my $A = V(address));  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ClearMemory($N, $A);

    $A->setReg(rax);
    Mov rdi, 128;
    PrintOutMemoryInHexNL;

    FreeMemory($N, $A);

    ok Assemble(debug => 1, eq => <<END);
  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  END

    my $N = 256;
    my $s = Rb 0..$N-1;

    AllocateMemory(K(size, $N), my $a = V(address));  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    CopyMemory(V(source, $s), V(size, $N), target => $a);


    AllocateMemory(K(size, $N), my $b = V(address));  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    CopyMemory(source => $a, target => $b, K(size, $N));

    $b->setReg(rax);
    Mov rdi, $N;
    PrintOutMemoryInHexNL;

    ok Assemble(debug=>0, eq => <<END);
  0001 0203 0405 06070809 0A0B 0C0D 0E0F1011 1213 1415 16171819 1A1B 1C1D 1E1F2021 2223 2425 26272829 2A2B 2C2D 2E2F3031 3233 3435 36373839 3A3B 3C3D 3E3F4041 4243 4445 46474849 4A4B 4C4D 4E4F5051 5253 5455 56575859 5A5B 5C5D 5E5F6061 6263 6465 66676869 6A6B 6C6D 6E6F7071 7273 7475 76777879 7A7B 7C7D 7E7F8081 8283 8485 86878889 8A8B 8C8D 8E8F9091 9293 9495 96979899 9A9B 9C9D 9E9FA0A1 A2A3 A4A5 A6A7A8A9 AAAB ACAD AEAFB0B1 B2B3 B4B5 B6B7B8B9 BABB BCBD BEBFC0C1 C2C3 C4C5 C6C7C8C9 CACB CCCD CECFD0D1 D2D3 D4D5 D6D7D8D9 DADB DCDD DEDFE0E1 E2E3 E4E5 E6E7E8E9 EAEB ECED EEEFF0F1 F2F3 F4F5 F6F7F8F9 FAFB FCFD FEFF
  END

FreeMemory(@variables)

Free memory.

     Parameter   Description
  1  @variables  Variables

Example:

    my $N = V(size, 4096);                                                        # Size of the initial allocation which should be one or more pages

    AllocateMemory($N, my $A = V(address));

    ClearMemory($N, $A);

    $A->setReg(rax);
    Mov rdi, 128;
    PrintOutMemoryInHexNL;


    FreeMemory($N, $A);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 1, eq => <<END);
  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  END

ClearMemory(@variables)

Clear memory.

     Parameter   Description
  1  @variables  Variables

Example:

    K(loop, 8+1)->for(sub
     {my ($index, $start, $next, $end) = @_;
      $index->setReg(r15);
      Push r15;
     });

    Mov rax, rsp;
    Mov rdi, 8*9;
    PrintOutMemoryInHexNL;

    ClearMemory(K(size, 8*9), V(address, rax));  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutMemoryInHexNL;

    ok Assemble(debug => 0, eq => <<END);
  0800 0000 0000 00000700 0000 0000 00000600 0000 0000 00000500 0000 0000 00000400 0000 0000 00000300 0000 0000 00000200 0000 0000 00000100 0000 0000 00000000 0000 0000 0000
  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  END

    my $N = V(size, 4096);                                                        # Size of the initial allocation which should be one or more pages

    AllocateMemory($N, my $A = V(address));


    ClearMemory($N, $A);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    $A->setReg(rax);
    Mov rdi, 128;
    PrintOutMemoryInHexNL;

    FreeMemory($N, $A);

    ok Assemble(debug => 1, eq => <<END);
  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  END

MaskMemory22(@variables)

Write the specified byte into locations in the target mask that correspond to the locations in the source that contain the specified byte.

     Parameter   Description
  1  @variables  Variables

MaskMemoryInRange4_22(@variables)

Write the specified byte into locations in the target mask that correspond to the locations in the source that contain 4 bytes in the specified range.

     Parameter   Description
  1  @variables  Variables

CopyMemory(@variables)

Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi.

     Parameter   Description
  1  @variables  Variables

Example:

    my $s = Rb 0; Rb 1; Rw 2; Rd 3;  Rq 4;
    my $t = Db 0; Db 1; Dw 2; Dd 3;  Dq 4;

    Vmovdqu8 xmm0, "[$s]";
    Vmovdqu8 xmm1, "[$t]";
    PrintOutRegisterInHex xmm0;
    PrintOutRegisterInHex xmm1;
    Sub rsp, 16;

    Mov rax, rsp;                                                                 # Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi
    Mov rdi, 16;
    Mov rsi, $s;

    CopyMemory(V(source, rsi), V(target, rax), V(size, rdi));  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutMemoryInHex;

    my $r = Assemble;
    ok $r =~ m(xmm0: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(xmm1: 0000 0000 0000 0004   0000 0003 0002 0100);
    ok $r =~ m(0001 0200 0300 00000400 0000 0000 0000);

    my $N = 256;
    my $s = Rb 0..$N-1;
    AllocateMemory(K(size, $N), my $a = V(address));

    CopyMemory(V(source, $s), V(size, $N), target => $a);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    AllocateMemory(K(size, $N), my $b = V(address));

    CopyMemory(source => $a, target => $b, K(size, $N));  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    $b->setReg(rax);
    Mov rdi, $N;
    PrintOutMemoryInHexNL;

    ok Assemble(debug=>0, eq => <<END);
  0001 0203 0405 06070809 0A0B 0C0D 0E0F1011 1213 1415 16171819 1A1B 1C1D 1E1F2021 2223 2425 26272829 2A2B 2C2D 2E2F3031 3233 3435 36373839 3A3B 3C3D 3E3F4041 4243 4445 46474849 4A4B 4C4D 4E4F5051 5253 5455 56575859 5A5B 5C5D 5E5F6061 6263 6465 66676869 6A6B 6C6D 6E6F7071 7273 7475 76777879 7A7B 7C7D 7E7F8081 8283 8485 86878889 8A8B 8C8D 8E8F9091 9293 9495 96979899 9A9B 9C9D 9E9FA0A1 A2A3 A4A5 A6A7A8A9 AAAB ACAD AEAFB0B1 B2B3 B4B5 B6B7B8B9 BABB BCBD BEBFC0C1 C2C3 C4C5 C6C7C8C9 CACB CCCD CECFD0D1 D2D3 D4D5 D6D7D8D9 DADB DCDD DEDFE0E1 E2E3 E4E5 E6E7E8E9 EAEB ECED EEEFF0F1 F2F3 F4F5 F6F7F8F9 FAFB FCFD FEFF
  END

Files

Interact with the operating system via files.

OpenRead()

Open a file, whose name is addressed by rax, for read and return the file descriptor in rax.

Example:

    Mov rax, Rs($0);                                                              # File to read

    OpenRead;                                                                     # Open file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;
    CloseFile;                                                                    # Close file
    PrintOutRegisterInHex rax;

    Mov rax, Rs(my $f = "zzzTemporaryFile.txt");                                  # File to write
    OpenWrite;                                                                    # Open file
    CloseFile;                                                                    # Close file

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rax: 0000 0000 0000 0000
  END
    ok -e $f;                                                                     # Created file
    unlink $f;

OpenWrite()

Create the file named by the terminated string addressed by rax for write.

Example:

    Mov rax, Rs($0);                                                              # File to read
    OpenRead;                                                                     # Open file
    PrintOutRegisterInHex rax;
    CloseFile;                                                                    # Close file
    PrintOutRegisterInHex rax;

    Mov rax, Rs(my $f = "zzzTemporaryFile.txt");                                  # File to write

    OpenWrite;                                                                    # Open file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    CloseFile;                                                                    # Close file

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rax: 0000 0000 0000 0000
  END
    ok -e $f;                                                                     # Created file
    unlink $f;

CloseFile()

Close the file whose descriptor is in rax.

Example:

    Mov rax, Rs($0);                                                              # File to read
    OpenRead;                                                                     # Open file
    PrintOutRegisterInHex rax;

    CloseFile;                                                                    # Close file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;

    Mov rax, Rs(my $f = "zzzTemporaryFile.txt");                                  # File to write
    OpenWrite;                                                                    # Open file

    CloseFile;                                                                    # Close file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 0000 0003
     rax: 0000 0000 0000 0000
  END
    ok -e $f;                                                                     # Created file
    unlink $f;

StatSize()

Stat a file whose name is addressed by rax to get its size in rax.

Example:

    Mov rax, Rs($0);                                                              # File to stat

    StatSize;                                                                     # Stat the file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;

    my $r = Assemble =~ s( ) ()gsr;
    if ($r =~ m(rax:([0-9a-f]{16}))is)                                            # Compare file size obtained with that from fileSize()
     {is_deeply $1, sprintf("%016X", fileSize($0));
     }

ReadChar()

Read a character from stdin and return it in rax else return -1 in rax if no character was read

ReadFile($File)

Read a file into memory.

     Parameter  Description
  1  $File      Variable addressing a zero terminated string naming the file

Example:

    my $file = V(file, Rs($0));

    my ($address, $size) = ReadFile $file;                                        # Read file into memory  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $address->setReg(rax);                                                        # Address of file in memory
    $size   ->setReg(rdi);                                                        # Length  of file in memory
    PrintOutMemory;                                                               # Print contents of memory to stdout

    my $r = Assemble;                                                             # Assemble and execute
    ok stringMd5Sum($r) eq fileMd5Sum($0);                                        # Output contains this file

executeFileViaBash(@variables)

Execute the file named in the arena addressed by rax with bash.

     Parameter   Description
  1  @variables  Variables

Example:

    my $s = CreateArena;                                                          # Create a string
    $s->ql(<<END);                                                                # Write code to execute
  #!/usr/bin/bash
  whoami
  ls -la
  pwd
  END
    $s->write         (my $f = V('file', Rs("zzz.sh")));                          # Write code to a file

    executeFileViaBash($f);                                                       # Execute the file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    unlinkFile        ($f);                                                       # Delete the file

    my $u = qx(whoami); chomp($u);
    ok Assemble(emulator => 0) =~ m($u);                                          # The Intel Software Development Emulator is way too slow on these operations.

unlinkFile(@variables)

Unlink the named file.

     Parameter   Description
  1  @variables  Variables

Example:

    my $s = CreateArena;                                                          # Create a string
    $s->ql(<<END);                                                                # Write code to execute
  #!/usr/bin/bash
  whoami
  ls -la
  pwd
  END
    $s->write         (my $f = V('file', Rs("zzz.sh")));                          # Write code to a file
    executeFileViaBash($f);                                                       # Execute the file

    unlinkFile        ($f);                                                       # Delete the file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    my $u = qx(whoami); chomp($u);
    ok Assemble(emulator => 0) =~ m($u);                                          # The Intel Software Development Emulator is way too slow on these operations.

Hash functions

Hash functions

Hash()

Hash a string addressed by rax with length held in rdi and return the hash code in r15.

Example:

    Mov rax, "[rbp+24]";
    Cstrlen;                                                                      # Length of string to hash
    Mov rdi, r15;

    Hash();                                                                       # Hash string  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    PrintOutRegisterInHex r15;

    my $e = Assemble keep=>'hash';                                                # Assemble to the specified file name
    ok qx($e "")  =~ m(r15: 0000 3F80 0000 3F80);                                 # Test well known hashes
    ok qx($e "a") =~ m(r15: 0000 3F80 C000 45B2);


    if (0)                                                                        # Hash various strings  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

     {my %r; my %f; my $count = 0;
      my $N = RegisterSize zmm0;

      if (1)                                                                      # Fixed blocks
       {for my $l(qw(a ab abc abcd), 'a a', 'a  a')
         {for my $i(1..$N)
           {my $t = $l x $i;
            last if $N < length $t;
            my $s = substr($t.(' ' x $N), 0, $N);
            next if $f{$s}++;
            my $r = qx($e "$s");
            say STDERR "$count  $r";
            if ($r =~ m(^.*r15:\s*(.*)$)m)
             {push $r{$1}->@*, $s;
              ++$count;
             }
           }
         }
       }

      if (1)                                                                      # Variable blocks
       {for my $l(qw(a ab abc abcd), '', 'a a', 'a  a')
         {for my $i(1..$N)
           {my $t = $l x $i;
            next if $f{$t}++;
            my $r = qx($e "$t");
            say STDERR "$count  $r";
            if ($r =~ m(^.*r15:\s*(.*)$)m)
             {push $r{$1}->@*, $t;
              ++$count;
             }
           }
         }
       }
      for my $r(keys %r)
       {delete $r{$r} if $r{$r}->@* < 2;
       }

      say STDERR dump(\%r);
      say STDERR "Keys hashed: ", $count;
      confess "Duplicates : ",  scalar keys(%r);
     }

Unicode

Convert utf8 to utf32

GetNextUtf8CharAsUtf32(@parameters)

Get the next utf8 encoded character from the addressed memory and return it as a utf32 char.

     Parameter    Description
  1  @parameters  Parameters

ConvertUtf8ToUtf32(@parameters)

Convert a string of utf8 to an allocated block of utf32 and return its address and length.

     Parameter    Description
  1  @parameters  Parameters

Example:

    my @p = my ($out, $size, $fail) = (V(out), V(size), V('fail'));

    my $Chars = Rb(0x24, 0xc2, 0xa2, 0xc9, 0x91, 0xE2, 0x82, 0xAC, 0xF0, 0x90, 0x8D, 0x88);
    my $chars = V(chars, $Chars);

    GetNextUtf8CharAsUtf32 in=>$chars, @p;                                        # Dollar               UTF-8 Encoding: 0x24                UTF-32 Encoding: 0x00000024
    $out->out('out1 : ');     $size->outNL(' size : ');

    GetNextUtf8CharAsUtf32 in=>$chars+1, @p;                                      # Cents                UTF-8 Encoding: 0xC2 0xA2           UTF-32 Encoding: 0x000000a2
    $out->out('out2 : ');     $size->outNL(' size : ');

    GetNextUtf8CharAsUtf32 in=>$chars+3, @p;                                      # Alpha                UTF-8 Encoding: 0xC9 0x91           UTF-32 Encoding: 0x00000251
    $out->out('out3 : ');     $size->outNL(' size : ');

    GetNextUtf8CharAsUtf32 in=>$chars+5, @p;                                      # Euro                 UTF-8 Encoding: 0xE2 0x82 0xAC      UTF-32 Encoding: 0x000020AC
    $out->out('out4 : ');     $size->outNL(' size : ');

    GetNextUtf8CharAsUtf32 in=>$chars+8, @p;                                      # Gothic Letter Hwair  UTF-8 Encoding  0xF0 0x90 0x8D 0x88 UTF-32 Encoding: 0x00010348
    $out->out('out5 : ');     $size->outNL(' size : ');

    my $statement = qq(𝖺
 𝑎𝑠𝑠𝑖𝑔𝑛 【【𝖻 𝐩𝐥𝐮𝐬 𝖼】】
AAAAAAAA);                        # A sample sentence to parse

    my $s = K(statement, Rutf8($statement));
    my $l = StringLength string => $s;

    AllocateMemory($l, my $address = V(address));                                 # Allocate enough memory for a copy of the string
    CopyMemory(source => $s, target => $address, $l);

    GetNextUtf8CharAsUtf32 in=>$address, @p;
    $out->out('outA : ');     $size->outNL(' size : ');

    GetNextUtf8CharAsUtf32 in=>$address+4, @p;
    $out->out('outB : ');     $size->outNL(' size : ');

    GetNextUtf8CharAsUtf32 in=>$address+5, @p;
    $out->out('outC : ');     $size->outNL(' size : ');

    GetNextUtf8CharAsUtf32 in=>$address+30, @p;
    $out->out('outD : ');     $size->outNL(' size : ');

    GetNextUtf8CharAsUtf32 in=>$address+35, @p;
    $out->out('outE : ');     $size->outNL(' size : ');

    $address->printOutMemoryInHexNL($l);

    ok Assemble(debug => 0, eq => <<END);
  out1 : 0000 0000 0000 0024 size : 0000 0000 0000 0001
  out2 : 0000 0000 0000 00A2 size : 0000 0000 0000 0002
  out3 : 0000 0000 0000 0251 size : 0000 0000 0000 0002
  out4 : 0000 0000 0000 20AC size : 0000 0000 0000 0003
  out5 : 0000 0000 0001 0348 size : 0000 0000 0000 0004
  outA : 0000 0000 0001 D5BA size : 0000 0000 0000 0004
  outB : 0000 0000 0000 000A size : 0000 0000 0000 0001
  outC : 0000 0000 0000 0020 size : 0000 0000 0000 0001
  outD : 0000 0000 0000 0020 size : 0000 0000 0000 0001
  outE : 0000 0000 0000 0010 size : 0000 0000 0000 0002
  F09D 96BA 0A20 F09D918E F09D 91A0 F09D91A0 F09D 9196 F09D9194 F09D 919B 20E38090 E380 90F0 9D96BB20 F09D 90A9 F09D90A5 F09D 90AE F09D90AC 20F0 9D96 BCE38091 E380 910A 41414141 4141 4141 0000
  END

ClassifyInRange(@parameters)

Character classification: classify the utf32 characters in a block of memory of specified length using a range specification held in zmm0, zmm1 formatted in double words with each double word in zmm0 having the classification in the highest 8 bits and with zmm0 and zmm1 having the utf32 character at the start (zmm0) and end (zmm1) of each range in the lowest 18 bits. The classification bits from the first matching range are copied into the high (unused) byte of each utf32 character in the block of memory. The effect is to replace the high order byte of each utf32 character with a classification code saying what type of character we are working.

     Parameter    Description
  1  @parameters  Parameters

ClassifyWithInRange(@parameters)

Bracket classification: Classify the utf32 characters in a block of memory of specified length using a range specification held in zmm0, zmm1 formatted in double words with the classification range in the high byte of each dword in zmm0 and the utf32 character at the start (zmm0) and end (zmm1) of each range in the lower 18 bits of each dword. The classification bits from the position within the first matching range are copied into the high (unused) byte of each utf32 character in the block of memory. With bracket matching this gives us a normalized bracket number.

     Parameter    Description
  1  @parameters  Parameters

ClassifyWithInRangeAndSaveOffset(@parameters)

Alphabetic classification: classify the utf32 characters in a block of memory of specified length using a range specification held in zmm0, zmm1 formatted in double words with the classification code in the highest byte of each double word in zmm0 and the offset of the first element in the range in the highest byte of each dword in zmm1. The lowest 18 bits of each double word in zmm0 and zmm1 contain the utf32 characters marking the start and end of each range. The classification bits from zmm1 for the first matching range are copied into the high byte of each utf32 character in the block of memory. The offset in the range is copied into the lowest byte of each utf32 character in the block of memory. The middle two bytes are cleared. The classification byte is placed in the lowest byte of the utf32 character.

     Parameter    Description
  1  @parameters  Parameters

ClassifyWithInRangeAndSaveWordOffset($address, $size, $classification)

Alphabetic classification: classify the utf32 characters in a block of memory of specified length using a range specification held in zmm0, zmm1, zmm2 formatted in double words. Zmm0 contains the low end of the range, zmm1 the high end and zmm2 contains the range offset in the high word of each Dword and the lexical classification on the lowest byte of each dword. Each utf32 character recognized is replaced by a dword whose upper byte is the lexical classification and whose lowest word is the range offset.

     Parameter        Description
  1  $address         Variable address of string of utf32 characters
  2  $size            Variable size of string in utf32 characters
  3  $classification  Variable one byte classification code for this range

Short Strings

Operations on Short Strings

CreateShortString($zmm)

Create a description of a short string.

     Parameter  Description
  1  $zmm       Numbered zmm containing the string

Example:

    my $s = CreateShortString(0);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    my $d = Rb(1..63);
    $s->load(K(address, $d), K(size, 9));
    PrintOutRegisterInHex xmm0;

    $s->len->outNL;

    $s->setLength(K(size, 7));
    PrintOutRegisterInHex xmm0;

    $s->append($s);
    PrintOutRegisterInHex ymm0;

    $s->appendByte(K(append,0xFF));
    PrintOutRegisterInHex ymm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    xmm0: 0000 0000 0000 0908   0706 0504 0302 0109
  size: 0000 0000 0000 0009
    xmm0: 0000 0000 0000 0908   0706 0504 0302 0107
    ymm0: 0000 0000 0000 0000   0000 0000 0000 0000   0007 0605 0403 0201   0706 0504 0302 010E
    ymm0: 0000 0000 0000 0000   0000 0000 0000 0000   FF07 0605 0403 0201   0706 0504 0302 010F
  END

Nasm::X86::ShortString::clear($string)

Clear a short string.

     Parameter  Description
  1  $string    String

Nasm::X86::ShortString::load($string, $address, $length)

Load the variable addressed data with the variable length into the short string.

     Parameter  Description
  1  $string    String
  2  $address   Address
  3  $length    Length

Example:

    my $s = CreateShortString(0);
    my $d = Rb(1..63);
    $s->load(K(address, $d), K(size, 9));
    PrintOutRegisterInHex xmm0;

    $s->len->outNL;

    $s->setLength(K(size, 7));
    PrintOutRegisterInHex xmm0;

    $s->append($s);
    PrintOutRegisterInHex ymm0;

    $s->appendByte(K(append,0xFF));
    PrintOutRegisterInHex ymm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    xmm0: 0000 0000 0000 0908   0706 0504 0302 0109
  size: 0000 0000 0000 0009
    xmm0: 0000 0000 0000 0908   0706 0504 0302 0107
    ymm0: 0000 0000 0000 0000   0000 0000 0000 0000   0007 0605 0403 0201   0706 0504 0302 010E
    ymm0: 0000 0000 0000 0000   0000 0000 0000 0000   FF07 0605 0403 0201   0706 0504 0302 010F
  END

Nasm::X86::ShortString::loadConstantString($string, $data)

Load the a short string with a constant string.

     Parameter  Description
  1  $string    Short string
  2  $data      String to load

Nasm::X86::ShortString::loadDwordBytes($string, $byte, $address, $length, $Offset)

Load the specified byte of each dword in the variable addressed data with the variable length into the short string.

     Parameter  Description
  1  $string    String
  2  $byte      Byte offset 0-3
  3  $address   Variable address
  4  $length    Variable length
  5  $Offset    Variable offset in short string at which to start

Nasm::X86::ShortString::loadDwordWords($string, $byte, $address, $length, $Offset)

Load the specified word of each dword in the variable addressed data with the variable length into the short string.

     Parameter  Description
  1  $string    String
  2  $byte      Byte offset 0-3 of word
  3  $address   Variable address
  4  $length    Variable length in words of data to be loaded
  5  $Offset    Variable offset in short string at which to start

Nasm::X86::ShortString::len($string)

Return the length of a short string in a variable.

     Parameter  Description
  1  $string    String

Nasm::X86::ShortString::setLength($string, $length)

Set the length of the short string.

     Parameter  Description
  1  $string    String
  2  $length    Variable size

Example:

    my $s = CreateShortString(0);
    my $d = Rb(1..63);
    $s->load(K(address, $d), K(size, 9));
    PrintOutRegisterInHex xmm0;

    $s->len->outNL;

    $s->setLength(K(size, 7));
    PrintOutRegisterInHex xmm0;

    $s->append($s);
    PrintOutRegisterInHex ymm0;

    $s->appendByte(K(append,0xFF));
    PrintOutRegisterInHex ymm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    xmm0: 0000 0000 0000 0908   0706 0504 0302 0109
  size: 0000 0000 0000 0009
    xmm0: 0000 0000 0000 0908   0706 0504 0302 0107
    ymm0: 0000 0000 0000 0000   0000 0000 0000 0000   0007 0605 0403 0201   0706 0504 0302 010E
    ymm0: 0000 0000 0000 0000   0000 0000 0000 0000   FF07 0605 0403 0201   0706 0504 0302 010F
  END

Nasm::X86::ShortString::appendByte($string, $char)

Append the lowest variable byte to the specified string.

     Parameter  Description
  1  $string    String
  2  $char      Variable byte

Nasm::X86::ShortString::append($left, $right)

Append the right hand short string to the left hand short string.

     Parameter  Description
  1  $left      Target zmm
  2  $right     Source zmm

Example:

    my $s = CreateShortString(0);
    my $d = Rb(1..63);
    $s->load(K(address, $d), K(size, 9));
    PrintOutRegisterInHex xmm0;

    $s->len->outNL;

    $s->setLength(K(size, 7));
    PrintOutRegisterInHex xmm0;

    $s->append($s);
    PrintOutRegisterInHex ymm0;

    $s->appendByte(K(append,0xFF));
    PrintOutRegisterInHex ymm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    xmm0: 0000 0000 0000 0908   0706 0504 0302 0109
  size: 0000 0000 0000 0009
    xmm0: 0000 0000 0000 0908   0706 0504 0302 0107
    ymm0: 0000 0000 0000 0000   0000 0000 0000 0000   0007 0605 0403 0201   0706 0504 0302 010E
    ymm0: 0000 0000 0000 0000   0000 0000 0000 0000   FF07 0605 0403 0201   0706 0504 0302 010F
  END

C Strings

C strings are a series of bytes terminated by a zero byte.

StringLength(@parameters)

Length of a zero terminated string.

     Parameter    Description
  1  @parameters  Parameters

Example:

    StringLength(V(string, Rs("abcd")))->outNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Assemble(debug => 0, eq => <<END);
  size: 0000 0000 0000 0004
  END

Arenas

An arena is single extensible block of memory which contains other data structures such as strings, arrays, trees within it.

DescribeArena($bs)

Describe a relocatable arena.

     Parameter  Description
  1  $bs        Optional variable addressing the start of the arena

CreateArena(%options)

Create an relocatable arena and returns its address in rax. We add a chain header so that 64 byte blocks of memory can be freed and reused within the arena.

     Parameter  Description
  1  %options   Free=>1 adds a free chain.

Example:

    my $a = CreateArena;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $a->q('aa');
    $a->out;
    PrintOutNL;
    ok Assemble(debug => 0, eq => <<END);
  aa
  END


    my $a = CreateArena;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    my $b = CreateArena;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $a->q('aa');
    $b->q('bb');
    $a->out;
    PrintOutNL;
    $b->out;
    PrintOutNL;
    ok Assemble(debug => 0, eq => <<END);
  aa
  bb
  END


    my $a = CreateArena;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    my $b = CreateArena;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $a->q('aa');
    $a->q('AA');
    $a->out;
    PrintOutNL;
    ok Assemble(debug => 0, eq => <<END);
  aaAA
  END


    my $a = CreateArena;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    my $b = CreateArena;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $a->q('aa');
    $b->q('bb');
    $a->q('AA');
    $b->q('BB');
    $a->q('aa');
    $b->q('bb');
    $a->out;
    $b->out;
    PrintOutNL;
    ok Assemble(debug => 0, eq => <<END);
  aaAAaabbBBbb
  END


    my $a = CreateArena;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $a->q('ab');

    my $b = CreateArena;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $b->append($a);
    $b->append($a);
    $a->append($b);
    $b->append($a);
    $a->append($b);
    $b->append($a);
    $b->append($a);
    $b->append($a);
    $b->append($a);


    $a->out;   PrintOutNL;                                                        # Print arena
    $b->out;   PrintOutNL;                                                        # Print arena
    my $sa = $a->length; $sa->outNL;
    my $sb = $b->length; $sb->outNL;
    $a->clear;
    my $sA = $a->length; $sA->outNL;
    my $sB = $b->length; $sB->outNL;

    ok Assemble(debug => 0, eq => <<END);
  abababababababab
  ababababababababababababababababababababababababababababababababababababab
  size: 0000 0000 0000 0010
  size: 0000 0000 0000 004A
  size: 0000 0000 0000 0000
  size: 0000 0000 0000 004A
  END

Nasm::X86::Arena::length($arena)

Get the currently used length of an arena.

     Parameter  Description
  1  $arena     Arena descriptor

Nasm::X86::Arena::arenaSize($arena)

Get the size of an arena.

     Parameter  Description
  1  $arena     Arena descriptor

Nasm::X86::Arena::makeReadOnly($arena)

Make an arena read only.

     Parameter  Description
  1  $arena     Arena descriptor

Nasm::X86::Arena::makeWriteable($arena)

Make an arena writable.

     Parameter  Description
  1  $arena     Arena descriptor

Nasm::X86::Arena::allocate($arena, $size)

Allocate the variable amount of space in the variable addressed arena and return the offset of the allocation in the arena as a variable.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $size      Variable amount of allocation

Nasm::X86::Arena::allocZmmBlock($arena)

Allocate a block to hold a zmm register in the specified arena and return the offset of the block as a variable.

     Parameter  Description
  1  $arena     Arena

Nasm::X86::Arena::allocBlock($arena)

Allocate a block to hold a zmm register in the specified arena and return the offset of the block in a variable.

     Parameter  Description
  1  $arena     Arena

Example:

    my $a = CreateArena; $a->dump;
    for (1..4)
     {my $b1 = $a->allocBlock; $a->dump;
      my $b2 = $a->allocBlock; $a->dump;
      $a->freeBlock($b2);      $a->dump;
      $a->freeBlock($b1);      $a->dump;
     }
    ok Assemble(debug => 0, eq => <<END);
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0018
  Block:  0000 0000 0000 0000  0010 0000 0000 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0058
  Block:  0000 0000 0000 0000  0010 0000 0000 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0098
  Block:  0000 0000 0000 0000  0010 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  END

Nasm::X86::Arena::m($arena, $address, $size)

Append the variable addressed content of variable size to the specified arena.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $address   Variable address of content
  3  $size      Variable length of content

Nasm::X86::Arena::q($arena, $string)

Append a constant string to the arena.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $string    String

Nasm::X86::Arena::ql($arena, $const)

Append a quoted string containing new line characters to the specified arena.

     Parameter  Description
  1  $arena     Arena
  2  $const     Constant

Nasm::X86::Arena::char($arena, $char)

Append a character expressed as a decimal number to the specified arena.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $char      Number of character to be appended

Nasm::X86::Arena::nl($arena)

Append a new line to the arena addressed by rax.

     Parameter  Description
  1  $arena     Arena descriptor

Nasm::X86::Arena::z($arena)

Append a trailing zero to the arena addressed by rax.

     Parameter  Description
  1  $arena     Arena descriptor

Nasm::X86::Arena::append($target, $source)

Append one arena to another.

     Parameter  Description
  1  $target    Target arena descriptor
  2  $source    Source arena descriptor

Nasm::X86::Arena::clear($arena)

Clear the arena addressed by rax.

     Parameter  Description
  1  $arena     Arena descriptor

Nasm::X86::Arena::write($arena, $file)

Write the content of the specified arena to a file specified by a zero terminated string.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $file      Variable addressing file name

Nasm::X86::Arena::read($arena, $file)

Read a file specified by a variable addressed zero terminated string and place the contents of the file into the named arena.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $file      Variable addressing file name

Nasm::X86::Arena::out($arena)

Print the specified arena on sysout.

     Parameter  Description
  1  $arena     Arena descriptor

Nasm::X86::Arena::dump($arena, $depth)

Dump details of an arena.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $depth     Optional variable number of 64 byte blocks to dump

String

Strings made from zmm sized blocks of text

DescribeString(%options)

Describe a string.

     Parameter  Description
  1  %options   String options

Nasm::X86::Arena::DescribeString22($arena, %options)

Describe a string and optionally set its first block.

     Parameter  Description
  1  $arena     Arena description
  2  %options   {first=> offset of first block}

Nasm::X86::Arena::DescribeString($arena, %options)

Describe a string and optionally set its first block .

     Parameter  Description
  1  $arena     Arena description
  2  %options   Arena options

Nasm::X86::Arena::CreateString($arena)

Create a string from a doubly link linked list of 64 byte blocks linked via 4 byte offsets in an arena and return its descriptor.

     Parameter  Description
  1  $arena     Arena description

Nasm::X86::String::dump($String)

Dump a string to sysout.

     Parameter  Description
  1  $String    String descriptor

Nasm::X86::String::len($String)

Find the length of a string.

     Parameter  Description
  1  $String    String descriptor

Example:

    my $c = Rb(0..255);
    my $S = CreateArena;   my $s = $S->CreateString;

    $s->append(source=>V(source, $c),  V(size, 165)); $s->dump;
    $s->deleteChar(V(position, 0x44));                $s->dump;
    $s->len->outNL;

    ok Assemble(debug => 0, eq => <<END);
  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0037
   zmm31: 0000 0058 0000 0098   3635 3433 3231 302F   2E2D 2C2B 2A29 2827   2625 2423 2221 201F   1E1D 1C1B 1A19 1817   1615 1413 1211 100F   0E0D 0C0B 0A09 0807   0605 0403 0201 0037
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0037
   zmm31: 0000 0098 0000 0018   6D6C 6B6A 6968 6766   6564 6362 6160 5F5E   5D5C 5B5A 5958 5756   5554 5352 5150 4F4E   4D4C 4B4A 4948 4746   4544 4342 4140 3F3E   3D3C 3B3A 3938 3737
  Offset: 0000 0000 0000 0098   Length: 0000 0000 0000 0037
   zmm31: 0000 0018 0000 0058   A4A3 A2A1 A09F 9E9D   9C9B 9A99 9897 9695   9493 9291 908F 8E8D   8C8B 8A89 8887 8685   8483 8281 807F 7E7D   7C7B 7A79 7877 7675   7473 7271 706F 6E37

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0037
   zmm31: 0000 0058 0000 0098   3635 3433 3231 302F   2E2D 2C2B 2A29 2827   2625 2423 2221 201F   1E1D 1C1B 1A19 1817   1615 1413 1211 100F   0E0D 0C0B 0A09 0807   0605 0403 0201 0037
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0036
   zmm31: 0000 0098 0000 0018   186D 6C6B 6A69 6867   6665 6463 6261 605F   5E5D 5C5B 5A59 5857   5655 5453 5251 504F   4E4D 4C4B 4A49 4847   4645 4342 4140 3F3E   3D3C 3B3A 3938 3736
  Offset: 0000 0000 0000 0098   Length: 0000 0000 0000 0037
   zmm31: 0000 0018 0000 0058   A4A3 A2A1 A09F 9E9D   9C9B 9A99 9897 9695   9493 9291 908F 8E8D   8C8B 8A89 8887 8685   8483 8281 807F 7E7D   7C7B 7A79 7877 7675   7473 7271 706F 6E37

  size: 0000 0000 0000 00A4
  END

Nasm::X86::String::concatenate($target, $source)

Concatenate two strings by appending a copy of the source to the target string.

     Parameter  Description
  1  $target    Target string
  2  $source    Source string

Nasm::X86::String::insertChar($String, $character, $position)

Insert a character into a string.

     Parameter   Description
  1  $String     String
  2  $character  Variable character
  3  $position   Variable position

Example:

    my $c = Rb(0..255);
    my $S = CreateArena;
    my $s = $S->CreateString;

    $s->append(source=>V(source, $c), K(size, 54));       $s->dump;

    $s->insertChar(V(character, 0x77), K(position,  4));  $s->dump;
    $s->insertChar(V(character, 0x88), K(position,  5));  $s->dump;
    $s->insertChar(V(character, 0x99), K(position,  6));  $s->dump;
    $s->insertChar(V(character, 0xAA), K(position,  7));  $s->dump;
    $s->insertChar(V(character, 0xBB), K(position,  8));  $s->dump;
    $s->insertChar(V(character, 0xCC), K(position,  9));  $s->dump;
    $s->insertChar(V(character, 0xDD), K(position, 10));  $s->dump;
    $s->insertChar(V(character, 0xEE), K(position, 11));  $s->dump;
    $s->insertChar(V(character, 0xFF), K(position, 12));  $s->dump;

    ok Assemble(debug => 0, eq => <<END);
  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0036
   zmm31: 0000 0018 0000 0018   0035 3433 3231 302F   2E2D 2C2B 2A29 2827   2625 2423 2221 201F   1E1D 1C1B 1A19 1817   1615 1413 1211 100F   0E0D 0C0B 0A09 0807   0605 0403 0201 0036

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0037
   zmm31: 0000 0018 0000 0018   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 7703 0201 0037

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0005
   zmm31: 0000 0058 0000 0058   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 7703 0201 0005
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0033
   zmm31: 0000 0018 0000 0018   0000 0018 3534 3332   3130 2F2E 2D2C 2B2A   2928 2726 2524 2322   2120 1F1E 1D1C 1B1A   1918 1716 1514 1312   1110 0F0E 0D0C 0B0A   0908 0706 0504 8833

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0005
   zmm31: 0000 0058 0000 0058   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 7703 0201 0005
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0034
   zmm31: 0000 0018 0000 0018   0000 0035 3433 3231   302F 2E2D 2C2B 2A29   2827 2625 2423 2221   201F 1E1D 1C1B 1A19   1817 1615 1413 1211   100F 0E0D 0C0B 0A09   0807 0605 0499 8834

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0005
   zmm31: 0000 0058 0000 0058   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 7703 0201 0005
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0035
   zmm31: 0000 0018 0000 0018   0000 3534 3332 3130   2F2E 2D2C 2B2A 2928   2726 2524 2322 2120   1F1E 1D1C 1B1A 1918   1716 1514 1312 1110   0F0E 0D0C 0B0A 0908   0706 0504 AA99 8835

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0005
   zmm31: 0000 0058 0000 0058   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 7703 0201 0005
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0036
   zmm31: 0000 0018 0000 0018   0035 3433 3231 302F   2E2D 2C2B 2A29 2827   2625 2423 2221 201F   1E1D 1C1B 1A19 1817   1615 1413 1211 100F   0E0D 0C0B 0A09 0807   0605 04BB AA99 8836

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0005
   zmm31: 0000 0058 0000 0058   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 7703 0201 0005
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0037
   zmm31: 0000 0018 0000 0018   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 CCBB AA99 8837

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0005
   zmm31: 0000 0058 0000 0058   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 7703 0201 0005
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0005
   zmm31: 0000 0098 0000 0098   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 CCBB AA99 8805
  Offset: 0000 0000 0000 0098   Length: 0000 0000 0000 0033
   zmm31: 0000 0018 0000 0018   0000 0018 3534 3332   3130 2F2E 2D2C 2B2A   2928 2726 2524 2322   2120 1F1E 1D1C 1B1A   1918 1716 1514 1312   1110 0F0E 0D0C 0B0A   0908 0706 0504 DD33

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0005
   zmm31: 0000 0058 0000 0058   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 7703 0201 0005
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0005
   zmm31: 0000 0098 0000 0098   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 CCBB AA99 8805
  Offset: 0000 0000 0000 0098   Length: 0000 0000 0000 0034
   zmm31: 0000 0018 0000 0018   0000 0035 3433 3231   302F 2E2D 2C2B 2A29   2827 2625 2423 2221   201F 1E1D 1C1B 1A19   1817 1615 1413 1211   100F 0E0D 0C0B 0A09   0807 0605 04EE DD34

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0005
   zmm31: 0000 0058 0000 0058   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 7703 0201 0005
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0005
   zmm31: 0000 0098 0000 0098   3534 3332 3130 2F2E   2D2C 2B2A 2928 2726   2524 2322 2120 1F1E   1D1C 1B1A 1918 1716   1514 1312 1110 0F0E   0D0C 0B0A 0908 0706   0504 CCBB AA99 8805
  Offset: 0000 0000 0000 0098   Length: 0000 0000 0000 0035
   zmm31: 0000 0018 0000 0018   0000 3534 3332 3130   2F2E 2D2C 2B2A 2928   2726 2524 2322 2120   1F1E 1D1C 1B1A 1918   1716 1514 1312 1110   0F0E 0D0C 0B0A 0908   0706 0504 FFEE DD35

  END

Nasm::X86::String::deleteChar($String, $position)

Delete a character in a string.

     Parameter  Description
  1  $String    String
  2  $position  Variable position in string

Example:

    my $c = Rb(0..255);
    my $S = CreateArena;   my $s = $S->CreateString;

    $s->append(source=>V(source, $c),  V(size, 165)); $s->dump;
    $s->deleteChar(V(position, 0x44));                $s->dump;
    $s->len->outNL;

    ok Assemble(debug => 0, eq => <<END);
  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0037
   zmm31: 0000 0058 0000 0098   3635 3433 3231 302F   2E2D 2C2B 2A29 2827   2625 2423 2221 201F   1E1D 1C1B 1A19 1817   1615 1413 1211 100F   0E0D 0C0B 0A09 0807   0605 0403 0201 0037
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0037
   zmm31: 0000 0098 0000 0018   6D6C 6B6A 6968 6766   6564 6362 6160 5F5E   5D5C 5B5A 5958 5756   5554 5352 5150 4F4E   4D4C 4B4A 4948 4746   4544 4342 4140 3F3E   3D3C 3B3A 3938 3737
  Offset: 0000 0000 0000 0098   Length: 0000 0000 0000 0037
   zmm31: 0000 0018 0000 0058   A4A3 A2A1 A09F 9E9D   9C9B 9A99 9897 9695   9493 9291 908F 8E8D   8C8B 8A89 8887 8685   8483 8281 807F 7E7D   7C7B 7A79 7877 7675   7473 7271 706F 6E37

  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0037
   zmm31: 0000 0058 0000 0098   3635 3433 3231 302F   2E2D 2C2B 2A29 2827   2625 2423 2221 201F   1E1D 1C1B 1A19 1817   1615 1413 1211 100F   0E0D 0C0B 0A09 0807   0605 0403 0201 0037
  Offset: 0000 0000 0000 0058   Length: 0000 0000 0000 0036
   zmm31: 0000 0098 0000 0018   186D 6C6B 6A69 6867   6665 6463 6261 605F   5E5D 5C5B 5A59 5857   5655 5453 5251 504F   4E4D 4C4B 4A49 4847   4645 4342 4140 3F3E   3D3C 3B3A 3938 3736
  Offset: 0000 0000 0000 0098   Length: 0000 0000 0000 0037
   zmm31: 0000 0018 0000 0058   A4A3 A2A1 A09F 9E9D   9C9B 9A99 9897 9695   9493 9291 908F 8E8D   8C8B 8A89 8887 8685   8483 8281 807F 7E7D   7C7B 7A79 7877 7675   7473 7271 706F 6E37

  size: 0000 0000 0000 00A4
  END

Nasm::X86::String::getCharacter($String, $position)

Get a character from a string at the variable position.

     Parameter  Description
  1  $String    String
  2  $position  Variable position

Nasm::X86::String::append($String, @variables)

Append the specified content in memory to the specified string.

     Parameter   Description
  1  $String     String descriptor
  2  @variables  Variables

Nasm::X86::String::appendShortString($string, $short)

Append the content of the specified short string.

     Parameter  Description
  1  $string    String descriptor
  2  $short     Short string

Example:

    my $a = CreateArena;
    my $S = $a->CreateString;

    my $s = CreateShortString(0);
    my $d = Rb(1..63);
    $s->load(K(address, $d), K(size, 9));
    $s->append($s);

    $S->appendShortString($s);

    $S->dump;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  string Dump
  Offset: 0000 0000 0000 0018   Length: 0000 0000 0000 0012
   zmm31: 0000 0018 0000 0018   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0009 0807   0605 0403 0201 0908   0706 0504 0302 0112

  END

    my $a = CreateArena;
    my $t = $a->CreateTree;

    my $s = CreateShortString(0);
    my $d = Rb(1..63);
    $s->load(K(address, $d), K(size, 9));

    $t->insertShortString($s, K(data,42));

    $t->dump;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Tree at:  0000 0000 0000 0018  length: 0000 0000 0000 0001
    Keys: 0000 0058 0001 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0403 0201
    Data: 0000 0000 0000 0002   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0098
    Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      index: 0000 0000 0000 0000   key: 0000 0000 0403 0201   data: 0000 0000 0000 0098 subTree
    Tree at:  0000 0000 0000 0098  length: 0000 0000 0000 0001
      Keys: 0000 00D8 0001 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0807 0605
      Data: 0000 0000 0000 0002   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0118
      Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        index: 0000 0000 0000 0000   key: 0000 0000 0807 0605   data: 0000 0000 0000 0118 subTree
      Tree at:  0000 0000 0000 0118  length: 0000 0000 0000 0001
        Keys: 0000 0158 0000 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0009
        Data: 0000 0000 0000 0002   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 002A
        Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
          index: 0000 0000 0000 0000   key: 0000 0000 0000 0009   data: 0000 0000 0000 002A
      end
    end
  end
  END

Nasm::X86::String::saveToShortString($String, $short, $first)

Place as much as possible of the specified string into the specified short string.

     Parameter  Description
  1  $String    String descriptor
  2  $short     Short string descriptor
  3  $first     Optional offset to first block of string

Nasm::X86::String::clear($String)

Clear the block by freeing all but the first block and putting the remainder on the free chain addressed by Yggdrasil .

     Parameter  Description
  1  $String    String descriptor

Array

Array constructed as a set of blocks in an arena

DescribeArray(%options)

Describe a dynamic array held in an arena.

     Parameter  Description
  1  %options   Array description

Nasm::X86::Arena::DescribeArray($arena, %options)

Describe a dynamic array held in an arena.

     Parameter  Description
  1  $arena     Arena description
  2  %options   Options

Nasm::X86::Arena::CreateArray($arena)

Create a dynamic array held in an arena.

     Parameter  Description
  1  $arena     Arena description

Nasm::X86::Array::reload($array, %options)

Reload the specified array description.

     Parameter  Description
  1  $array     Array descriptor
  2  %options   {first=>first block of array if not the existing first node; arena=>arena used by array if not the existing arena}

Nasm::X86::Array::dump($Array, @variables)

Dump a array.

     Parameter   Description
  1  $Array      Array descriptor
  2  @variables  Variables

Nasm::X86::Array::push($Array, $element)

Push a variable element onto an array.

     Parameter  Description
  1  $Array     Array descriptor
  2  $element   Variable element to push

Example:

    my $c = Rb(0..255);
    my $A = CreateArena;  my $a = $A->CreateArray;
    my $l = V(limit, 15);
    my $L = $l + 5;

    my sub put                                                                    # Put a constant or a variable
     {my ($e) = @_;
      $a->push(ref($e) ? $e : V($e, $e));
     };

    my sub get                                                                    # Get a constant or a variable
     {my ($i) = @_;
      my $e = $a->get(my $v = ref($i) ? $i : K('index', $i));
      $v->out("index: ", "  "); $e->outNL;
     };

    $l->for(sub                                                                   # Loop to the limit pushing
     {my ($index, $start, $next, $end) = @_;
      put($index+1);
     });

    $l->for(sub                                                                   # Loop to the limit getting
     {my ($index, $start, $next, $end) = @_;
      get($index);
     });

    put(16);
    get(15);

    $L->for(sub
     {my ($index, $start, $next, $end) = @_;
      put($index+$l+2);
     });

    $L->for(sub
     {my ($index, $start, $next, $end) = @_;
      get($index + $l + 1);
     });

    if (1)
     {$a->put(my $i = V('index',  9), my $e = V(element, 0xFFF9));
      get(9);
     }

    if (1)
     {$a->put(my $i = V('index', 19), my $e = V(element, 0xEEE9));
      get(19);
     }

    ($l+$L+1)->for(sub
     {my ($i, $start, $next, $end) = @_;
      my $e = $a->pop;
      $e->outNL;
     });

    V(limit, 38)->for(sub                                                         # Push using a loop and reusing the freed space
     {my ($index, $start, $next, $end) = @_;
      $a->push($index*2);
     });

    V(limit, 38)->for(sub                                                         # Push using a loop and reusing the freed space
     {my ($index, $start, $next, $end) = @_;
      $a->pop->outNL;
     });

    $a->dump;

    ok Assemble(debug => 0, eq => <<END);
  index: 0000 0000 0000 0000  element: 0000 0000 0000 0001
  index: 0000 0000 0000 0001  element: 0000 0000 0000 0002
  index: 0000 0000 0000 0002  element: 0000 0000 0000 0003
  index: 0000 0000 0000 0003  element: 0000 0000 0000 0004
  index: 0000 0000 0000 0004  element: 0000 0000 0000 0005
  index: 0000 0000 0000 0005  element: 0000 0000 0000 0006
  index: 0000 0000 0000 0006  element: 0000 0000 0000 0007
  index: 0000 0000 0000 0007  element: 0000 0000 0000 0008
  index: 0000 0000 0000 0008  element: 0000 0000 0000 0009
  index: 0000 0000 0000 0009  element: 0000 0000 0000 000A
  index: 0000 0000 0000 000A  element: 0000 0000 0000 000B
  index: 0000 0000 0000 000B  element: 0000 0000 0000 000C
  index: 0000 0000 0000 000C  element: 0000 0000 0000 000D
  index: 0000 0000 0000 000D  element: 0000 0000 0000 000E
  index: 0000 0000 0000 000E  element: 0000 0000 0000 000F
  index: 0000 0000 0000 000F  element: 0000 0000 0000 0010
  index: 0000 0000 0000 0010  element: 0000 0000 0000 0011
  index: 0000 0000 0000 0011  element: 0000 0000 0000 0012
  index: 0000 0000 0000 0012  element: 0000 0000 0000 0013
  index: 0000 0000 0000 0013  element: 0000 0000 0000 0014
  index: 0000 0000 0000 0014  element: 0000 0000 0000 0015
  index: 0000 0000 0000 0015  element: 0000 0000 0000 0016
  index: 0000 0000 0000 0016  element: 0000 0000 0000 0017
  index: 0000 0000 0000 0017  element: 0000 0000 0000 0018
  index: 0000 0000 0000 0018  element: 0000 0000 0000 0019
  index: 0000 0000 0000 0019  element: 0000 0000 0000 001A
  index: 0000 0000 0000 001A  element: 0000 0000 0000 001B
  index: 0000 0000 0000 001B  element: 0000 0000 0000 001C
  index: 0000 0000 0000 001C  element: 0000 0000 0000 001D
  index: 0000 0000 0000 001D  element: 0000 0000 0000 001E
  index: 0000 0000 0000 001E  element: 0000 0000 0000 001F
  index: 0000 0000 0000 001F  element: 0000 0000 0000 0020
  index: 0000 0000 0000 0020  element: 0000 0000 0000 0021
  index: 0000 0000 0000 0021  element: 0000 0000 0000 0022
  index: 0000 0000 0000 0022  element: 0000 0000 0000 0023
  index: 0000 0000 0000 0023  element: 0000 0000 0000 0024
  index: 0000 0000 0000 0009  element: 0000 0000 0000 FFF9
  index: 0000 0000 0000 0013  element: 0000 0000 0000 EEE9
  element: 0000 0000 0000 0024
  element: 0000 0000 0000 0023
  element: 0000 0000 0000 0022
  element: 0000 0000 0000 0021
  element: 0000 0000 0000 0020
  element: 0000 0000 0000 001F
  element: 0000 0000 0000 001E
  element: 0000 0000 0000 001D
  element: 0000 0000 0000 001C
  element: 0000 0000 0000 001B
  element: 0000 0000 0000 001A
  element: 0000 0000 0000 0019
  element: 0000 0000 0000 0018
  element: 0000 0000 0000 0017
  element: 0000 0000 0000 0016
  element: 0000 0000 0000 0015
  element: 0000 0000 0000 EEE9
  element: 0000 0000 0000 0013
  element: 0000 0000 0000 0012
  element: 0000 0000 0000 0011
  element: 0000 0000 0000 0010
  element: 0000 0000 0000 000F
  element: 0000 0000 0000 000E
  element: 0000 0000 0000 000D
  element: 0000 0000 0000 000C
  element: 0000 0000 0000 000B
  element: 0000 0000 0000 FFF9
  element: 0000 0000 0000 0009
  element: 0000 0000 0000 0008
  element: 0000 0000 0000 0007
  element: 0000 0000 0000 0006
  element: 0000 0000 0000 0005
  element: 0000 0000 0000 0004
  element: 0000 0000 0000 0003
  element: 0000 0000 0000 0002
  element: 0000 0000 0000 0001
  element: 0000 0000 0000 004A
  element: 0000 0000 0000 0048
  element: 0000 0000 0000 0046
  element: 0000 0000 0000 0044
  element: 0000 0000 0000 0042
  element: 0000 0000 0000 0040
  element: 0000 0000 0000 003E
  element: 0000 0000 0000 003C
  element: 0000 0000 0000 003A
  element: 0000 0000 0000 0038
  element: 0000 0000 0000 0036
  element: 0000 0000 0000 0034
  element: 0000 0000 0000 0032
  element: 0000 0000 0000 0030
  element: 0000 0000 0000 002E
  element: 0000 0000 0000 002C
  element: 0000 0000 0000 002A
  element: 0000 0000 0000 0028
  element: 0000 0000 0000 0026
  element: 0000 0000 0000 0024
  element: 0000 0000 0000 0022
  element: 0000 0000 0000 0020
  element: 0000 0000 0000 001E
  element: 0000 0000 0000 001C
  element: 0000 0000 0000 001A
  element: 0000 0000 0000 0018
  element: 0000 0000 0000 0016
  element: 0000 0000 0000 0014
  element: 0000 0000 0000 0012
  element: 0000 0000 0000 0010
  element: 0000 0000 0000 000E
  element: 0000 0000 0000 000C
  element: 0000 0000 0000 000A
  element: 0000 0000 0000 0008
  element: 0000 0000 0000 0006
  element: 0000 0000 0000 0004
  element: 0000 0000 0000 0002
  element: 0000 0000 0000 0000
  array
  Size: 0000 0000 0000 0000   zmm31: 0000 001C 0000 001A   0000 0018 0000 0016   0000 0014 0000 0012   0000 0010 0000 000E   0000 000C 0000 000A   0000 0008 0000 0006   0000 0004 0000 0002   0000 0000 0000 0000
  END

    my $c = Rb(0..255);
    my $A = CreateArena;  my $a = $A->CreateArray;

    my sub put
     {my ($e) = @_;
      $a->push(V($e, $e));
     };

    my sub get
     {my ($i) = @_;                                                               # Parameters
      my $e = $a->get(my $v = V('index', $i));
      $v->out; PrintOutString "  "; $e->outNL;
     };

    put($_) for 1..15;  get(15);

    ok Assemble(debug => 2, eq => <<END);
  Index out of bounds on get from array, Index: 0000 0000 0000 000F  Size: 0000 0000 0000 000F
  END

Nasm::X86::Array::pop($Array)

Pop an element from an array and return it in a variable.

     Parameter  Description
  1  $Array     Array descriptor

Example:

    my $c = Rb(0..255);
    my $A = CreateArena;  my $a = $A->CreateArray;
    my $l = V(limit, 15);
    my $L = $l + 5;

    my sub put                                                                    # Put a constant or a variable
     {my ($e) = @_;
      $a->push(ref($e) ? $e : V($e, $e));
     };

    my sub get                                                                    # Get a constant or a variable
     {my ($i) = @_;
      my $e = $a->get(my $v = ref($i) ? $i : K('index', $i));
      $v->out("index: ", "  "); $e->outNL;
     };

    $l->for(sub                                                                   # Loop to the limit pushing
     {my ($index, $start, $next, $end) = @_;
      put($index+1);
     });

    $l->for(sub                                                                   # Loop to the limit getting
     {my ($index, $start, $next, $end) = @_;
      get($index);
     });

    put(16);
    get(15);

    $L->for(sub
     {my ($index, $start, $next, $end) = @_;
      put($index+$l+2);
     });

    $L->for(sub
     {my ($index, $start, $next, $end) = @_;
      get($index + $l + 1);
     });

    if (1)
     {$a->put(my $i = V('index',  9), my $e = V(element, 0xFFF9));
      get(9);
     }

    if (1)
     {$a->put(my $i = V('index', 19), my $e = V(element, 0xEEE9));
      get(19);
     }

    ($l+$L+1)->for(sub
     {my ($i, $start, $next, $end) = @_;
      my $e = $a->pop;
      $e->outNL;
     });

    V(limit, 38)->for(sub                                                         # Push using a loop and reusing the freed space
     {my ($index, $start, $next, $end) = @_;
      $a->push($index*2);
     });

    V(limit, 38)->for(sub                                                         # Push using a loop and reusing the freed space
     {my ($index, $start, $next, $end) = @_;
      $a->pop->outNL;
     });

    $a->dump;

    ok Assemble(debug => 0, eq => <<END);
  index: 0000 0000 0000 0000  element: 0000 0000 0000 0001
  index: 0000 0000 0000 0001  element: 0000 0000 0000 0002
  index: 0000 0000 0000 0002  element: 0000 0000 0000 0003
  index: 0000 0000 0000 0003  element: 0000 0000 0000 0004
  index: 0000 0000 0000 0004  element: 0000 0000 0000 0005
  index: 0000 0000 0000 0005  element: 0000 0000 0000 0006
  index: 0000 0000 0000 0006  element: 0000 0000 0000 0007
  index: 0000 0000 0000 0007  element: 0000 0000 0000 0008
  index: 0000 0000 0000 0008  element: 0000 0000 0000 0009
  index: 0000 0000 0000 0009  element: 0000 0000 0000 000A
  index: 0000 0000 0000 000A  element: 0000 0000 0000 000B
  index: 0000 0000 0000 000B  element: 0000 0000 0000 000C
  index: 0000 0000 0000 000C  element: 0000 0000 0000 000D
  index: 0000 0000 0000 000D  element: 0000 0000 0000 000E
  index: 0000 0000 0000 000E  element: 0000 0000 0000 000F
  index: 0000 0000 0000 000F  element: 0000 0000 0000 0010
  index: 0000 0000 0000 0010  element: 0000 0000 0000 0011
  index: 0000 0000 0000 0011  element: 0000 0000 0000 0012
  index: 0000 0000 0000 0012  element: 0000 0000 0000 0013
  index: 0000 0000 0000 0013  element: 0000 0000 0000 0014
  index: 0000 0000 0000 0014  element: 0000 0000 0000 0015
  index: 0000 0000 0000 0015  element: 0000 0000 0000 0016
  index: 0000 0000 0000 0016  element: 0000 0000 0000 0017
  index: 0000 0000 0000 0017  element: 0000 0000 0000 0018
  index: 0000 0000 0000 0018  element: 0000 0000 0000 0019
  index: 0000 0000 0000 0019  element: 0000 0000 0000 001A
  index: 0000 0000 0000 001A  element: 0000 0000 0000 001B
  index: 0000 0000 0000 001B  element: 0000 0000 0000 001C
  index: 0000 0000 0000 001C  element: 0000 0000 0000 001D
  index: 0000 0000 0000 001D  element: 0000 0000 0000 001E
  index: 0000 0000 0000 001E  element: 0000 0000 0000 001F
  index: 0000 0000 0000 001F  element: 0000 0000 0000 0020
  index: 0000 0000 0000 0020  element: 0000 0000 0000 0021
  index: 0000 0000 0000 0021  element: 0000 0000 0000 0022
  index: 0000 0000 0000 0022  element: 0000 0000 0000 0023
  index: 0000 0000 0000 0023  element: 0000 0000 0000 0024
  index: 0000 0000 0000 0009  element: 0000 0000 0000 FFF9
  index: 0000 0000 0000 0013  element: 0000 0000 0000 EEE9
  element: 0000 0000 0000 0024
  element: 0000 0000 0000 0023
  element: 0000 0000 0000 0022
  element: 0000 0000 0000 0021
  element: 0000 0000 0000 0020
  element: 0000 0000 0000 001F
  element: 0000 0000 0000 001E
  element: 0000 0000 0000 001D
  element: 0000 0000 0000 001C
  element: 0000 0000 0000 001B
  element: 0000 0000 0000 001A
  element: 0000 0000 0000 0019
  element: 0000 0000 0000 0018
  element: 0000 0000 0000 0017
  element: 0000 0000 0000 0016
  element: 0000 0000 0000 0015
  element: 0000 0000 0000 EEE9
  element: 0000 0000 0000 0013
  element: 0000 0000 0000 0012
  element: 0000 0000 0000 0011
  element: 0000 0000 0000 0010
  element: 0000 0000 0000 000F
  element: 0000 0000 0000 000E
  element: 0000 0000 0000 000D
  element: 0000 0000 0000 000C
  element: 0000 0000 0000 000B
  element: 0000 0000 0000 FFF9
  element: 0000 0000 0000 0009
  element: 0000 0000 0000 0008
  element: 0000 0000 0000 0007
  element: 0000 0000 0000 0006
  element: 0000 0000 0000 0005
  element: 0000 0000 0000 0004
  element: 0000 0000 0000 0003
  element: 0000 0000 0000 0002
  element: 0000 0000 0000 0001
  element: 0000 0000 0000 004A
  element: 0000 0000 0000 0048
  element: 0000 0000 0000 0046
  element: 0000 0000 0000 0044
  element: 0000 0000 0000 0042
  element: 0000 0000 0000 0040
  element: 0000 0000 0000 003E
  element: 0000 0000 0000 003C
  element: 0000 0000 0000 003A
  element: 0000 0000 0000 0038
  element: 0000 0000 0000 0036
  element: 0000 0000 0000 0034
  element: 0000 0000 0000 0032
  element: 0000 0000 0000 0030
  element: 0000 0000 0000 002E
  element: 0000 0000 0000 002C
  element: 0000 0000 0000 002A
  element: 0000 0000 0000 0028
  element: 0000 0000 0000 0026
  element: 0000 0000 0000 0024
  element: 0000 0000 0000 0022
  element: 0000 0000 0000 0020
  element: 0000 0000 0000 001E
  element: 0000 0000 0000 001C
  element: 0000 0000 0000 001A
  element: 0000 0000 0000 0018
  element: 0000 0000 0000 0016
  element: 0000 0000 0000 0014
  element: 0000 0000 0000 0012
  element: 0000 0000 0000 0010
  element: 0000 0000 0000 000E
  element: 0000 0000 0000 000C
  element: 0000 0000 0000 000A
  element: 0000 0000 0000 0008
  element: 0000 0000 0000 0006
  element: 0000 0000 0000 0004
  element: 0000 0000 0000 0002
  element: 0000 0000 0000 0000
  array
  Size: 0000 0000 0000 0000   zmm31: 0000 001C 0000 001A   0000 0018 0000 0016   0000 0014 0000 0012   0000 0010 0000 000E   0000 000C 0000 000A   0000 0008 0000 0006   0000 0004 0000 0002   0000 0000 0000 0000
  END

Nasm::X86::Array::size($Array, $bs, $first)

Return the size of an array as a variable.

     Parameter  Description
  1  $Array     Array descriptor
  2  $bs        Optional arena address
  3  $first     Optional first block

Example:

  my $t = time;
    my $N = 15;
    my $A = CreateArena;
    my $a = $A->CreateArray;

    $a->push(V(element, $_)) for 1..$N;

    K(loop, $N)->for(sub
     {my ($start, $end, $next) = @_;
      my $l = $a->size;
      If $l == 0, Then {Jmp $end};
      my $e = $a->pop;
      $e->outNL;
     });

    ok Assemble(debug => 0, eq => <<END);
  element: 0000 0000 0000 000F
  element: 0000 0000 0000 000E
  element: 0000 0000 0000 000D
  element: 0000 0000 0000 000C
  element: 0000 0000 0000 000B
  element: 0000 0000 0000 000A
  element: 0000 0000 0000 0009
  element: 0000 0000 0000 0008
  element: 0000 0000 0000 0007
  element: 0000 0000 0000 0006
  element: 0000 0000 0000 0005
  element: 0000 0000 0000 0004
  element: 0000 0000 0000 0003
  element: 0000 0000 0000 0002
  element: 0000 0000 0000 0001
  END

Nasm::X86::Array::get($Array, $index)

Get an element from the array.

     Parameter  Description
  1  $Array     Array descriptor
  2  $index     Variables

Example:

    my $c = Rb(0..255);
    my $A = CreateArena;  my $a = $A->CreateArray;
    my $l = V(limit, 15);
    my $L = $l + 5;

    my sub put                                                                    # Put a constant or a variable
     {my ($e) = @_;
      $a->push(ref($e) ? $e : V($e, $e));
     };

    my sub get                                                                    # Get a constant or a variable
     {my ($i) = @_;
      my $e = $a->get(my $v = ref($i) ? $i : K('index', $i));
      $v->out("index: ", "  "); $e->outNL;
     };

    $l->for(sub                                                                   # Loop to the limit pushing
     {my ($index, $start, $next, $end) = @_;
      put($index+1);
     });

    $l->for(sub                                                                   # Loop to the limit getting
     {my ($index, $start, $next, $end) = @_;
      get($index);
     });

    put(16);
    get(15);

    $L->for(sub
     {my ($index, $start, $next, $end) = @_;
      put($index+$l+2);
     });

    $L->for(sub
     {my ($index, $start, $next, $end) = @_;
      get($index + $l + 1);
     });

    if (1)
     {$a->put(my $i = V('index',  9), my $e = V(element, 0xFFF9));
      get(9);
     }

    if (1)
     {$a->put(my $i = V('index', 19), my $e = V(element, 0xEEE9));
      get(19);
     }

    ($l+$L+1)->for(sub
     {my ($i, $start, $next, $end) = @_;
      my $e = $a->pop;
      $e->outNL;
     });

    V(limit, 38)->for(sub                                                         # Push using a loop and reusing the freed space
     {my ($index, $start, $next, $end) = @_;
      $a->push($index*2);
     });

    V(limit, 38)->for(sub                                                         # Push using a loop and reusing the freed space
     {my ($index, $start, $next, $end) = @_;
      $a->pop->outNL;
     });

    $a->dump;

    ok Assemble(debug => 0, eq => <<END);
  index: 0000 0000 0000 0000  element: 0000 0000 0000 0001
  index: 0000 0000 0000 0001  element: 0000 0000 0000 0002
  index: 0000 0000 0000 0002  element: 0000 0000 0000 0003
  index: 0000 0000 0000 0003  element: 0000 0000 0000 0004
  index: 0000 0000 0000 0004  element: 0000 0000 0000 0005
  index: 0000 0000 0000 0005  element: 0000 0000 0000 0006
  index: 0000 0000 0000 0006  element: 0000 0000 0000 0007
  index: 0000 0000 0000 0007  element: 0000 0000 0000 0008
  index: 0000 0000 0000 0008  element: 0000 0000 0000 0009
  index: 0000 0000 0000 0009  element: 0000 0000 0000 000A
  index: 0000 0000 0000 000A  element: 0000 0000 0000 000B
  index: 0000 0000 0000 000B  element: 0000 0000 0000 000C
  index: 0000 0000 0000 000C  element: 0000 0000 0000 000D
  index: 0000 0000 0000 000D  element: 0000 0000 0000 000E
  index: 0000 0000 0000 000E  element: 0000 0000 0000 000F
  index: 0000 0000 0000 000F  element: 0000 0000 0000 0010
  index: 0000 0000 0000 0010  element: 0000 0000 0000 0011
  index: 0000 0000 0000 0011  element: 0000 0000 0000 0012
  index: 0000 0000 0000 0012  element: 0000 0000 0000 0013
  index: 0000 0000 0000 0013  element: 0000 0000 0000 0014
  index: 0000 0000 0000 0014  element: 0000 0000 0000 0015
  index: 0000 0000 0000 0015  element: 0000 0000 0000 0016
  index: 0000 0000 0000 0016  element: 0000 0000 0000 0017
  index: 0000 0000 0000 0017  element: 0000 0000 0000 0018
  index: 0000 0000 0000 0018  element: 0000 0000 0000 0019
  index: 0000 0000 0000 0019  element: 0000 0000 0000 001A
  index: 0000 0000 0000 001A  element: 0000 0000 0000 001B
  index: 0000 0000 0000 001B  element: 0000 0000 0000 001C
  index: 0000 0000 0000 001C  element: 0000 0000 0000 001D
  index: 0000 0000 0000 001D  element: 0000 0000 0000 001E
  index: 0000 0000 0000 001E  element: 0000 0000 0000 001F
  index: 0000 0000 0000 001F  element: 0000 0000 0000 0020
  index: 0000 0000 0000 0020  element: 0000 0000 0000 0021
  index: 0000 0000 0000 0021  element: 0000 0000 0000 0022
  index: 0000 0000 0000 0022  element: 0000 0000 0000 0023
  index: 0000 0000 0000 0023  element: 0000 0000 0000 0024
  index: 0000 0000 0000 0009  element: 0000 0000 0000 FFF9
  index: 0000 0000 0000 0013  element: 0000 0000 0000 EEE9
  element: 0000 0000 0000 0024
  element: 0000 0000 0000 0023
  element: 0000 0000 0000 0022
  element: 0000 0000 0000 0021
  element: 0000 0000 0000 0020
  element: 0000 0000 0000 001F
  element: 0000 0000 0000 001E
  element: 0000 0000 0000 001D
  element: 0000 0000 0000 001C
  element: 0000 0000 0000 001B
  element: 0000 0000 0000 001A
  element: 0000 0000 0000 0019
  element: 0000 0000 0000 0018
  element: 0000 0000 0000 0017
  element: 0000 0000 0000 0016
  element: 0000 0000 0000 0015
  element: 0000 0000 0000 EEE9
  element: 0000 0000 0000 0013
  element: 0000 0000 0000 0012
  element: 0000 0000 0000 0011
  element: 0000 0000 0000 0010
  element: 0000 0000 0000 000F
  element: 0000 0000 0000 000E
  element: 0000 0000 0000 000D
  element: 0000 0000 0000 000C
  element: 0000 0000 0000 000B
  element: 0000 0000 0000 FFF9
  element: 0000 0000 0000 0009
  element: 0000 0000 0000 0008
  element: 0000 0000 0000 0007
  element: 0000 0000 0000 0006
  element: 0000 0000 0000 0005
  element: 0000 0000 0000 0004
  element: 0000 0000 0000 0003
  element: 0000 0000 0000 0002
  element: 0000 0000 0000 0001
  element: 0000 0000 0000 004A
  element: 0000 0000 0000 0048
  element: 0000 0000 0000 0046
  element: 0000 0000 0000 0044
  element: 0000 0000 0000 0042
  element: 0000 0000 0000 0040
  element: 0000 0000 0000 003E
  element: 0000 0000 0000 003C
  element: 0000 0000 0000 003A
  element: 0000 0000 0000 0038
  element: 0000 0000 0000 0036
  element: 0000 0000 0000 0034
  element: 0000 0000 0000 0032
  element: 0000 0000 0000 0030
  element: 0000 0000 0000 002E
  element: 0000 0000 0000 002C
  element: 0000 0000 0000 002A
  element: 0000 0000 0000 0028
  element: 0000 0000 0000 0026
  element: 0000 0000 0000 0024
  element: 0000 0000 0000 0022
  element: 0000 0000 0000 0020
  element: 0000 0000 0000 001E
  element: 0000 0000 0000 001C
  element: 0000 0000 0000 001A
  element: 0000 0000 0000 0018
  element: 0000 0000 0000 0016
  element: 0000 0000 0000 0014
  element: 0000 0000 0000 0012
  element: 0000 0000 0000 0010
  element: 0000 0000 0000 000E
  element: 0000 0000 0000 000C
  element: 0000 0000 0000 000A
  element: 0000 0000 0000 0008
  element: 0000 0000 0000 0006
  element: 0000 0000 0000 0004
  element: 0000 0000 0000 0002
  element: 0000 0000 0000 0000
  array
  Size: 0000 0000 0000 0000   zmm31: 0000 001C 0000 001A   0000 0018 0000 0016   0000 0014 0000 0012   0000 0010 0000 000E   0000 000C 0000 000A   0000 0008 0000 0006   0000 0004 0000 0002   0000 0000 0000 0000
  END

Nasm::X86::Array::put($Array, @variables)

Put an element into an array as long as it is with in its limits established by pushing.

     Parameter   Description
  1  $Array      Array descriptor
  2  @variables  Variables

Example:

    my $c = Rb(0..255);
    my $A = CreateArena;  my $a = $A->CreateArray;
    my $l = V(limit, 15);
    my $L = $l + 5;

    my sub put                                                                    # Put a constant or a variable
     {my ($e) = @_;
      $a->push(ref($e) ? $e : V($e, $e));
     };

    my sub get                                                                    # Get a constant or a variable
     {my ($i) = @_;
      my $e = $a->get(my $v = ref($i) ? $i : K('index', $i));
      $v->out("index: ", "  "); $e->outNL;
     };

    $l->for(sub                                                                   # Loop to the limit pushing
     {my ($index, $start, $next, $end) = @_;
      put($index+1);
     });

    $l->for(sub                                                                   # Loop to the limit getting
     {my ($index, $start, $next, $end) = @_;
      get($index);
     });

    put(16);
    get(15);

    $L->for(sub
     {my ($index, $start, $next, $end) = @_;
      put($index+$l+2);
     });

    $L->for(sub
     {my ($index, $start, $next, $end) = @_;
      get($index + $l + 1);
     });

    if (1)
     {$a->put(my $i = V('index',  9), my $e = V(element, 0xFFF9));
      get(9);
     }

    if (1)
     {$a->put(my $i = V('index', 19), my $e = V(element, 0xEEE9));
      get(19);
     }

    ($l+$L+1)->for(sub
     {my ($i, $start, $next, $end) = @_;
      my $e = $a->pop;
      $e->outNL;
     });

    V(limit, 38)->for(sub                                                         # Push using a loop and reusing the freed space
     {my ($index, $start, $next, $end) = @_;
      $a->push($index*2);
     });

    V(limit, 38)->for(sub                                                         # Push using a loop and reusing the freed space
     {my ($index, $start, $next, $end) = @_;
      $a->pop->outNL;
     });

    $a->dump;

    ok Assemble(debug => 0, eq => <<END);
  index: 0000 0000 0000 0000  element: 0000 0000 0000 0001
  index: 0000 0000 0000 0001  element: 0000 0000 0000 0002
  index: 0000 0000 0000 0002  element: 0000 0000 0000 0003
  index: 0000 0000 0000 0003  element: 0000 0000 0000 0004
  index: 0000 0000 0000 0004  element: 0000 0000 0000 0005
  index: 0000 0000 0000 0005  element: 0000 0000 0000 0006
  index: 0000 0000 0000 0006  element: 0000 0000 0000 0007
  index: 0000 0000 0000 0007  element: 0000 0000 0000 0008
  index: 0000 0000 0000 0008  element: 0000 0000 0000 0009
  index: 0000 0000 0000 0009  element: 0000 0000 0000 000A
  index: 0000 0000 0000 000A  element: 0000 0000 0000 000B
  index: 0000 0000 0000 000B  element: 0000 0000 0000 000C
  index: 0000 0000 0000 000C  element: 0000 0000 0000 000D
  index: 0000 0000 0000 000D  element: 0000 0000 0000 000E
  index: 0000 0000 0000 000E  element: 0000 0000 0000 000F
  index: 0000 0000 0000 000F  element: 0000 0000 0000 0010
  index: 0000 0000 0000 0010  element: 0000 0000 0000 0011
  index: 0000 0000 0000 0011  element: 0000 0000 0000 0012
  index: 0000 0000 0000 0012  element: 0000 0000 0000 0013
  index: 0000 0000 0000 0013  element: 0000 0000 0000 0014
  index: 0000 0000 0000 0014  element: 0000 0000 0000 0015
  index: 0000 0000 0000 0015  element: 0000 0000 0000 0016
  index: 0000 0000 0000 0016  element: 0000 0000 0000 0017
  index: 0000 0000 0000 0017  element: 0000 0000 0000 0018
  index: 0000 0000 0000 0018  element: 0000 0000 0000 0019
  index: 0000 0000 0000 0019  element: 0000 0000 0000 001A
  index: 0000 0000 0000 001A  element: 0000 0000 0000 001B
  index: 0000 0000 0000 001B  element: 0000 0000 0000 001C
  index: 0000 0000 0000 001C  element: 0000 0000 0000 001D
  index: 0000 0000 0000 001D  element: 0000 0000 0000 001E
  index: 0000 0000 0000 001E  element: 0000 0000 0000 001F
  index: 0000 0000 0000 001F  element: 0000 0000 0000 0020
  index: 0000 0000 0000 0020  element: 0000 0000 0000 0021
  index: 0000 0000 0000 0021  element: 0000 0000 0000 0022
  index: 0000 0000 0000 0022  element: 0000 0000 0000 0023
  index: 0000 0000 0000 0023  element: 0000 0000 0000 0024
  index: 0000 0000 0000 0009  element: 0000 0000 0000 FFF9
  index: 0000 0000 0000 0013  element: 0000 0000 0000 EEE9
  element: 0000 0000 0000 0024
  element: 0000 0000 0000 0023
  element: 0000 0000 0000 0022
  element: 0000 0000 0000 0021
  element: 0000 0000 0000 0020
  element: 0000 0000 0000 001F
  element: 0000 0000 0000 001E
  element: 0000 0000 0000 001D
  element: 0000 0000 0000 001C
  element: 0000 0000 0000 001B
  element: 0000 0000 0000 001A
  element: 0000 0000 0000 0019
  element: 0000 0000 0000 0018
  element: 0000 0000 0000 0017
  element: 0000 0000 0000 0016
  element: 0000 0000 0000 0015
  element: 0000 0000 0000 EEE9
  element: 0000 0000 0000 0013
  element: 0000 0000 0000 0012
  element: 0000 0000 0000 0011
  element: 0000 0000 0000 0010
  element: 0000 0000 0000 000F
  element: 0000 0000 0000 000E
  element: 0000 0000 0000 000D
  element: 0000 0000 0000 000C
  element: 0000 0000 0000 000B
  element: 0000 0000 0000 FFF9
  element: 0000 0000 0000 0009
  element: 0000 0000 0000 0008
  element: 0000 0000 0000 0007
  element: 0000 0000 0000 0006
  element: 0000 0000 0000 0005
  element: 0000 0000 0000 0004
  element: 0000 0000 0000 0003
  element: 0000 0000 0000 0002
  element: 0000 0000 0000 0001
  element: 0000 0000 0000 004A
  element: 0000 0000 0000 0048
  element: 0000 0000 0000 0046
  element: 0000 0000 0000 0044
  element: 0000 0000 0000 0042
  element: 0000 0000 0000 0040
  element: 0000 0000 0000 003E
  element: 0000 0000 0000 003C
  element: 0000 0000 0000 003A
  element: 0000 0000 0000 0038
  element: 0000 0000 0000 0036
  element: 0000 0000 0000 0034
  element: 0000 0000 0000 0032
  element: 0000 0000 0000 0030
  element: 0000 0000 0000 002E
  element: 0000 0000 0000 002C
  element: 0000 0000 0000 002A
  element: 0000 0000 0000 0028
  element: 0000 0000 0000 0026
  element: 0000 0000 0000 0024
  element: 0000 0000 0000 0022
  element: 0000 0000 0000 0020
  element: 0000 0000 0000 001E
  element: 0000 0000 0000 001C
  element: 0000 0000 0000 001A
  element: 0000 0000 0000 0018
  element: 0000 0000 0000 0016
  element: 0000 0000 0000 0014
  element: 0000 0000 0000 0012
  element: 0000 0000 0000 0010
  element: 0000 0000 0000 000E
  element: 0000 0000 0000 000C
  element: 0000 0000 0000 000A
  element: 0000 0000 0000 0008
  element: 0000 0000 0000 0006
  element: 0000 0000 0000 0004
  element: 0000 0000 0000 0002
  element: 0000 0000 0000 0000
  array
  Size: 0000 0000 0000 0000   zmm31: 0000 001C 0000 001A   0000 0018 0000 0016   0000 0014 0000 0012   0000 0010 0000 000E   0000 000C 0000 000A   0000 0008 0000 0006   0000 0004 0000 0002   0000 0000 0000 0000
  END

Tree

Tree constructed as sets of blocks in an arena.

DescribeTree(%options)

Return a descriptor for a tree with the specified options.

     Parameter  Description
  1  %options   Tree description options

Nasm::X86::Arena::DescribeTree($arena, %options)

Return a descriptor for a tree in the specified arena with the specified options.

     Parameter  Description
  1  $arena     Arena descriptor
  2  %options   Options for tree

Nasm::X86::Arena::CreateTree($arena)

Create a tree in an arena.

     Parameter  Description
  1  $arena     Arena description

Example:

    my $N = 12;
    my $b = CreateArena;
    my $t = $b->CreateTree;

    K(count, $N)->for(sub                                                         # Add some entries to the tree
     {my ($index, $start, $next, $end) = @_;
      my $k = $index + 1;
      $t->insert($k,      $k + 0x100);
      $t->insert($k + $N, $k + 0x200);
     });

    $t->by(sub                                                                    # Iterate through the tree
     {my ($iter, $end) = @_;
      $iter->key ->out('key: ');
      $iter->data->out(' data: ');
      my $D = V(depth);
      $iter->tree->depth($t->address, $iter->node, $D);

      $t->find($iter->key);
      $t->found->out(' found: '); $t->data->out(' data: '); $D->outNL(' depth: ');
     });

    $t->find(K(key, 0xffff));  $t->found->outNL('Found: ');                       # Find some entries
    $t->find(K(key, 0xd));     $t->found->outNL('Found: ');
    If ($t->found > 0,
    Then
     {$t->data->outNL("Data : ");
     });

    ok Assemble(debug => 0, eq => <<END);
  key: 0000 0000 0000 0001 data: 0000 0000 0000 0101 found: 0000 0000 0000 0001 data: 0000 0000 0000 0101 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0002 data: 0000 0000 0000 0102 found: 0000 0000 0000 0001 data: 0000 0000 0000 0102 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0003 data: 0000 0000 0000 0103 found: 0000 0000 0000 0001 data: 0000 0000 0000 0103 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0004 data: 0000 0000 0000 0104 found: 0000 0000 0000 0001 data: 0000 0000 0000 0104 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0005 data: 0000 0000 0000 0105 found: 0000 0000 0000 0001 data: 0000 0000 0000 0105 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0006 data: 0000 0000 0000 0106 found: 0000 0000 0000 0001 data: 0000 0000 0000 0106 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0007 data: 0000 0000 0000 0107 found: 0000 0000 0000 0001 data: 0000 0000 0000 0107 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0008 data: 0000 0000 0000 0108 found: 0000 0000 0000 0001 data: 0000 0000 0000 0108 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0009 data: 0000 0000 0000 0109 found: 0000 0000 0000 0001 data: 0000 0000 0000 0109 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 000A data: 0000 0000 0000 010A found: 0000 0000 0000 0001 data: 0000 0000 0000 010A depth: 0000 0000 0000 0002
  key: 0000 0000 0000 000B data: 0000 0000 0000 010B found: 0000 0000 0000 0001 data: 0000 0000 0000 010B depth: 0000 0000 0000 0002
  key: 0000 0000 0000 000C data: 0000 0000 0000 010C found: 0000 0000 0000 0001 data: 0000 0000 0000 010C depth: 0000 0000 0000 0002
  key: 0000 0000 0000 000D data: 0000 0000 0000 0201 found: 0000 0000 0000 0001 data: 0000 0000 0000 0201 depth: 0000 0000 0000 0001
  key: 0000 0000 0000 000E data: 0000 0000 0000 0202 found: 0000 0000 0000 0001 data: 0000 0000 0000 0202 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 000F data: 0000 0000 0000 0203 found: 0000 0000 0000 0001 data: 0000 0000 0000 0203 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0010 data: 0000 0000 0000 0204 found: 0000 0000 0000 0001 data: 0000 0000 0000 0204 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0011 data: 0000 0000 0000 0205 found: 0000 0000 0000 0001 data: 0000 0000 0000 0205 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0012 data: 0000 0000 0000 0206 found: 0000 0000 0000 0001 data: 0000 0000 0000 0206 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0013 data: 0000 0000 0000 0207 found: 0000 0000 0000 0001 data: 0000 0000 0000 0207 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0014 data: 0000 0000 0000 0208 found: 0000 0000 0000 0001 data: 0000 0000 0000 0208 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0015 data: 0000 0000 0000 0209 found: 0000 0000 0000 0001 data: 0000 0000 0000 0209 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0016 data: 0000 0000 0000 020A found: 0000 0000 0000 0001 data: 0000 0000 0000 020A depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0017 data: 0000 0000 0000 020B found: 0000 0000 0000 0001 data: 0000 0000 0000 020B depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0018 data: 0000 0000 0000 020C found: 0000 0000 0000 0001 data: 0000 0000 0000 020C depth: 0000 0000 0000 0002
  Found: 0000 0000 0000 0000
  Found: 0000 0000 0000 0001
  Data : 0000 0000 0000 0201
  END

Nasm::X86::Tree::reload($tree, %options)

Reload the specified tree description.

     Parameter  Description
  1  $tree      Tree descriptor
  2  %options   {first=>first node of tree if not the existing first node; arena=>arena used by tree if not the existing arena}

Nasm::X86::Tree::find($t, $key, $bs, $first)

Find a key in a tree and test whether the found data is a sub tree. The results are held in the variables "found", "data", "subTree" addressed by the tree descriptor.

     Parameter  Description
  1  $t         Tree descriptor
  2  $key       Key field to search for
  3  $bs        Optional arena address
  4  $first     Optional start node

Nasm::X86::Tree::findAndReload($t, $key)

Find a key in the specified tree and clone it is it is a sub tree.

     Parameter  Description
  1  $t         Tree descriptor
  2  $key       Key as a dword

Example:

    my $L = K(loop, 4);
    my $b = CreateArena;
    my $T = $b->CreateTree;
    my $t = $T->reload;

    $L->for(sub
     {my ($i, $start, $next, $end) = @_;
      $t->insertTreeAndReload($i);
      $t->first->outNL;
     });

    $t->insert($L, $L*2);

    my $f = $T->reload;
    $L->for(sub
     {my ($i, $start, $next, $end) = @_;
      $f->findAndReload($i);
      $i->out('i: '); $f->found->out('  f: '); $f->data->out('  d: '); $f->subTree->outNL('  s: ');
     });
    $f->find($L);
    $L->out('N: '); $f->found->out('  f: '); $f->data->out('  d: ');   $f->subTree->outNL('  s: ');

    ok Assemble(debug => 0, eq => <<END);
  first: 0000 0000 0000 0098
  first: 0000 0000 0000 0118
  first: 0000 0000 0000 0198
  first: 0000 0000 0000 0218
  i: 0000 0000 0000 0000  f: 0000 0000 0000 0001  d: 0000 0000 0000 0098  s: 0000 0000 0000 0001
  i: 0000 0000 0000 0001  f: 0000 0000 0000 0001  d: 0000 0000 0000 0118  s: 0000 0000 0000 0001
  i: 0000 0000 0000 0002  f: 0000 0000 0000 0001  d: 0000 0000 0000 0198  s: 0000 0000 0000 0001
  i: 0000 0000 0000 0003  f: 0000 0000 0000 0001  d: 0000 0000 0000 0218  s: 0000 0000 0000 0001
  N: 0000 0000 0000 0004  f: 0000 0000 0000 0001  d: 0000 0000 0000 0008  s: 0000 0000 0000 0000
  END

Nasm::X86::Tree::findShortString($tree, $string)

Find the data at the end of a key chain held in a short string. Return a tree descriptor referencing the data located or marked as failed to find.

     Parameter  Description
  1  $tree      Tree descriptor
  2  $string    Short string

Nasm::X86::Tree::size($t)

Return a variable containing the number of keys in the specified tree.

     Parameter  Description
  1  $t         Tree descriptor

Example:

    my $b = CreateArena;
    my $t = $b->CreateTree;
    my $s = $t->size;
       $s->outNL;

    V(count, 24)->for(sub
     {my ($index, $start, $next, $end) = @_;
      my $k = $index + 1; my $d = $k + 0x100;
      $t->insert($k, $d);
      my $s = $t->size;
         $s->outNL;
     });

    $t->getKeysDataNode($t->first, 31, 30, 29);
    PrintOutStringNL "Root"; $t->first->outNL('First: ');
    PrintOutRegisterInHex zmm31, zmm30, zmm29;

    $t->getKeysDataNode(V(offset, 0xd8), 28,27,26);
    PrintOutStringNL "Left";
    PrintOutRegisterInHex zmm28, zmm27, zmm26;

    $t->getKeysDataNode(V(offset, 0x258), 28,27,26);
    PrintOutStringNL "Left";
    PrintOutRegisterInHex zmm28, zmm27, zmm26;

    $t->getKeysDataNode(V(offset, 0x198), 28,27,26);
    PrintOutStringNL "Left";
    PrintOutRegisterInHex zmm28, zmm27, zmm26;

    ok Assemble(debug => 0, eq => <<END);
  size: 0000 0000 0000 0000
  size: 0000 0000 0000 0001
  size: 0000 0000 0000 0002
  size: 0000 0000 0000 0003
  size: 0000 0000 0000 0004
  size: 0000 0000 0000 0005
  size: 0000 0000 0000 0006
  size: 0000 0000 0000 0007
  size: 0000 0000 0000 0008
  size: 0000 0000 0000 0009
  size: 0000 0000 0000 000A
  size: 0000 0000 0000 000B
  size: 0000 0000 0000 000C
  size: 0000 0000 0000 000D
  size: 0000 0000 0000 000E
  size: 0000 0000 0000 000F
  size: 0000 0000 0000 0010
  size: 0000 0000 0000 0011
  size: 0000 0000 0000 0012
  size: 0000 0000 0000 0013
  size: 0000 0000 0000 0014
  size: 0000 0000 0000 0015
  size: 0000 0000 0000 0016
  size: 0000 0000 0000 0017
  size: 0000 0000 0000 0018
  Root
  First: 0000 0000 0000 0018
   zmm31: 0000 0058 0000 0002   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0010 0000 0008
   zmm30: 0000 0098 0000 0030   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0110 0000 0108
   zmm29: 0000 0018 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0198   0000 0258 0000 00D8
  Left
   zmm28: 0000 0118 0000 0007   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0007   0000 0006 0000 0005   0000 0004 0000 0003   0000 0002 0000 0001
   zmm27: 0000 0158 0000 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0107   0000 0106 0000 0105   0000 0104 0000 0103   0000 0102 0000 0101
   zmm26: 0000 00D8 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
  Left
   zmm28: 0000 0298 0000 0007   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 000F   0000 000E 0000 000D   0000 000C 0000 000B   0000 000A 0000 0009
   zmm27: 0000 02D8 0000 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 010F   0000 010E 0000 010D   0000 010C 0000 010B   0000 010A 0000 0109
   zmm26: 0000 0258 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
  Left
   zmm28: 0000 01D8 0000 0008   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0018 0000 0017   0000 0016 0000 0015   0000 0014 0000 0013   0000 0012 0000 0011
   zmm27: 0000 0218 0000 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0118 0000 0117   0000 0116 0000 0115   0000 0114 0000 0113   0000 0112 0000 0111
   zmm26: 0000 0198 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
  END

Nasm::X86::Tree::insertDataOrTree($t, $tnd, $key, $data)

Insert either a key, data pair into the tree or create a sub tree at the specified key (if it does not already exist) and return the offset of the first block of the sub tree in the data variable.

     Parameter  Description
  1  $t         Tree descriptor
  2  $tnd       0 - data or 1 - tree
  3  $key       Key as a dword
  4  $data      Data as a dword

Nasm::X86::Tree::insert($t, $key, $data)

Insert a dword into into the specified tree at the specified key.

     Parameter  Description
  1  $t         Tree descriptor
  2  $key       Key as a dword
  3  $data      Data as a dword

Example:

    my $b = CreateArena;
    my $t = $b->CreateTree;
    my $T = $b->CreateTree;

    $T->insert(K(key, 2), K(data, 4));
    $t->insert(K(key, 5), K(data, 7));

    $T->print;
    $t->print;

    ok Assemble(debug => 0, eq => <<END);
  Tree at:  0000 0000 0000 0098
  key: 0000 0000 0000 0002 data: 0000 0000 0000 0004 depth: 0000 0000 0000 0001
  Tree at:  0000 0000 0000 0018
  key: 0000 0000 0000 0005 data: 0000 0000 0000 0007 depth: 0000 0000 0000 0001
  END

Nasm::X86::Tree::insertTree($t, $key, $subTree)

Insert a sub tree into the specified tree tree under the specified key. If no sub tree is supplied an empty one is provided gratis.

     Parameter  Description
  1  $t         Tree descriptor
  2  $key       Key as a dword
  3  $subTree   Sub tree to insert else an empty one will be added

Example:

    my $b = CreateArena;
    my $t = $b->CreateTree;
    my $T = $b->CreateTree;

    $T->insert    (K(key, 2), K(data, 4));
    $t->insertTree(K(key, 1), $T);

    $t->print;

    ok Assemble(debug => 0, eq => <<END);
  Tree at:  0000 0000 0000 0098
  key: 0000 0000 0000 0002 data: 0000 0000 0000 0004 depth: 0000 0000 0000 0001
  Tree at:  0000 0000 0000 0018
  key: 0000 0000 0000 0005 data: 0000 0000 0000 0007 depth: 0000 0000 0000 0001
  END

    my $L = K(loop, 11);
    my $b = CreateArena;
    my $B = CreateArena;
    my $t = $b->CreateTree;
    my $T = $B->CreateTree;

    $L->for(sub
     {my ($i, $start, $next, $end) = @_;
      $t->insert($i+0x11, K(data, 0xFF));
      $T->insert($i+0x22, K(data, 0xDD));
     });

    $b->dump;
    $B->dump;

    $t->print;
    $T->print;

    ok Assemble(debug => 0, eq => <<END);
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0098
  Block:  0000 0000 0000 0000  0010 0000 0000 00009800 0000 0000 00000000 0000 0000 00001100 0000 1200 00001300 0000 1400 00001500 0000 1600 00001700 0000 1800 00001900 0000 1A00 0000
  Block:  0000 0000 0000 0001  1B00 0000 0000 00000000 0000 0000 00000B00 0000 5800 0000FF00 0000 FF00 0000FF00 0000 FF00 0000FF00 0000 FF00 0000FF00 0000 FF00 0000FF00 0000 FF00 0000
  Block:  0000 0000 0000 0002  FF00 0000 0000 00000000 0000 0000 00001600 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0098
  Block:  0000 0000 0000 0000  0010 0000 0000 00009800 0000 0000 00000000 0000 0000 00002200 0000 2300 00002400 0000 2500 00002600 0000 2700 00002800 0000 2900 00002A00 0000 2B00 0000
  Block:  0000 0000 0000 0001  2C00 0000 0000 00000000 0000 0000 00000B00 0000 5800 0000DD00 0000 DD00 0000DD00 0000 DD00 0000DD00 0000 DD00 0000DD00 0000 DD00 0000DD00 0000 DD00 0000
  Block:  0000 0000 0000 0002  DD00 0000 0000 00000000 0000 0000 00001600 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Tree at:  0000 0000 0000 0018
  key: 0000 0000 0000 0011 data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0012 data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0013 data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0014 data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0015 data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0016 data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0017 data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0018 data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0019 data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 001A data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  key: 0000 0000 0000 001B data: 0000 0000 0000 00FF depth: 0000 0000 0000 0001
  Tree at:  0000 0000 0000 0018
  key: 0000 0000 0000 0022 data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0023 data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0024 data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0025 data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0026 data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0027 data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0028 data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0029 data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 002A data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 002B data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  key: 0000 0000 0000 002C data: 0000 0000 0000 00DD depth: 0000 0000 0000 0001
  END

Nasm::X86::Tree::insertTreeAndReload($t, $key)

Insert a new sub tree into the specified tree tree under the specified key and return a descriptor for it. If the tree already exists, return a descriptor for it.

     Parameter  Description
  1  $t         Tree descriptor
  2  $key       Key as a dword

Example:

    my $L = K(loop, 4);
    my $b = CreateArena;
    my $T = $b->CreateTree;
    my $t = $T->reload;

    $L->for(sub
     {my ($i, $start, $next, $end) = @_;
      $t->insertTreeAndReload($i);
      $t->first->outNL;
     });

    $t->insert($L, $L*2);

    my $f = $T->reload;
    $L->for(sub
     {my ($i, $start, $next, $end) = @_;
      $f->findAndReload($i);
      $i->out('i: '); $f->found->out('  f: '); $f->data->out('  d: '); $f->subTree->outNL('  s: ');
     });
    $f->find($L);
    $L->out('N: '); $f->found->out('  f: '); $f->data->out('  d: ');   $f->subTree->outNL('  s: ');

    ok Assemble(debug => 0, eq => <<END);
  first: 0000 0000 0000 0098
  first: 0000 0000 0000 0118
  first: 0000 0000 0000 0198
  first: 0000 0000 0000 0218
  i: 0000 0000 0000 0000  f: 0000 0000 0000 0001  d: 0000 0000 0000 0098  s: 0000 0000 0000 0001
  i: 0000 0000 0000 0001  f: 0000 0000 0000 0001  d: 0000 0000 0000 0118  s: 0000 0000 0000 0001
  i: 0000 0000 0000 0002  f: 0000 0000 0000 0001  d: 0000 0000 0000 0198  s: 0000 0000 0000 0001
  i: 0000 0000 0000 0003  f: 0000 0000 0000 0001  d: 0000 0000 0000 0218  s: 0000 0000 0000 0001
  N: 0000 0000 0000 0004  f: 0000 0000 0000 0001  d: 0000 0000 0000 0008  s: 0000 0000 0000 0000
  END

Nasm::X86::Tree::insertShortString($tree, $string, $data)

Insert some data at the end of a chain of sub trees keyed by the contents of a short string.

     Parameter  Description
  1  $tree      Tree descriptor
  2  $string    Short string
  3  $data      Data as a dword

Nasm::X86::Tree::leftOrRightMost($t, $dir, $node, $offset)

Return the offset of the left most or right most node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $dir       Direction: left = 0 or right = 1
  3  $node      Start node
  4  $offset    Offset of located node

Nasm::X86::Tree::leftMost($t, $node, $offset)

Return the offset of the left most node from the specified node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $node      Start node
  3  $offset    Returned offset

Nasm::X86::Tree::rightMost($t, $node, $offset)

Return the offset of the left most node from the specified node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $node      Start node
  3  $offset    Returned offset

Nasm::X86::Tree::depth($t, $bs, $node, $depth)

Return the depth of a node within a tree.

     Parameter  Description
  1  $t         Tree descriptor
  2  $bs        Arena address
  3  $node      Node
  4  $depth     Return depth

Sub trees

Construct trees of trees.

Print

Print a tree

Nasm::X86::Tree::print($t)

Print a tree.

     Parameter  Description
  1  $t         Tree

Example:

    my $b = CreateArena;
    my $t = $b->CreateTree;
    my $T = $b->CreateTree;

    $T->insert(K(key, 2), K(data, 4));
    $t->insert(K(key, 5), K(data, 7));

    $T->print;
    $t->print;

    ok Assemble(debug => 0, eq => <<END);
  Tree at:  0000 0000 0000 0098
  key: 0000 0000 0000 0002 data: 0000 0000 0000 0004 depth: 0000 0000 0000 0001
  Tree at:  0000 0000 0000 0018
  key: 0000 0000 0000 0005 data: 0000 0000 0000 0007 depth: 0000 0000 0000 0001
  END

    my $L = V(loop, 45);

    my $b = CreateArena;
    my $t = $b->CreateTree;

    $L->for(sub
     {my ($i, $start, $next, $end) = @_;
      my $l = $L - $i;
      If ($i % 2 == 0, sub
       {$t->insert($i, $l);
        $t->insertTree($l);
       });
     });

    $t->print;

    ok Assemble(debug => 0, eq => <<END);
  Tree at:  0000 0000 0000 0018
  key: 0000 0000 0000 0000 data: 0000 0000 0000 002D depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0001 data: 0000 0000 0000 0ED8 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0ED8
  key: 0000 0000 0000 0002 data: 0000 0000 0000 002B depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0003 data: 0000 0000 0000 0E58 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0E58
  key: 0000 0000 0000 0004 data: 0000 0000 0000 0029 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0005 data: 0000 0000 0000 0DD8 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0DD8
  key: 0000 0000 0000 0006 data: 0000 0000 0000 0027 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0007 data: 0000 0000 0000 0D58 depth: 0000 0000 0000 0001
  Tree at:  0000 0000 0000 0D58
  key: 0000 0000 0000 0008 data: 0000 0000 0000 0025 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0009 data: 0000 0000 0000 0CD8 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0CD8
  key: 0000 0000 0000 000A data: 0000 0000 0000 0023 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 000B data: 0000 0000 0000 0C58 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0C58
  key: 0000 0000 0000 000C data: 0000 0000 0000 0021 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 000D data: 0000 0000 0000 0BD8 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0BD8
  key: 0000 0000 0000 000E data: 0000 0000 0000 001F depth: 0000 0000 0000 0001
  key: 0000 0000 0000 000F data: 0000 0000 0000 0B58 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0B58
  key: 0000 0000 0000 0010 data: 0000 0000 0000 001D depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0011 data: 0000 0000 0000 0AD8 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0AD8
  key: 0000 0000 0000 0012 data: 0000 0000 0000 001B depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0013 data: 0000 0000 0000 0998 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0998
  key: 0000 0000 0000 0014 data: 0000 0000 0000 0019 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0015 data: 0000 0000 0000 0918 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0918
  key: 0000 0000 0000 0016 data: 0000 0000 0000 0017 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0017 data: 0000 0000 0000 0898 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0898
  key: 0000 0000 0000 0018 data: 0000 0000 0000 0015 depth: 0000 0000 0000 0001
  key: 0000 0000 0000 0019 data: 0000 0000 0000 0818 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0818
  key: 0000 0000 0000 001A data: 0000 0000 0000 0013 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 001B data: 0000 0000 0000 06D8 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 06D8
  key: 0000 0000 0000 001C data: 0000 0000 0000 0011 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 001D data: 0000 0000 0000 0658 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0658
  key: 0000 0000 0000 001E data: 0000 0000 0000 000F depth: 0000 0000 0000 0002
  key: 0000 0000 0000 001F data: 0000 0000 0000 05D8 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 05D8
  key: 0000 0000 0000 0020 data: 0000 0000 0000 000D depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0021 data: 0000 0000 0000 0398 depth: 0000 0000 0000 0001
  Tree at:  0000 0000 0000 0398
  key: 0000 0000 0000 0022 data: 0000 0000 0000 000B depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0023 data: 0000 0000 0000 0318 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0318
  key: 0000 0000 0000 0024 data: 0000 0000 0000 0009 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0025 data: 0000 0000 0000 0298 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0298
  key: 0000 0000 0000 0026 data: 0000 0000 0000 0007 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0027 data: 0000 0000 0000 0218 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0218
  key: 0000 0000 0000 0028 data: 0000 0000 0000 0005 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 0029 data: 0000 0000 0000 0198 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0198
  key: 0000 0000 0000 002A data: 0000 0000 0000 0003 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 002B data: 0000 0000 0000 0118 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0118
  key: 0000 0000 0000 002C data: 0000 0000 0000 0001 depth: 0000 0000 0000 0002
  key: 0000 0000 0000 002D data: 0000 0000 0000 0098 depth: 0000 0000 0000 0002
  Tree at:  0000 0000 0000 0098
  END

Nasm::X86::Tree::dump($t, $first, $bs)

Dump a tree and all its sub trees.

     Parameter  Description
  1  $t         Tree
  2  $first     Optional offset to first node
  3  $bs        Optional arena address

Example:

    my $A = CreateArena;
    my $t = $A->CreateTree;

    $t->insert(K('key', 0x99), K('data', 0xcc));
    $A->dump;
    $t->dump;

    ok Assemble(debug => 0, eq => <<END);
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0098
  Block:  0000 0000 0000 0000  0010 0000 0000 00009800 0000 0000 00000000 0000 0000 00009900 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000100 0000 5800 0000CC00 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000200 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Tree at:  0000 0000 0000 0018  length: 0000 0000 0000 0001
    Keys: 0000 0058 0000 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0099
    Data: 0000 0000 0000 0002   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 00CC
    Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      index: 0000 0000 0000 0000   key: 0000 0000 0000 0099   data: 0000 0000 0000 00CC
  end
  END

    my $L = V(loop, 15);

    my $b = CreateArena;
    my $t = $b->CreateTree;

    $L->for(sub
     {my ($i, $start, $next, $end) = @_;
      If ($i % 2 == 0,
      Then
       {$t->insert    ($i, $i);
       },
      Else
       {$t->insertTree($i);
       });
     });

    $t->dump();

    ok Assemble(debug => 0, eq => <<END);
  Tree at:  0000 0000 0000 0018  length: 0000 0000 0000 0001
    Keys: 0000 0058 0001 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0007
    Data: 0000 0418 0000 001E   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0218
    Node: 0000 0018 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0518 0000 0458
      index: 0000 0000 0000 0000   key: 0000 0000 0000 0007   data: 0000 0000 0000 0218 subTree
    Tree at:  0000 0000 0000 0218  length: 0000 0000 0000 0000
      Keys: 0000 0258 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      Data: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    end
    Tree at:  0000 0000 0000 0458  length: 0000 0000 0000 0007
      Keys: 0000 0498 002A 0007   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0006   0000 0005 0000 0004   0000 0003 0000 0002   0000 0001 0000 0000
      Data: 0000 04D8 0000 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0006   0000 0198 0000 0004   0000 0118 0000 0002   0000 0098 0000 0000
      Node: 0000 0458 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        index: 0000 0000 0000 0000   key: 0000 0000 0000 0000   data: 0000 0000 0000 0000
        index: 0000 0000 0000 0001   key: 0000 0000 0000 0001   data: 0000 0000 0000 0098 subTree
        index: 0000 0000 0000 0002   key: 0000 0000 0000 0002   data: 0000 0000 0000 0002
        index: 0000 0000 0000 0003   key: 0000 0000 0000 0003   data: 0000 0000 0000 0118 subTree
        index: 0000 0000 0000 0004   key: 0000 0000 0000 0004   data: 0000 0000 0000 0004
        index: 0000 0000 0000 0005   key: 0000 0000 0000 0005   data: 0000 0000 0000 0198 subTree
        index: 0000 0000 0000 0006   key: 0000 0000 0000 0006   data: 0000 0000 0000 0006
      Tree at:  0000 0000 0000 0098  length: 0000 0000 0000 0000
        Keys: 0000 00D8 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Data: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      end
      Tree at:  0000 0000 0000 0118  length: 0000 0000 0000 0000
        Keys: 0000 0158 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Data: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      end
      Tree at:  0000 0000 0000 0198  length: 0000 0000 0000 0000
        Keys: 0000 01D8 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Data: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      end
    end
    Tree at:  0000 0000 0000 0518  length: 0000 0000 0000 0007
      Keys: 0000 0558 002A 0007   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 000E   0000 000D 0000 000C   0000 000B 0000 000A   0000 0009 0000 0008
      Data: 0000 0598 0000 0001   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 000E   0000 0398 0000 000C   0000 0318 0000 000A   0000 0298 0000 0008
      Node: 0000 0518 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        index: 0000 0000 0000 0000   key: 0000 0000 0000 0008   data: 0000 0000 0000 0008
        index: 0000 0000 0000 0001   key: 0000 0000 0000 0009   data: 0000 0000 0000 0298 subTree
        index: 0000 0000 0000 0002   key: 0000 0000 0000 000A   data: 0000 0000 0000 000A
        index: 0000 0000 0000 0003   key: 0000 0000 0000 000B   data: 0000 0000 0000 0318 subTree
        index: 0000 0000 0000 0004   key: 0000 0000 0000 000C   data: 0000 0000 0000 000C
        index: 0000 0000 0000 0005   key: 0000 0000 0000 000D   data: 0000 0000 0000 0398 subTree
        index: 0000 0000 0000 0006   key: 0000 0000 0000 000E   data: 0000 0000 0000 000E
      Tree at:  0000 0000 0000 0298  length: 0000 0000 0000 0000
        Keys: 0000 02D8 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Data: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      end
      Tree at:  0000 0000 0000 0318  length: 0000 0000 0000 0000
        Keys: 0000 0358 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Data: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      end
      Tree at:  0000 0000 0000 0398  length: 0000 0000 0000 0000
        Keys: 0000 03D8 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Data: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
        Node: 0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
      end
    end
  end
  END

Iteration

Iterate through a tree non recursively

Nasm::X86::Tree::iterator($t, $bs, $first)

Iterate through a multi way tree starting either at the specified node or the first node of the specified tree.

     Parameter  Description
  1  $t         Tree
  2  $bs        Optional arena else the arena associated with the tree
  3  $first     Optionally the node to start at else the first node of the supplied tree will be used

Nasm::X86::Tree::Iterator::next($iter)

Next element in the tree.

     Parameter  Description
  1  $iter      Iterator

Nasm::X86::Tree::by($t, $block, $bs, $first)

Call the specified block with each (key, data) from the specified tree in order.

     Parameter  Description
  1  $t         Tree descriptor
  2  $block     Block to execute
  3  $bs        Arena address if not the one associated with the tree descriptor
  4  $first     First node offset if not the root of the tree provided

Quarks

Quarks allow us to replace unique strings with unique numbers. We can translate either from a string to its associated number or from a number to its associated string or from a quark in one set of quarks to the corresponding quark with the same string in another set of quarks.

DescribeQuarks(%options)

Return a descriptor for a set of quarks.

     Parameter  Description
  1  %options   Options

Nasm::X86::Arena::DescribeQuarks($arena)

Return a descriptor for a tree in the specified arena.

     Parameter  Description
  1  $arena     Arena descriptor

Nasm::X86::Arena::CreateQuarks($arena)

Create quarks in a specified arena.

     Parameter  Description
  1  $arena     Arena description optional arena address

Example:

    my $N = 5;
    my $a = CreateArena;                                                          # Arena containing quarks
    my $Q = $a->CreateQuarks;                                                     # Quarks

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);

    for my $i(1..$N)                                                              # Load a set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 4+$i));
      my $q = $Q->quarkFromShortString($s);
      $q->outNL("New quark    $j: ");                                             # New quark, new number
     }
    PrintOutNL;

    for my $i(reverse 1..$N)                                                      # Reload a set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 4+$i));
      my $q = $Q->quarkFromShortString($s);
      $q->outNL("Old quark    $j: ");                                             # Old quark, old number
     }
    PrintOutNL;

    for my $i(1..$N)                                                              # Dump quarks
     {my $j = $i - 1;
       $s->clear;
      $Q->shortStringFromQuark(K(quark, $j), $s);
      PrintOutString "Quark string $j: ";
      PrintOutRegisterInHex xmm0;
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  New quark    0: 0000 0000 0000 0000
  New quark    1: 0000 0000 0000 0001
  New quark    2: 0000 0000 0000 0002
  New quark    3: 0000 0000 0000 0003
  New quark    4: 0000 0000 0000 0004

  Old quark    4: 0000 0000 0000 0004
  Old quark    3: 0000 0000 0000 0003
  Old quark    2: 0000 0000 0000 0002
  Old quark    1: 0000 0000 0000 0001
  Old quark    0: 0000 0000 0000 0000

  Quark string 0:   xmm0: 0000 0000 0000 0000   0000 0504 0302 0105
  Quark string 1:   xmm0: 0000 0000 0000 0000   0006 0504 0302 0106
  Quark string 2:   xmm0: 0000 0000 0000 0000   0706 0504 0302 0107
  Quark string 3:   xmm0: 0000 0000 0000 0008   0706 0504 0302 0108
  Quark string 4:   xmm0: 0000 0000 0000 0908   0706 0504 0302 0109
  END

    my $N  = 5;
    my $a  = CreateArena;                                                         # Arena containing quarks
    my $Q1 = $a->CreateQuarks;                                                    # Quarks
    my $Q2 = $a->CreateQuarks;                                                    # Quarks

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);

    for my $i(1..$N)                                                              # Load first set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 4+$i));
      my $q = $Q1->quarkFromShortString($s);
      $q->outNL("Q1 $j: ");
     }
    PrintOutNL;

    for my $i(1..$N)                                                              # Load second set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 5+$i));
      my $q = $Q2->quarkFromShortString($s);
      $q->outNL("Q2 $j: ");
     }
    PrintOutNL;

    $Q1->quarkToQuark(K(three,3), $Q1)->outNL;
    $Q1->quarkToQuark(K(three,3), $Q2)->outNL;
    $Q2->quarkToQuark(K(two,  2), $Q1)->outNL;
    $Q2->quarkToQuark(K(two,  2), $Q2)->outNL;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Q1 0: 0000 0000 0000 0000
  Q1 1: 0000 0000 0000 0001
  Q1 2: 0000 0000 0000 0002
  Q1 3: 0000 0000 0000 0003
  Q1 4: 0000 0000 0000 0004

  Q2 0: 0000 0000 0000 0000
  Q2 1: 0000 0000 0000 0001
  Q2 2: 0000 0000 0000 0002
  Q2 3: 0000 0000 0000 0003
  Q2 4: 0000 0000 0000 0004

  found: 0000 0000 0000 0003
  found: 0000 0000 0000 0002
  found: 0000 0000 0000 0003
  found: 0000 0000 0000 0002
  END

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);
    $s->loadDwordBytes(0, K(address, $d), K(size, 9));
    PrintOutRegisterInHex xmm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    xmm0: 0000 0000 0000 211D   1915 110D 0905 0109
  END

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);
    $s->loadDwordWords(0, K(address, $d), K(size, 9));
    PrintOutRegisterInHex ymm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    ymm0: 0000 0000 0000 0000   0000 0000 0022 211E   1D1A 1916 1512 110E   0D0A 0906 0502 0112
  END

Nasm::X86::Quarks::reload($q, %options)

Reload the description of a set of quarks.

     Parameter  Description
  1  $q         Quarks
  2  %options   {arena=>arena to use; tree => first tree block; array => first array block}

Nasm::X86::Quarks::put($q, $string)

Create a quark from a string.

     Parameter  Description
  1  $q         Quarks
  2  $string    String

Example:

    my $s = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "SSSS";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [qw(p)], name => 'ssss';

    my $t = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "TTTT";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [], name => 'tttt', with => $s;

    my $A = CreateArena;

    my $Q  = $A->CreateQuarks;
             $Q->put('aaaa');
             $Q->put('bbbb');
    my $Qs = $Q->put('ssss');
    my $Qt = $Q->put('tttt');

    my $q  = $A->CreateQuarks;
    my $qs = $q->putSub('ssss', $s);
    my $qt = $q->putSub('tttt', $t);

    PrintOutStringNL "Quarks";   $Q->dump;
    PrintOutStringNL "Subs";     $q->dump;

    $q->subFromQuarkViaQuarks($Q, $Qs)->outNL;
    $q->subFromQuarkViaQuarks($Q, $Qt)->outNL;
    $q->subFromQuarkNumber($qs)->outNL;
    $q->subFromQuarkNumber($qt)->outNL;

    my $cs = $q->subFromQuarkNumber($qs);  $s->via($cs, p => 1);
    my $ct = $q->subFromQuarkNumber($qt);  $s->via($ct, p => 2);
    $q->callSubFromQuarkNumber   (    $s, $qs, p => 0x11);
    $q->callSubFromQuarkNumber   (    $s, $qt, p => 0x22);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qs, p => 0x111);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qt, p => 0x222);

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->subFromShortString($s)->outNL;
     }

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->callSubFromShortString($t, $s, p => 3);
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Quarks
  Quark : 0000 0000 0000 0000 => 0000 0000 0000 00D8 == 0000 00D8 0000 00D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0061 6161 6104
  Quark : 0000 0000 0000 0001 => 0000 0000 0000 0198 == 0000 0198 0000 0198   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0062 6262 6204
  Quark : 0000 0000 0000 0002 => 0000 0000 0000 01D8 == 0000 01D8 0000 01D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0073 7373 7304
  Quark : 0000 0000 0000 0003 => 0000 0000 0000 0218 == 0000 0218 0000 0218   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0074 7474 7404
  Subs
  Quark : 0000 0000 0000 0000 => 0000 0000 0040 1009
  Quark : 0000 0000 0000 0001 => 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  SSSS   r15: 0000 0000 0000 0001
  TTTT   r15: 0000 0000 0000 0002
  SSSS   r15: 0000 0000 0000 0011
  TTTT   r15: 0000 0000 0000 0022
  SSSS   r15: 0000 0000 0000 0111
  TTTT   r15: 0000 0000 0000 0222
  sub: 0000 0000 0040 1009
  SSSS   r15: 0000 0000 0000 0003
  END

    my $a = V('a', 1);
    my $b = $a->clone();

    $_->outNL for $a, $b;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  a: 0000 0000 0000 0001
  a: 0000 0000 0000 0001
  END

Nasm::X86::Quarks::quarkFromShortString($q, $string)

Create a quark from a short string.

     Parameter  Description
  1  $q         Quarks
  2  $string    Short string

Example:

    my $N = 5;
    my $a = CreateArena;                                                          # Arena containing quarks
    my $Q = $a->CreateQuarks;                                                     # Quarks

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);

    for my $i(1..$N)                                                              # Load a set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 4+$i));
      my $q = $Q->quarkFromShortString($s);
      $q->outNL("New quark    $j: ");                                             # New quark, new number
     }
    PrintOutNL;

    for my $i(reverse 1..$N)                                                      # Reload a set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 4+$i));
      my $q = $Q->quarkFromShortString($s);
      $q->outNL("Old quark    $j: ");                                             # Old quark, old number
     }
    PrintOutNL;

    for my $i(1..$N)                                                              # Dump quarks
     {my $j = $i - 1;
       $s->clear;
      $Q->shortStringFromQuark(K(quark, $j), $s);
      PrintOutString "Quark string $j: ";
      PrintOutRegisterInHex xmm0;
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  New quark    0: 0000 0000 0000 0000
  New quark    1: 0000 0000 0000 0001
  New quark    2: 0000 0000 0000 0002
  New quark    3: 0000 0000 0000 0003
  New quark    4: 0000 0000 0000 0004

  Old quark    4: 0000 0000 0000 0004
  Old quark    3: 0000 0000 0000 0003
  Old quark    2: 0000 0000 0000 0002
  Old quark    1: 0000 0000 0000 0001
  Old quark    0: 0000 0000 0000 0000

  Quark string 0:   xmm0: 0000 0000 0000 0000   0000 0504 0302 0105
  Quark string 1:   xmm0: 0000 0000 0000 0000   0006 0504 0302 0106
  Quark string 2:   xmm0: 0000 0000 0000 0000   0706 0504 0302 0107
  Quark string 3:   xmm0: 0000 0000 0000 0008   0706 0504 0302 0108
  Quark string 4:   xmm0: 0000 0000 0000 0908   0706 0504 0302 0109
  END

    my $N  = 5;
    my $a  = CreateArena;                                                         # Arena containing quarks
    my $Q1 = $a->CreateQuarks;                                                    # Quarks
    my $Q2 = $a->CreateQuarks;                                                    # Quarks

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);

    for my $i(1..$N)                                                              # Load first set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 4+$i));
      my $q = $Q1->quarkFromShortString($s);
      $q->outNL("Q1 $j: ");
     }
    PrintOutNL;

    for my $i(1..$N)                                                              # Load second set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 5+$i));
      my $q = $Q2->quarkFromShortString($s);
      $q->outNL("Q2 $j: ");
     }
    PrintOutNL;

    $Q1->quarkToQuark(K(three,3), $Q1)->outNL;
    $Q1->quarkToQuark(K(three,3), $Q2)->outNL;
    $Q2->quarkToQuark(K(two,  2), $Q1)->outNL;
    $Q2->quarkToQuark(K(two,  2), $Q2)->outNL;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Q1 0: 0000 0000 0000 0000
  Q1 1: 0000 0000 0000 0001
  Q1 2: 0000 0000 0000 0002
  Q1 3: 0000 0000 0000 0003
  Q1 4: 0000 0000 0000 0004

  Q2 0: 0000 0000 0000 0000
  Q2 1: 0000 0000 0000 0001
  Q2 2: 0000 0000 0000 0002
  Q2 3: 0000 0000 0000 0003
  Q2 4: 0000 0000 0000 0004

  found: 0000 0000 0000 0003
  found: 0000 0000 0000 0002
  found: 0000 0000 0000 0003
  found: 0000 0000 0000 0002
  END

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);
    $s->loadDwordBytes(0, K(address, $d), K(size, 9));
    PrintOutRegisterInHex xmm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    xmm0: 0000 0000 0000 211D   1915 110D 0905 0109
  END

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);
    $s->loadDwordWords(0, K(address, $d), K(size, 9));
    PrintOutRegisterInHex ymm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    ymm0: 0000 0000 0000 0000   0000 0000 0022 211E   1D1A 1916 1512 110E   0D0A 0906 0502 0112
  END

Nasm::X86::Quarks::locateQuarkFromShortString($q, $string)

Locate (if possible) but do not create a quark from a short string. A quark of -1 is returned if there is no matching quark otherwise the number of the matching quark is returned in a variable.

     Parameter  Description
  1  $q         Quarks
  2  $string    Short string

Nasm::X86::Quarks::shortStringFromQuark($q, $number, $string)

Load a short string from the quark with the specified number. Returns a variable that is set to one if the quark was found else zero.

     Parameter  Description
  1  $q         Quarks
  2  $number    Variable quark number
  3  $string    Short string to load

Example:

    my $N = 5;
    my $a = CreateArena;                                                          # Arena containing quarks
    my $Q = $a->CreateQuarks;                                                     # Quarks

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);

    for my $i(1..$N)                                                              # Load a set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 4+$i));
      my $q = $Q->quarkFromShortString($s);
      $q->outNL("New quark    $j: ");                                             # New quark, new number
     }
    PrintOutNL;

    for my $i(reverse 1..$N)                                                      # Reload a set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 4+$i));
      my $q = $Q->quarkFromShortString($s);
      $q->outNL("Old quark    $j: ");                                             # Old quark, old number
     }
    PrintOutNL;

    for my $i(1..$N)                                                              # Dump quarks
     {my $j = $i - 1;
       $s->clear;
      $Q->shortStringFromQuark(K(quark, $j), $s);
      PrintOutString "Quark string $j: ";
      PrintOutRegisterInHex xmm0;
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  New quark    0: 0000 0000 0000 0000
  New quark    1: 0000 0000 0000 0001
  New quark    2: 0000 0000 0000 0002
  New quark    3: 0000 0000 0000 0003
  New quark    4: 0000 0000 0000 0004

  Old quark    4: 0000 0000 0000 0004
  Old quark    3: 0000 0000 0000 0003
  Old quark    2: 0000 0000 0000 0002
  Old quark    1: 0000 0000 0000 0001
  Old quark    0: 0000 0000 0000 0000

  Quark string 0:   xmm0: 0000 0000 0000 0000   0000 0504 0302 0105
  Quark string 1:   xmm0: 0000 0000 0000 0000   0006 0504 0302 0106
  Quark string 2:   xmm0: 0000 0000 0000 0000   0706 0504 0302 0107
  Quark string 3:   xmm0: 0000 0000 0000 0008   0706 0504 0302 0108
  Quark string 4:   xmm0: 0000 0000 0000 0908   0706 0504 0302 0109
  END

    my $N  = 5;
    my $a  = CreateArena;                                                         # Arena containing quarks
    my $Q1 = $a->CreateQuarks;                                                    # Quarks
    my $Q2 = $a->CreateQuarks;                                                    # Quarks

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);

    for my $i(1..$N)                                                              # Load first set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 4+$i));
      my $q = $Q1->quarkFromShortString($s);
      $q->outNL("Q1 $j: ");
     }
    PrintOutNL;

    for my $i(1..$N)                                                              # Load second set of quarks
     {my $j = $i - 1;
      $s->load(K(address, $d), K(size, 5+$i));
      my $q = $Q2->quarkFromShortString($s);
      $q->outNL("Q2 $j: ");
     }
    PrintOutNL;

    $Q1->quarkToQuark(K(three,3), $Q1)->outNL;
    $Q1->quarkToQuark(K(three,3), $Q2)->outNL;
    $Q2->quarkToQuark(K(two,  2), $Q1)->outNL;
    $Q2->quarkToQuark(K(two,  2), $Q2)->outNL;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Q1 0: 0000 0000 0000 0000
  Q1 1: 0000 0000 0000 0001
  Q1 2: 0000 0000 0000 0002
  Q1 3: 0000 0000 0000 0003
  Q1 4: 0000 0000 0000 0004

  Q2 0: 0000 0000 0000 0000
  Q2 1: 0000 0000 0000 0001
  Q2 2: 0000 0000 0000 0002
  Q2 3: 0000 0000 0000 0003
  Q2 4: 0000 0000 0000 0004

  found: 0000 0000 0000 0003
  found: 0000 0000 0000 0002
  found: 0000 0000 0000 0003
  found: 0000 0000 0000 0002
  END

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);
    $s->loadDwordBytes(0, K(address, $d), K(size, 9));
    PrintOutRegisterInHex xmm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    xmm0: 0000 0000 0000 211D   1915 110D 0905 0109
  END

    my $s = CreateShortString(0);                                                 # Short string used to load and unload quarks
    my $d = Rb(1..63);
    $s->loadDwordWords(0, K(address, $d), K(size, 9));
    PrintOutRegisterInHex ymm0;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
    ymm0: 0000 0000 0000 0000   0000 0000 0022 211E   1D1A 1916 1512 110E   0D0A 0906 0502 0112
  END

Nasm::X86::Quarks::quarkToQuark($Q, $number, $q)

Given a variable quark number in one set of quarks find the corresponding quark in another set of quarks and return it in a variable. No new quarks are created in this process. If the quark cannot be found in the first set we return -1, if it cannot be found in the second set we return -2 else the number of the matching quark.

     Parameter  Description
  1  $Q         First set of quarks
  2  $number    Variable quark number in first set
  3  $q         Second set of quarks

Nasm::X86::Quarks::quarkFromSub($q, $sub, $String)

Create a quark from a subroutine definition.

     Parameter  Description
  1  $q         Quarks
  2  $sub       Subroutine definition
  3  $String    Optional overriding name as a short string

Example:

    my $s1 = Subroutine
     {PrintOutStringNL "11111";
     } [], name => 'test1';

    my $s2 = Subroutine
     {PrintOutStringNL "22222";
     } [], name => 'test2';

    my $a  = CreateArena;
    my $q  = $a->CreateQuarks;
    my $n1 = $q->quarkFromSub($s1);

    my $s  = CreateShortString(0);
    $s->loadConstantString("assign");
    my $n2 = $q->quarkFromSub($s2, $s);

    my $S1 = $q->subFromQuark($n1);
    $s1->V->outNL;
    $S1   ->outNL(" sub: ");

    my $S2 = $q->subFromQuark($n2);
    $s2->V->outNL;
    $S2   ->outNL(" sub: ");

    $q->call($n1);
    $q->call($n2);

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  call: 0000 0000 0040 1009
   sub: 0000 0000 0040 1009
  call: 0000 0000 0040 10A3
   sub: 0000 0000 0040 10A3
  11111
  22222
  END

Nasm::X86::Quarks::subFromQuark($q, $number)

Get the offset of a subroutine as a variable from a set of quarks.

     Parameter  Description
  1  $q         Quarks
  2  $number    Variable subroutine number

Example:

    my $s1 = Subroutine
     {PrintOutStringNL "11111";
     } [], name => 'test1';

    my $s2 = Subroutine
     {PrintOutStringNL "22222";
     } [], name => 'test2';

    my $a  = CreateArena;
    my $q  = $a->CreateQuarks;
    my $n1 = $q->quarkFromSub($s1);

    my $s  = CreateShortString(0);
    $s->loadConstantString("assign");
    my $n2 = $q->quarkFromSub($s2, $s);

    my $S1 = $q->subFromQuark($n1);
    $s1->V->outNL;
    $S1   ->outNL(" sub: ");

    my $S2 = $q->subFromQuark($n2);
    $s2->V->outNL;
    $S2   ->outNL(" sub: ");

    $q->call($n1);
    $q->call($n2);

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  call: 0000 0000 0040 1009
   sub: 0000 0000 0040 1009
  call: 0000 0000 0040 10A3
   sub: 0000 0000 0040 10A3
  11111
  22222
  END

Nasm::X86::Quarks::call($q, $number)

Call a subroutine via its quark number. Return one in a variable if the subroutine was found and called else zero.

     Parameter  Description
  1  $q         Quarks
  2  $number    Variable subroutine number

Nasm::X86::Quarks::dump($q)

Dump a set of quarks

     Parameter  Description
  1  $q         Quarks

Example:

    my $s = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "SSSS";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [qw(p)], name => 'ssss';

    my $t = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "TTTT";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [], name => 'tttt', with => $s;

    my $A = CreateArena;

    my $Q  = $A->CreateQuarks;
             $Q->put('aaaa');
             $Q->put('bbbb');
    my $Qs = $Q->put('ssss');
    my $Qt = $Q->put('tttt');

    my $q  = $A->CreateQuarks;
    my $qs = $q->putSub('ssss', $s);
    my $qt = $q->putSub('tttt', $t);

    PrintOutStringNL "Quarks";   $Q->dump;
    PrintOutStringNL "Subs";     $q->dump;

    $q->subFromQuarkViaQuarks($Q, $Qs)->outNL;
    $q->subFromQuarkViaQuarks($Q, $Qt)->outNL;
    $q->subFromQuarkNumber($qs)->outNL;
    $q->subFromQuarkNumber($qt)->outNL;

    my $cs = $q->subFromQuarkNumber($qs);  $s->via($cs, p => 1);
    my $ct = $q->subFromQuarkNumber($qt);  $s->via($ct, p => 2);
    $q->callSubFromQuarkNumber   (    $s, $qs, p => 0x11);
    $q->callSubFromQuarkNumber   (    $s, $qt, p => 0x22);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qs, p => 0x111);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qt, p => 0x222);

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->subFromShortString($s)->outNL;
     }

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->callSubFromShortString($t, $s, p => 3);
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Quarks
  Quark : 0000 0000 0000 0000 => 0000 0000 0000 00D8 == 0000 00D8 0000 00D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0061 6161 6104
  Quark : 0000 0000 0000 0001 => 0000 0000 0000 0198 == 0000 0198 0000 0198   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0062 6262 6204
  Quark : 0000 0000 0000 0002 => 0000 0000 0000 01D8 == 0000 01D8 0000 01D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0073 7373 7304
  Quark : 0000 0000 0000 0003 => 0000 0000 0000 0218 == 0000 0218 0000 0218   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0074 7474 7404
  Subs
  Quark : 0000 0000 0000 0000 => 0000 0000 0040 1009
  Quark : 0000 0000 0000 0001 => 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  SSSS   r15: 0000 0000 0000 0001
  TTTT   r15: 0000 0000 0000 0002
  SSSS   r15: 0000 0000 0000 0011
  TTTT   r15: 0000 0000 0000 0022
  SSSS   r15: 0000 0000 0000 0111
  TTTT   r15: 0000 0000 0000 0222
  sub: 0000 0000 0040 1009
  SSSS   r15: 0000 0000 0000 0003
  END

    my $a = V('a', 1);
    my $b = $a->clone();

    $_->outNL for $a, $b;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  a: 0000 0000 0000 0001
  a: 0000 0000 0000 0001
  END

Nasm::X86::Quarks::putSub($q, $string, $sub)

Put a new subroutine definition into the sub quarks.

     Parameter  Description
  1  $q         Subquarks
  2  $string    String containing operator type and method name
  3  $sub       Variable offset to subroutine

Example:

    my $s = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "SSSS";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [qw(p)], name => 'ssss';

    my $t = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "TTTT";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [], name => 'tttt', with => $s;

    my $A = CreateArena;

    my $Q  = $A->CreateQuarks;
             $Q->put('aaaa');
             $Q->put('bbbb');
    my $Qs = $Q->put('ssss');
    my $Qt = $Q->put('tttt');

    my $q  = $A->CreateQuarks;
    my $qs = $q->putSub('ssss', $s);
    my $qt = $q->putSub('tttt', $t);

    PrintOutStringNL "Quarks";   $Q->dump;
    PrintOutStringNL "Subs";     $q->dump;

    $q->subFromQuarkViaQuarks($Q, $Qs)->outNL;
    $q->subFromQuarkViaQuarks($Q, $Qt)->outNL;
    $q->subFromQuarkNumber($qs)->outNL;
    $q->subFromQuarkNumber($qt)->outNL;

    my $cs = $q->subFromQuarkNumber($qs);  $s->via($cs, p => 1);
    my $ct = $q->subFromQuarkNumber($qt);  $s->via($ct, p => 2);
    $q->callSubFromQuarkNumber   (    $s, $qs, p => 0x11);
    $q->callSubFromQuarkNumber   (    $s, $qt, p => 0x22);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qs, p => 0x111);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qt, p => 0x222);

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->subFromShortString($s)->outNL;
     }

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->callSubFromShortString($t, $s, p => 3);
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Quarks
  Quark : 0000 0000 0000 0000 => 0000 0000 0000 00D8 == 0000 00D8 0000 00D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0061 6161 6104
  Quark : 0000 0000 0000 0001 => 0000 0000 0000 0198 == 0000 0198 0000 0198   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0062 6262 6204
  Quark : 0000 0000 0000 0002 => 0000 0000 0000 01D8 == 0000 01D8 0000 01D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0073 7373 7304
  Quark : 0000 0000 0000 0003 => 0000 0000 0000 0218 == 0000 0218 0000 0218   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0074 7474 7404
  Subs
  Quark : 0000 0000 0000 0000 => 0000 0000 0040 1009
  Quark : 0000 0000 0000 0001 => 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  SSSS   r15: 0000 0000 0000 0001
  TTTT   r15: 0000 0000 0000 0002
  SSSS   r15: 0000 0000 0000 0011
  TTTT   r15: 0000 0000 0000 0022
  SSSS   r15: 0000 0000 0000 0111
  TTTT   r15: 0000 0000 0000 0222
  sub: 0000 0000 0040 1009
  SSSS   r15: 0000 0000 0000 0003
  END

    my $a = V('a', 1);
    my $b = $a->clone();

    $_->outNL for $a, $b;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  a: 0000 0000 0000 0001
  a: 0000 0000 0000 0001
  END

Nasm::X86::Quarks::subFromQuarkViaQuarks($q, $lexicals, $number)

Given the quark number for a lexical item and the quark set of lexical items get the offset of the associated method.

     Parameter  Description
  1  $q         Sub quarks
  2  $lexicals  Lexical item quarks
  3  $number    Lexical item quark

Example:

    my $s = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "SSSS";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [qw(p)], name => 'ssss';

    my $t = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "TTTT";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [], name => 'tttt', with => $s;

    my $A = CreateArena;

    my $Q  = $A->CreateQuarks;
             $Q->put('aaaa');
             $Q->put('bbbb');
    my $Qs = $Q->put('ssss');
    my $Qt = $Q->put('tttt');

    my $q  = $A->CreateQuarks;
    my $qs = $q->putSub('ssss', $s);
    my $qt = $q->putSub('tttt', $t);

    PrintOutStringNL "Quarks";   $Q->dump;
    PrintOutStringNL "Subs";     $q->dump;

    $q->subFromQuarkViaQuarks($Q, $Qs)->outNL;
    $q->subFromQuarkViaQuarks($Q, $Qt)->outNL;
    $q->subFromQuarkNumber($qs)->outNL;
    $q->subFromQuarkNumber($qt)->outNL;

    my $cs = $q->subFromQuarkNumber($qs);  $s->via($cs, p => 1);
    my $ct = $q->subFromQuarkNumber($qt);  $s->via($ct, p => 2);
    $q->callSubFromQuarkNumber   (    $s, $qs, p => 0x11);
    $q->callSubFromQuarkNumber   (    $s, $qt, p => 0x22);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qs, p => 0x111);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qt, p => 0x222);

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->subFromShortString($s)->outNL;
     }

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->callSubFromShortString($t, $s, p => 3);
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Quarks
  Quark : 0000 0000 0000 0000 => 0000 0000 0000 00D8 == 0000 00D8 0000 00D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0061 6161 6104
  Quark : 0000 0000 0000 0001 => 0000 0000 0000 0198 == 0000 0198 0000 0198   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0062 6262 6204
  Quark : 0000 0000 0000 0002 => 0000 0000 0000 01D8 == 0000 01D8 0000 01D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0073 7373 7304
  Quark : 0000 0000 0000 0003 => 0000 0000 0000 0218 == 0000 0218 0000 0218   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0074 7474 7404
  Subs
  Quark : 0000 0000 0000 0000 => 0000 0000 0040 1009
  Quark : 0000 0000 0000 0001 => 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  SSSS   r15: 0000 0000 0000 0001
  TTTT   r15: 0000 0000 0000 0002
  SSSS   r15: 0000 0000 0000 0011
  TTTT   r15: 0000 0000 0000 0022
  SSSS   r15: 0000 0000 0000 0111
  TTTT   r15: 0000 0000 0000 0222
  sub: 0000 0000 0040 1009
  SSSS   r15: 0000 0000 0000 0003
  END

    my $a = V('a', 1);
    my $b = $a->clone();

    $_->outNL for $a, $b;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  a: 0000 0000 0000 0001
  a: 0000 0000 0000 0001
  END

Nasm::X86::Quarks::subFromShortString($q, $shortString)

Given a short string get the offset of the associated subroutine or zero if no such subroutine exists.

     Parameter     Description
  1  $q            Sub quarks
  2  $shortString  Short string

Example:

    my $s = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "SSSS";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [qw(p)], name => 'ssss';

    my $t = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "TTTT";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [], name => 'tttt', with => $s;

    my $A = CreateArena;

    my $Q  = $A->CreateQuarks;
             $Q->put('aaaa');
             $Q->put('bbbb');
    my $Qs = $Q->put('ssss');
    my $Qt = $Q->put('tttt');

    my $q  = $A->CreateQuarks;
    my $qs = $q->putSub('ssss', $s);
    my $qt = $q->putSub('tttt', $t);

    PrintOutStringNL "Quarks";   $Q->dump;
    PrintOutStringNL "Subs";     $q->dump;

    $q->subFromQuarkViaQuarks($Q, $Qs)->outNL;
    $q->subFromQuarkViaQuarks($Q, $Qt)->outNL;
    $q->subFromQuarkNumber($qs)->outNL;
    $q->subFromQuarkNumber($qt)->outNL;

    my $cs = $q->subFromQuarkNumber($qs);  $s->via($cs, p => 1);
    my $ct = $q->subFromQuarkNumber($qt);  $s->via($ct, p => 2);
    $q->callSubFromQuarkNumber   (    $s, $qs, p => 0x11);
    $q->callSubFromQuarkNumber   (    $s, $qt, p => 0x22);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qs, p => 0x111);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qt, p => 0x222);

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->subFromShortString($s)->outNL;
     }

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->callSubFromShortString($t, $s, p => 3);
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Quarks
  Quark : 0000 0000 0000 0000 => 0000 0000 0000 00D8 == 0000 00D8 0000 00D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0061 6161 6104
  Quark : 0000 0000 0000 0001 => 0000 0000 0000 0198 == 0000 0198 0000 0198   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0062 6262 6204
  Quark : 0000 0000 0000 0002 => 0000 0000 0000 01D8 == 0000 01D8 0000 01D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0073 7373 7304
  Quark : 0000 0000 0000 0003 => 0000 0000 0000 0218 == 0000 0218 0000 0218   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0074 7474 7404
  Subs
  Quark : 0000 0000 0000 0000 => 0000 0000 0040 1009
  Quark : 0000 0000 0000 0001 => 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  SSSS   r15: 0000 0000 0000 0001
  TTTT   r15: 0000 0000 0000 0002
  SSSS   r15: 0000 0000 0000 0011
  TTTT   r15: 0000 0000 0000 0022
  SSSS   r15: 0000 0000 0000 0111
  TTTT   r15: 0000 0000 0000 0222
  sub: 0000 0000 0040 1009
  SSSS   r15: 0000 0000 0000 0003
  END

    my $a = V('a', 1);
    my $b = $a->clone();

    $_->outNL for $a, $b;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  a: 0000 0000 0000 0001
  a: 0000 0000 0000 0001
  END

Nasm::X86::Quarks::callSubFromShortString($q, $sub, $shortString, @parameters)

Given a short string call the associated subroutine if it exists.

     Parameter     Description
  1  $q            Sub quarks
  2  $sub          Subroutine definition
  3  $shortString  Short string
  4  @parameters   Parameters

Example:

    my $s = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "SSSS";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [qw(p)], name => 'ssss';

    my $t = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "TTTT";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [], name => 'tttt', with => $s;

    my $A = CreateArena;

    my $Q  = $A->CreateQuarks;
             $Q->put('aaaa');
             $Q->put('bbbb');
    my $Qs = $Q->put('ssss');
    my $Qt = $Q->put('tttt');

    my $q  = $A->CreateQuarks;
    my $qs = $q->putSub('ssss', $s);
    my $qt = $q->putSub('tttt', $t);

    PrintOutStringNL "Quarks";   $Q->dump;
    PrintOutStringNL "Subs";     $q->dump;

    $q->subFromQuarkViaQuarks($Q, $Qs)->outNL;
    $q->subFromQuarkViaQuarks($Q, $Qt)->outNL;
    $q->subFromQuarkNumber($qs)->outNL;
    $q->subFromQuarkNumber($qt)->outNL;

    my $cs = $q->subFromQuarkNumber($qs);  $s->via($cs, p => 1);
    my $ct = $q->subFromQuarkNumber($qt);  $s->via($ct, p => 2);
    $q->callSubFromQuarkNumber   (    $s, $qs, p => 0x11);
    $q->callSubFromQuarkNumber   (    $s, $qt, p => 0x22);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qs, p => 0x111);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qt, p => 0x222);

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->subFromShortString($s)->outNL;
     }

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->callSubFromShortString($t, $s, p => 3);
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Quarks
  Quark : 0000 0000 0000 0000 => 0000 0000 0000 00D8 == 0000 00D8 0000 00D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0061 6161 6104
  Quark : 0000 0000 0000 0001 => 0000 0000 0000 0198 == 0000 0198 0000 0198   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0062 6262 6204
  Quark : 0000 0000 0000 0002 => 0000 0000 0000 01D8 == 0000 01D8 0000 01D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0073 7373 7304
  Quark : 0000 0000 0000 0003 => 0000 0000 0000 0218 == 0000 0218 0000 0218   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0074 7474 7404
  Subs
  Quark : 0000 0000 0000 0000 => 0000 0000 0040 1009
  Quark : 0000 0000 0000 0001 => 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  SSSS   r15: 0000 0000 0000 0001
  TTTT   r15: 0000 0000 0000 0002
  SSSS   r15: 0000 0000 0000 0011
  TTTT   r15: 0000 0000 0000 0022
  SSSS   r15: 0000 0000 0000 0111
  TTTT   r15: 0000 0000 0000 0222
  sub: 0000 0000 0040 1009
  SSSS   r15: 0000 0000 0000 0003
  END

    my $a = V('a', 1);
    my $b = $a->clone();

    $_->outNL for $a, $b;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  a: 0000 0000 0000 0001
  a: 0000 0000 0000 0001
  END

Nasm::X86::Quarks::callSubFromQuarkViaQuarks($q, $lexicals, $sub, $number, @parameters)

Given the quark number for a lexical item and the quark set of lexical items call the associated method.

     Parameter    Description
  1  $q           Sub quarks
  2  $lexicals    Lexical item quarks
  3  $sub         Subroutine definition
  4  $number      Lexical item quark
  5  @parameters  Parameters

Nasm::X86::Quarks::subFromQuarkNumber($q, $number)

Get the sub associated with a sub quark by its number.

     Parameter  Description
  1  $q         Sub quarks
  2  $number    Lexical item quark

Example:

    my $s = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "SSSS";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [qw(p)], name => 'ssss';

    my $t = Subroutine
     {my ($p, $s) = @_;
      PrintOutString "TTTT";
      $$p{p}->setReg(r15);
      PrintOutRegisterInHex r15;
     } [], name => 'tttt', with => $s;

    my $A = CreateArena;

    my $Q  = $A->CreateQuarks;
             $Q->put('aaaa');
             $Q->put('bbbb');
    my $Qs = $Q->put('ssss');
    my $Qt = $Q->put('tttt');

    my $q  = $A->CreateQuarks;
    my $qs = $q->putSub('ssss', $s);
    my $qt = $q->putSub('tttt', $t);

    PrintOutStringNL "Quarks";   $Q->dump;
    PrintOutStringNL "Subs";     $q->dump;

    $q->subFromQuarkViaQuarks($Q, $Qs)->outNL;
    $q->subFromQuarkViaQuarks($Q, $Qt)->outNL;
    $q->subFromQuarkNumber($qs)->outNL;
    $q->subFromQuarkNumber($qt)->outNL;

    my $cs = $q->subFromQuarkNumber($qs);  $s->via($cs, p => 1);
    my $ct = $q->subFromQuarkNumber($qt);  $s->via($ct, p => 2);
    $q->callSubFromQuarkNumber   (    $s, $qs, p => 0x11);
    $q->callSubFromQuarkNumber   (    $s, $qt, p => 0x22);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qs, p => 0x111);
    $q->callSubFromQuarkViaQuarks($Q, $s, $Qt, p => 0x222);

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->subFromShortString($s)->outNL;
     }

    if (1)
     {my $s = CreateShortString(0);
         $s->loadConstantString("ssss");
      $q->callSubFromShortString($t, $s, p => 3);
     }

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  Quarks
  Quark : 0000 0000 0000 0000 => 0000 0000 0000 00D8 == 0000 00D8 0000 00D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0061 6161 6104
  Quark : 0000 0000 0000 0001 => 0000 0000 0000 0198 == 0000 0198 0000 0198   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0062 6262 6204
  Quark : 0000 0000 0000 0002 => 0000 0000 0000 01D8 == 0000 01D8 0000 01D8   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0073 7373 7304
  Quark : 0000 0000 0000 0003 => 0000 0000 0000 0218 == 0000 0218 0000 0218   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0074 7474 7404
  Subs
  Quark : 0000 0000 0000 0000 => 0000 0000 0040 1009
  Quark : 0000 0000 0000 0001 => 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  sub: 0000 0000 0040 1009
  sub: 0000 0000 0040 12B8
  SSSS   r15: 0000 0000 0000 0001
  TTTT   r15: 0000 0000 0000 0002
  SSSS   r15: 0000 0000 0000 0011
  TTTT   r15: 0000 0000 0000 0022
  SSSS   r15: 0000 0000 0000 0111
  TTTT   r15: 0000 0000 0000 0222
  sub: 0000 0000 0040 1009
  SSSS   r15: 0000 0000 0000 0003
  END

    my $a = V('a', 1);
    my $b = $a->clone();

    $_->outNL for $a, $b;

    ok Assemble(debug => 0, trace => 0, eq => <<END);
  a: 0000 0000 0000 0001
  a: 0000 0000 0000 0001
  END

Nasm::X86::Quarks::callSubFromQuarkNumber($q, $sub, $number, @parameters)

Call the sub associated with a quark number.

     Parameter    Description
  1  $q           Sub quarks
  2  $sub         Subroutine definition
  3  $number      Lexical item quark
  4  @parameters  Parameters to called subroutine

Assemble

Assemble generated code

CallC($sub, @parameters)

Call a C subroutine.

     Parameter    Description
  1  $sub         Name of the sub to call
  2  @parameters  Parameters

Example:

    my $format = Rs "Hello %s
";
    my $data   = Rs "World";

    Extern qw(printf exit malloc strcpy); Link 'c';


    CallC 'malloc', length($format)+1;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov r15, rax;

    CallC 'strcpy', r15, $format;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    CallC 'printf', r15, $data;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    CallC 'exit', 0;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble eq => <<END;
  Hello World
  END

Extern(@externalReferences)

Name external references.

     Parameter            Description
  1  @externalReferences  External references

Example:

    my $format = Rs "Hello %s
";
    my $data   = Rs "World";


    Extern qw(printf exit malloc strcpy); Link 'c';  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    CallC 'malloc', length($format)+1;
    Mov r15, rax;
    CallC 'strcpy', r15, $format;
    CallC 'printf', r15, $data;
    CallC 'exit', 0;

    ok Assemble eq => <<END;
  Hello World
  END

Link(@libraries)

Libraries to link with.

     Parameter   Description
  1  @libraries  External references

Example:

    my $format = Rs "Hello %s
";
    my $data   = Rs "World";


    Extern qw(printf exit malloc strcpy); Link 'c';  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    CallC 'malloc', length($format)+1;
    Mov r15, rax;
    CallC 'strcpy', r15, $format;
    CallC 'printf', r15, $data;
    CallC 'exit', 0;

    ok Assemble eq => <<END;
  Hello World
  END

Start()

Initialize the assembler.

Exit($c)

Exit with the specified return code or zero if no return code supplied. Assemble() automatically adds a call to Exit(0) if the last operation in the program is not a call to Exit.

     Parameter  Description
  1  $c         Return code

Example:

    Comment "Print a string from memory";
    my $s = "Hello World";
    Mov rax, Rs($s);
    Mov rdi, length $s;
    PrintOutMemory;

    Exit(0);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


    ok Assemble =~ m(Hello World);

Assemble(%options)

Assemble the generated code.

     Parameter  Description
  1  %options   Options

Example:

    PrintOutStringNL "Hello World";
    PrintOutStringNL "Hello
World";
    PrintErrStringNL "Hello World";


    ok Assemble(debug => 0, eq => <<END);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  Hello World
  Hello
  World
  END

CreateLibrary(%library)

Create a library

     Parameter  Description
  1  %library   Library definition

NasmX86::Library::load($library)

Load a library and return the addresses of its subroutines as variables

     Parameter  Description
  1  $library   Description of library to load

Hash Definitions

Nasm::X86 Definition

Quarks

Output fields

N

Initial allocation

arena

The arena containing the quarks

args

Hash of {argument name, argument variable}

bs

Arena containing tree

constant

Constant if true

count

Counter - number of node

data

Data at this position

end

End label for this subroutine

expr

Expression that initializes the variable

first

Variable addressing offset to first block of keys.

found

Variable indicating whether the last find was successful or not

global

Global if true

key

Key at this position

label

Address in memory

leftLength

Left split length

length

Maximum length in a block

lengthOffset

Offset of length in keys block. The length field is a word - see: "MultiWayTree.svg"

level

Lexical level

Location of links in bytes in zmm

loop

Offset of keys, data, node loop.

maxKeys

Maximum number of keys.

maximumLength

The maximum length of a short string if we want to store bytes

maximumLengthWords

The maximum length of a short string if we want to store words

more

Iteration not yet finished

name

Name of the variable

nameString

Name of the sub as a string constant in read only storage

next

Location of next offset in block in bytes

node

Current node within tree

numbersToStrings

Array mapping numbers to strings

options

Options used by the author of the subroutine

parameters

Parameters definitions supplied by the author of the subroutine which get mapped in to parameter variables.

pos

Current position within node

prev

Location of prev offset in block in bytes

reference

Reference to another variable

rightLength

Right split length

size

Size field offset

slots1

Number of slots in first block

slots2

Number of slots in second and subsequent blocks

splittingKey

POint at which to split a full block

start

Start label for this subroutine which includes the enter instruction used to create a new stack frame

stringsToNumbers

A tree mapping strings to numbers

subTree

Variable indicating whether the last find found a sub tree

tree

Tree we are iterating over

treeBits

Offset of tree bits in keys block. The tree bits field is a word, each bit of which tells us whether the corresponding data element is the offset (or not) to a sub tree of this tree .

treeBitsMask

Total of 14 tree bits

up

Offset of up in data block.

used

Used field offset

variables

Argument variables which show up as the first parameter in the called sub so that it knows what its parameters are.

vars

Number of variables in subroutine

width

Width of a key or data slot.

x

The associated xmm register

z

The full name of the zmm register

zmm

The number of the zmm register containing the string

zmmBlock

Size of a zmm block - 64 bytes

Attributes

The following is a list of all the attributes in this package. A method coded with the same name in your package will over ride the method of the same name in this package and thus provide your value for the attribute in place of the default value supplied for this attribute by this package.

Replaceable Attribute List

Pi32 Pi64

Pi32

Pi as a 32 bit float.

Pi64

Pi as a 64 bit float.

Private Methods

Label({return "l".++$Labels unless @_;)

Create a unique label or reuse the one supplied.

     Parameter                         Description
  1  {return "l".++$Labels unless @_;  Generate a label

Dbwdq($s, @d)

Layout data.

     Parameter  Description
  1  $s         Element size
  2  @d         Data to be laid out

Rbwdq($s, @d)

Layout data.

     Parameter  Description
  1  $s         Element size
  2  @d         Data to be laid out

Nasm::X86::Sub::callTo($sub, $mode, $label, @parameters)

Call a sub passing it some parameters.

     Parameter    Description
  1  $sub         Subroutine descriptor
  2  $mode        Mode 0 - direct call or 1 - indirect call
  3  $label       Label of sub
  4  @parameters  Parameter variables

hexTranslateTable()

Create/address a hex translate table and return its label.

PrintOutRipInHex()

Print the instruction pointer in hex.

PrintOutRflagsInHex()

Print the flags register in hex.

PrintUtf32($channel, $size, $address)

Print the specified number of utf32 characters at the specified address to the specified channel.

     Parameter  Description
  1  $channel   Channel
  2  $size      Variable: number of characters to print
  3  $address   Variable: address of memory

Nasm::X86::Variable::dump($left, $channel, $newLine, $title1, $title2)

Dump the value of a variable to the specified channel adding an optional title and new line if requested.

     Parameter  Description
  1  $left      Left variable
  2  $channel   Channel
  3  $newLine   New line required
  4  $title1    Optional leading title
  5  $title2    Optional trailing title

Example:

    my $a = V(a, 3);  $a->outNL;
    my $b = K(b, 2);  $b->outNL;
    my $c = $a +  $b; $c->outNL;
    my $d = $c -  $a; $d->outNL;
    my $g = $a *  $b; $g->outNL;
    my $h = $g /  $b; $h->outNL;
    my $i = $a %  $b; $i->outNL;

    If ($a == 3,
    Then
     {PrintOutStringNL "a == 3"
     },
    Else
     {PrintOutStringNL "a != 3"
     });

    ++$a; $a->outNL;
    --$a; $a->outNL;

    ok Assemble(debug => 0, eq => <<END);
  a: 0000 0000 0000 0003
  b: 0000 0000 0000 0002
  (a add b): 0000 0000 0000 0005
  ((a add b) sub a): 0000 0000 0000 0002
  (a times b): 0000 0000 0000 0006
  ((a times b) / b): 0000 0000 0000 0003
  (a % b): 0000 0000 0000 0001
  a == 3
  a: 0000 0000 0000 0004
  a: 0000 0000 0000 0003
  END

PushRR(@r)

Push registers onto the stack without tracking.

     Parameter  Description
  1  @r         Register

PushR(@r)

Push registers onto the stack.

     Parameter  Description
  1  @r         Registers

Example:

    Mov rax, 0x11111111;
    Mov rbx, 0x22222222;

    PushR my @save = (rax, rbx);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rax, 0x33333333;
    PopR;
    PrintOutRegisterInHex rax;
    PrintOutRegisterInHex rbx;

    ok Assemble(debug => 0, eq => <<END);
     rax: 0000 0000 1111 1111
     rbx: 0000 0000 2222 2222
  END

PushRAssert($depth)

Check that the stack ash the expected depth.

     Parameter  Description
  1  $depth     Expected Depth

PopRR(@r)

Pop registers from the stack without tracking.

     Parameter  Description
  1  @r         Register

ClassifyRange($recordOffsetInRange, @parameters)

Implementation of ClassifyInRange and ClassifyWithinRange.

     Parameter             Description
  1  $recordOffsetInRange  Record offset in classification in high byte if 1 else in classification if 2
  2  @parameters           Parameters

Cstrlen()

Length of the C style string addressed by rax returning the length in r15.

Example:

    my $s = Rs("Hello World

Hello Skye"); Mov rax, $s;

    Cstrlen;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rdi, r15;
    PrintOutMemoryNL;

    ok Assemble(debug => 0, eq => <<END);
  Hello World

  Hello Skye
  END

Nasm::X86::Arena::chain($arena, $variable, @offsets)

Return a variable with the end point of a chain of double words in the arena starting at the specified variable.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $variable  Start variable
  3  @offsets   Offsets chain

Example:

    my $format = Rd(map{4*$_+24} 0..64);

    my $b = CreateArena;
    my $a = $b->allocBlock;
    Vmovdqu8 zmm31, "[$format]";
    $b->putZmmBlock($a, 31);
    my $r = $b->chain(V(start, 0x18), 4);       $r->outNL("chain1: ");
    my $s = $b->chain($r, 4);                   $s->outNL("chain2: ");
    my $t = $b->chain($s, 4);                   $t->outNL("chain3: ");
    my $A = $b->chain(V(start, 0x18), 4, 4, 4); $A->outNL("chain4: ");            # Get a long chain

    $b->putChain(V(start, 0x18), V(end, 0xff), 4, 4, 4);                          # Put at the end of a long chain

    $b->dump;

    my $sub = Subroutine
     {my ($p) = @_;                                                               # Parameters
      If ($$p{c} == -1,
        sub {PrintOutStringNL "C is minus one"},
        sub {PrintOutStringNL "C is NOT minus one"},
       );
      If ($$p{d} == -1,
        sub {PrintOutStringNL "D is minus one"},
        sub {PrintOutStringNL "D is NOT minus one"},
       );

      $$p{c}->outNL;

      $$p{e} += 1;
      $$p{e}->outNL('E: ');

      $$p{f}->outNL('F1: ');
      $$p{f}++;
      $$p{f}->outNL('F2: ');
     } [qw(c d e f)], name=> 'aaa';

    my $c = K(c, -1);
    my $d = K(d, -1);
    my $e = V(e,  1);
    my $f = V(f,  2);

    $sub->call($c, $d, $e, $f);
    $f->outNL('F3: ');

    ok Assemble(debug => 0, eq => <<END);
  chain1: 0000 0000 0000 001C
  chain2: 0000 0000 0000 0020
  chain3: 0000 0000 0000 0024
  chain4: 0000 0000 0000 0024
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0058
  Block:  0000 0000 0000 0000  0010 0000 0000 00005800 0000 0000 00000000 0000 0000 00001800 0000 1C00 00002000 0000 FF00 00002800 0000 2C00 00003000 0000 3400 00003800 0000 3C00 0000
  Block:  0000 0000 0000 0001  4000 0000 4400 00004800 0000 4C00 00005000 0000 5400 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  C is minus one
  D is minus one
  c: FFFF FFFF FFFF FFFF
  E: 0000 0000 0000 0002
  F1: 0000 0000 0000 0002
  F2: 0000 0000 0000 0003
  F3: 0000 0000 0000 0003
  END

Nasm::X86::Arena::putChain($arena, $start, $value, @offsets)

Write the double word in the specified variable to the double word location at the the specified offset in the specified arena.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $start     Start variable
  3  $value     Value to put as a variable
  4  @offsets   Offsets chain

Nasm::X86::Arena::updateSpace($arena, $size)

Make sure that the variable addressed arena has enough space to accommodate content of the variable size.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $size      Variable size needed

Nasm::X86::Arena::checkYggdrasilCreated($arena)

Return a tree descriptor to the Yggdrasil world tree for an arena. If Yggdrasil has not been created the found variable will be zero else one.

     Parameter  Description
  1  $arena     Arena descriptor

Example:

    my $A = CreateArena;
    my $t = $A->checkYggdrasilCreated;
       $t->found->outNL;
    my $y = $A->establishYggdrasil;
    my $T = $A->checkYggdrasilCreated;
       $T->found->outNL;

    my $f = $A->firstFreeBlock; $f->outNL;

    $A->setFirstFreeBlock(V('first', 0xcc));

    my $F = $A->firstFreeBlock; $F->outNL;

    ok Assemble(debug => 0, eq => <<END);
  found: 0000 0000 0000 0000
  found: 0000 0000 0000 0001
  free: 0000 0000 0000 0000
  free: 0000 0000 0000 00CC
  END

Nasm::X86::Arena::establishYggdrasil($arena)

Return a tree descriptor to the Yggdrasil world tree for an arena creating the world tree Yggdrasil if it has not already been created.

     Parameter  Description
  1  $arena     Arena descriptor

Example:

    my $A = CreateArena;
    my $t = $A->checkYggdrasilCreated;
       $t->found->outNL;
    my $y = $A->establishYggdrasil;
    my $T = $A->checkYggdrasilCreated;
       $T->found->outNL;

    my $f = $A->firstFreeBlock; $f->outNL;

    $A->setFirstFreeBlock(V('first', 0xcc));

    my $F = $A->firstFreeBlock; $F->outNL;

    ok Assemble(debug => 0, eq => <<END);
  found: 0000 0000 0000 0000
  found: 0000 0000 0000 0001
  free: 0000 0000 0000 0000
  free: 0000 0000 0000 00CC
  END

Nasm::X86::Arena::firstFreeBlock($arena)

Create and load a variable with the first free block on the free block chain or zero if no such block in the given arena.

     Parameter  Description
  1  $arena     Arena descriptor

Example:

    my $A = CreateArena;
    my $t = $A->checkYggdrasilCreated;
       $t->found->outNL;
    my $y = $A->establishYggdrasil;
    my $T = $A->checkYggdrasilCreated;
       $T->found->outNL;

    my $f = $A->firstFreeBlock; $f->outNL;

    $A->setFirstFreeBlock(V('first', 0xcc));

    my $F = $A->firstFreeBlock; $F->outNL;

    ok Assemble(debug => 0, eq => <<END);
  found: 0000 0000 0000 0000
  found: 0000 0000 0000 0001
  free: 0000 0000 0000 0000
  free: 0000 0000 0000 00CC
  END

Nasm::X86::Arena::setFirstFreeBlock($arena, $offset)

Set the first free block field from a variable.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $offset    First free block offset as a variable

Example:

    my $A = CreateArena;
    my $t = $A->checkYggdrasilCreated;
       $t->found->outNL;
    my $y = $A->establishYggdrasil;
    my $T = $A->checkYggdrasilCreated;
       $T->found->outNL;

    my $f = $A->firstFreeBlock; $f->outNL;

    $A->setFirstFreeBlock(V('first', 0xcc));

    my $F = $A->firstFreeBlock; $F->outNL;

    ok Assemble(debug => 0, eq => <<END);
  found: 0000 0000 0000 0000
  found: 0000 0000 0000 0001
  free: 0000 0000 0000 0000
  free: 0000 0000 0000 00CC
  END

Nasm::X86::Arena::freeBlock($arena, $offset)

Free a block in an arena by placing it on the free chain.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $offset    Offset of 64  byte to be freed

Example:

    my $a = CreateArena; $a->dump;
    for (1..4)
     {my $b1 = $a->allocBlock; $a->dump;
      my $b2 = $a->allocBlock; $a->dump;
      $a->freeBlock($b2);      $a->dump;
      $a->freeBlock($b1);      $a->dump;
     }
    ok Assemble(debug => 0, eq => <<END);
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0018
  Block:  0000 0000 0000 0000  0010 0000 0000 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0058
  Block:  0000 0000 0000 0000  0010 0000 0000 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0098
  Block:  0000 0000 0000 0000  0010 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00005800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Arena
    Size: 0000 0000 0000 1000
    Used: 0000 0000 0000 0118
  Block:  0000 0000 0000 0000  0010 0000 0000 00001801 0000 0000 00009800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0001  0000 0000 0000 00000000 0000 0000 00000000 0000 5800 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0002  0000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  Block:  0000 0000 0000 0003  0000 0000 0000 00000000 0000 0000 00000100 0000 D800 00001800 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 00000000 0000 0000 0000
  END

Nasm::X86::Arena::getZmmBlock($arena, $block, $zmm, $work1, $work2)

Get the block with the specified offset in the specified string and return it in the numbered zmm.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $block     Offset of the block as a variable
  3  $zmm       Number of zmm register to contain block
  4  $work1     First optional work register
  5  $work2     Second optional work register

Nasm::X86::Arena::putZmmBlock($arena, $block, $zmm, $work1, $work2)

Write the numbered zmm to the block at the specified offset in the specified arena.

     Parameter  Description
  1  $arena     Arena descriptor
  2  $block     Offset of the block as a variable
  3  $zmm       Number of zmm register to contain block
  4  $work1     First optional work register
  5  $work2     Second optional work register

Nasm::X86::String::address($String)

Address of a string.

     Parameter  Description
  1  $String    String descriptor

Nasm::X86::String::allocBlock($String)

Allocate a block to hold a zmm register in the specified arena and return the offset of the block in a variable.

     Parameter  Description
  1  $String    String descriptor

Nasm::X86::String::getBlockLength($String, $zmm)

Get the block length of the numbered zmm and return it in a variable.

     Parameter  Description
  1  $String    String descriptor
  2  $zmm       Number of zmm register

Nasm::X86::String::setBlockLengthInZmm($String, $length, $zmm)

Set the block length of the numbered zmm to the specified length.

     Parameter  Description
  1  $String    String descriptor
  2  $length    Length as a variable
  3  $zmm       Number of zmm register

Nasm::X86::String::getZmmBlock($String, $block, $zmm)

Get the block with the specified offset in the specified string and return it in the numbered zmm.

     Parameter  Description
  1  $String    String descriptor
  2  $block     Offset of the block as a variable
  3  $zmm       Number of zmm register to contain block

Nasm::X86::String::putZmmBlock($String, $block, $zmm)

Write the numbered zmm to the block at the specified offset in the specified arena.

     Parameter  Description
  1  $String    String descriptor
  2  $block     Block in arena
  3  $zmm       Content variable

Nasm::X86::String::getNextAndPrevBlockOffsetFromZmm($String, $zmm)

Get the offsets of the next and previous blocks as variables from the specified zmm.

     Parameter  Description
  1  $String    String descriptor
  2  $zmm       Zmm containing block

Nasm::X86::String::putNextandPrevBlockOffsetIntoZmm($String, $zmm, $next, $prev)

Save next and prev offsets into a zmm representing a block.

     Parameter  Description
  1  $String    String descriptor
  2  $zmm       Zmm containing block
  3  $next      Next offset as a variable
  4  $prev      Prev offset as a variable

Nasm::X86::Array::address($Array)

Address of a string.

     Parameter  Description
  1  $Array     Array descriptor

Nasm::X86::Array::allocBlock($Array)

Allocate a block to hold a zmm register in the specified arena and return the offset of the block in a variable.

     Parameter  Description
  1  $Array     Array descriptor

Nasm::X86::Tree::allocKeysDataNode($t, $K, $D, $N)

Allocate a keys/data/node block and place it in the numbered zmm registers.

     Parameter  Description
  1  $t         Tree descriptor
  2  $K         Numbered zmm for keys
  3  $D         Numbered zmm for data
  4  $N         Numbered zmm for children

Nasm::X86::Tree::splitNode($t, $node, $key)

Split a non root node given its offset in an arena retaining the key being inserted in the node being split while putting the remainder to the left or right.

     Parameter  Description
  1  $t         Tree descriptor
  2  $node      Offset of node
  3  $key       Key

Nasm::X86::Tree::reParent($t, $PK, $PD, $PN)

Reparent the children of a node held in registers. The children are in the backing arena not registers.

     Parameter  Description
  1  $t         Tree descriptor
  2  $PK        Numbered zmm key node
  3  $PD        Numbered zmm data node
  4  $PN        Numbered zmm child node

Nasm::X86::Tree::transferTreeBitsFromParent($t, $parent, $left, $right)

Transfer tree bits when splitting a full node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $parent    Numbered parent zmm
  3  $left      Numbered left zmm
  4  $right     Numbered right zmm

Example:

    my $B = Rb(0..63);
    Vmovdqu8 zmm0, "[$B]";
    loadFromZmm r15, w, zmm, 14;

    my $b = CreateArena;
    my $t = $b->CreateTree;
    $t->getTreeBits(0, r14);

    PrintOutRegisterInHex zmm0, r15, r14;

    Mov r14, my $treeBits = 0xDCBA;
    $t->putTreeBits(1, r14);
    PrintOutRegisterInHex zmm1;

    $t->transferTreeBitsFromParent(1, 2, 3);
    PrintOutStringNL "Split:";
    PrintOutRegisterInHex zmm1, zmm2, zmm3;

    my $left  =  $treeBits & ((1<<$t->leftLength)  - 1);
    my $right = ($treeBits >>    ($t->leftLength   + 1)) & ((1<<$t->rightLength) - 1);

    my $l = sprintf("%02X", $left);
    my $r = sprintf("%02X", $right);

    ok Assemble(debug => 0, eq => <<END);
    zmm0: 3F3E 3D3C 3B3A 3938   3736 3534 3332 3130   2F2E 2D2C 2B2A 2928   2726 2524 2322 2120   1F1E 1D1C 1B1A 1918   1716 1514 1312 1110   0F0E 0D0C 0B0A 0908   0706 0504 0302 0100
     r15: 0000 0000 0000 0F0E
     r14: 0000 0000 0000 3B3A
    zmm1: 0000 0000 DCBA 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
  Split:
    zmm1: 0000 0000 0001 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    zmm2: 0000 0000 00$l 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    zmm3: 0000 0000 00$r 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
  END

Nasm::X86::Tree::transferTreeBitsFromLeftOrRight($t, $rnl, $point, $parent, $left, $right)

Transfer tree bits when splitting a full left or right node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $rnl       0 - left 1 - right
  3  $point     Register indicating point of left in parent
  4  $parent    Numbered parent zmm
  5  $left      Numbered left zmm
  6  $right     Numbered right zmm

Nasm::X86::Tree::transferTreeBitsFromLeft($t, $point, $parent, $left, $right)

Transfer tree bits when splitting a full left node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $point     Register indicating point of left in parent
  3  $parent    Numbered parent zmm
  4  $left      Numbered left zmm
  5  $right     Numbered right zmm

Example:

    my $b = CreateArena;
    my $t = $b->CreateTree;
    my $lR = "110110";
    my $lP = "1";
    my $lL = "1110111";

    my $p1 = "01010_110010";
    my $p2 = "1";

    my $epe = sprintf("%04X", eval "0b$p1$lP$p2");
    my $ele = sprintf("%04X", eval "0b$lL"      );
    my $ere = sprintf("%04X", eval "0b$lR"      );

    my @expected;
    for my $i(0..1)
     {Mov r15, eval "0b$lR$lP$lL"; $t->putTreeBits(1+$i, r15);
      Mov r15, eval "0b$p1$p2";    $t->putTreeBits(0,    r15);

      PrintOutRegisterInHex zmm 0, 1+$i;

      Mov r15, 0b10;
      $t->transferTreeBitsFromLeft (r15, 0, 1, 2) unless $i;
      $t->transferTreeBitsFromRight(r15, 0, 1, 2) if     $i;
      PrintOutRegisterInHex zmm 0..2;

      my $zzz = $i ? "zmm2" : "zmm1";
      push @expected, <<END;
    zmm0: 0000 0000 0565 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    $zzz: 0000 0000 36F7 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    zmm0: 0000 0000 $epe 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    zmm1: 0000 0000 $ele 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    zmm2: 0000 0000 $ere 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
  END
     }

    ok Assemble(debug => 0, eq => join "", @expected);

Nasm::X86::Tree::transferTreeBitsFromRight($t, $point, $parent, $left, $right)

Transfer tree bits when splitting a full right node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $point     Register indicating point of right in parent
  3  $parent    Numbered parent zmm
  4  $left      Numbered left zmm
  5  $right     Numbered right zmm

Example:

    my $b = CreateArena;
    my $t = $b->CreateTree;
    my $lR = "110110";
    my $lP = "1";
    my $lL = "1110111";

    my $p1 = "01010_110010";
    my $p2 = "1";

    my $epe = sprintf("%04X", eval "0b$p1$lP$p2");
    my $ele = sprintf("%04X", eval "0b$lL"      );
    my $ere = sprintf("%04X", eval "0b$lR"      );

    my @expected;
    for my $i(0..1)
     {Mov r15, eval "0b$lR$lP$lL"; $t->putTreeBits(1+$i, r15);
      Mov r15, eval "0b$p1$p2";    $t->putTreeBits(0,    r15);

      PrintOutRegisterInHex zmm 0, 1+$i;

      Mov r15, 0b10;
      $t->transferTreeBitsFromLeft (r15, 0, 1, 2) unless $i;
      $t->transferTreeBitsFromRight(r15, 0, 1, 2) if     $i;
      PrintOutRegisterInHex zmm 0..2;

      my $zzz = $i ? "zmm2" : "zmm1";
      push @expected, <<END;
    zmm0: 0000 0000 0565 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    $zzz: 0000 0000 36F7 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    zmm0: 0000 0000 $epe 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    zmm1: 0000 0000 $ele 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
    zmm2: 0000 0000 $ere 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000
  END
     }

    ok Assemble(debug => 0, eq => join "", @expected);

Nasm::X86::Tree::splitFullRoot($t)

Split a full root block held in 31..29 and place the left block in 28..26 and the right block in 25..23. The left and right blocks should have their loop offsets set so they can be inserted into the root.

     Parameter  Description
  1  $t         Tree descriptor

Nasm::X86::Tree::splitFullLeftOrRightNode($t, $right)

Split a full a full left node (held in 28..26) or a full right node (held in 25..23) whose parent is in 31..29.

     Parameter  Description
  1  $t         Tree descriptor
  2  $right     0 left or 1 right

Nasm::X86::Tree::splitFullLeftNode($t)

Split a full left node block held in 28..26 whose parent is in 31..29 and place the new right block in 25..23. The parent is assumed to be not full. The loop and length fields are assumed to be authoritative and hence are preserved.

     Parameter  Description
  1  $t         Tree descriptor

Example:

    my $Sk = Rd(17..28, 0, 0, 12,   0xFF);
    my $Sd = Rd(17..28, 0, 0, 0xDD, 0xEE);
    my $Sn = Rd(1..13,     0, 0,    0xCC);

    my $sk = Rd(1..14, 14,   0xA1);
    my $sd = Rd(1..14, 0xCC, 0xA2);
    my $sn = Rd(1..15,       0xA3);

    my $rk = Rd((0)x14, 14,   0xB1);
    my $rd = Rd((0)x14, 0xCC, 0xB2);
    my $rn = Rd((0)x15,       0xB3);

    my $b = CreateArena;
    my $t = $b->CreateTree;

    Vmovdqu8 zmm31, "[$Sk]";
    Vmovdqu8 zmm30, "[$Sd]";
    Vmovdqu8 zmm29, "[$Sn]";

    Vmovdqu8 zmm28, "[$sk]";
    Vmovdqu8 zmm27, "[$sd]";
    Vmovdqu8 zmm26, "[$sn]";

    Vmovdqu8 zmm25, "[$rk]";
    Vmovdqu8 zmm24, "[$rd]";
    Vmovdqu8 zmm23, "[$rn]";

    $t->splitFullLeftNode;

    PrintOutRegisterInHex reverse zmm(23..31);

    ok Assemble(debug => 0, eq => <<END);
   zmm31: 0000 00FF 0000 000D   0000 0000 0000 0000   0000 001C 0000 001B   0000 001A 0000 0019   0000 0018 0000 0017   0000 0016 0000 0015   0000 0014 0000 0013   0000 0012 0000 0011
   zmm30: 0000 00EE 0000 00DD   0000 0000 0000 0000   0000 001C 0000 001B   0000 001A 0000 0019   0000 0018 0000 0017   0000 0016 0000 0015   0000 0014 0000 0013   0000 0012 0000 0011
   zmm29: 0000 00CC 0000 0000   0000 0000 0000 000D   0000 000C 0000 000B   0000 000A 0000 0009   0000 0008 0000 0007   0000 0006 0000 0005   0000 0004 0000 0003   0000 0002 0000 0001
   zmm28: 0000 00A1 0000 0007   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0007   0000 0006 0000 0005   0000 0004 0000 0003   0000 0002 0000 0001
   zmm27: 0000 00A2 0000 00CC   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0007   0000 0006 0000 0005   0000 0004 0000 0003   0000 0002 0000 0001
   zmm26: 0000 00A3 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0007   0000 0006 0000 0005   0000 0004 0000 0003   0000 0002 0000 0001
   zmm25: 0000 00B1 0000 0006   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 000E 0000 000D   0000 000C 0000 000B   0000 000A 0000 0009
   zmm24: 0000 00B2 0000 00CC   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 000E 0000 000D   0000 000C 0000 000B   0000 000A 0000 0009
   zmm23: 0000 00B3 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 000E 0000 000D   0000 000C 0000 000B   0000 000A 0000 0009
  END

    my $tk = Rd(1, (0) x 13, 1, 0xC1);
    my $td = Rd(1, (0) x 14,    0xC2);
    my $tn = Rd(1, 0xAA, (0) x 13, 0xCC);

    my $lk = Rd(1..14, 14,   0xA1);
    my $ld = Rd(1..14, 0xCC, 0xA2);
    my $ln = Rd(1..15,       0xAA);

    my $rk = Rd((0)x14, 14,   0xB1);
    my $rd = Rd((0)x14, 0xCC, 0xB2);
    my $rn = Rd((0)x15,       0xBB);

    my $b = CreateArena;
    my $t = $b->CreateTree;

    Vmovdqu8 zmm31, "[$tk]";
    Vmovdqu8 zmm30, "[$td]";
    Vmovdqu8 zmm29, "[$tn]";

    Vmovdqu8 zmm28, "[$lk]";
    Vmovdqu8 zmm27, "[$ld]";
    Vmovdqu8 zmm26, "[$ln]";

    Vmovdqu8 zmm25, "[$rk]";
    Vmovdqu8 zmm24, "[$rd]";
    Vmovdqu8 zmm23, "[$rn]";

    $t->splitFullLeftNode;

    PrintOutRegisterInHex reverse zmm(23..31);

    ok Assemble(debug => 0, eq => <<END);
   zmm31: 0000 00C1 0000 0002   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0008 0000 0001
   zmm30: 0000 00C2 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0008 0000 0001
   zmm29: 0000 00CC 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 00BB   0000 00AA 0000 0001
   zmm28: 0000 00A1 0000 0007   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0007   0000 0006 0000 0005   0000 0004 0000 0003   0000 0002 0000 0001
   zmm27: 0000 00A2 0000 00CC   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0007   0000 0006 0000 0005   0000 0004 0000 0003   0000 0002 0000 0001
   zmm26: 0000 00AA 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0007   0000 0006 0000 0005   0000 0004 0000 0003   0000 0002 0000 0001
   zmm25: 0000 00B1 0000 0006   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 000E 0000 000D   0000 000C 0000 000B   0000 000A 0000 0009
   zmm24: 0000 00B2 0000 00CC   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 000E 0000 000D   0000 000C 0000 000B   0000 000A 0000 0009
   zmm23: 0000 00BB 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 000E 0000 000D   0000 000C 0000 000B   0000 000A 0000 0009
  END

Nasm::X86::Tree::splitFullRightNode($t)

Split a full right node block held in 25..23 whose parent is in 31..29 and place the new left block in 28..26. The loop and length fields are assumed to be authoritative and hence are preserved.

     Parameter  Description
  1  $t         Tree descriptor

Example:

    my $tk = Rd(1..12, 0, 0, 12,      0xC1);
    my $td = Rd(1..12, 0, 0,  0,      0xC2);
    my $tn = Rd(1, 0xBB, 3..13, 0, 0, 0xCC);

    my $lk = Rd(17..30, 14,   0xA1);
    my $ld = Rd(17..30, 0xCC, 0xA2);
    my $ln = Rd(17..31,       0xAA);

    my $rk = Rd(17..30, 14,   0xB1);
    my $rd = Rd(17..30, 0xCC, 0xB2);
    my $rn = Rd(17..31,       0xBB);

    my $b = CreateArena;
    my $t = $b->CreateTree;

    Vmovdqu8 zmm31, "[$tk]";
    Vmovdqu8 zmm30, "[$td]";
    Vmovdqu8 zmm29, "[$tn]";

    Vmovdqu8 zmm28, "[$lk]";
    Vmovdqu8 zmm27, "[$ld]";
    Vmovdqu8 zmm26, "[$ln]";

    Vmovdqu8 zmm25, "[$rk]";
    Vmovdqu8 zmm24, "[$rd]";
    Vmovdqu8 zmm23, "[$rn]";

    $t->splitFullRightNode;

    PrintOutRegisterInHex reverse zmm(23..31);

    ok Assemble(debug => 0, eq => <<END);
   zmm31: 0000 00C1 0000 000D   0000 0000 0000 000C   0000 000B 0000 000A   0000 0009 0000 0008   0000 0007 0000 0006   0000 0005 0000 0004   0000 0003 0000 0002   0000 0018 0000 0001
   zmm30: 0000 00C2 0000 0000   0000 0000 0000 000C   0000 000B 0000 000A   0000 0009 0000 0008   0000 0007 0000 0006   0000 0005 0000 0004   0000 0003 0000 0002   0000 0018 0000 0001
   zmm29: 0000 00CC 0000 0000   0000 000D 0000 000C   0000 000B 0000 000A   0000 0009 0000 0008   0000 0007 0000 0006   0000 0005 0000 0004   0000 0003 0000 00BB   0000 00AA 0000 0001
   zmm28: 0000 00A1 0000 0007   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0017   0000 0016 0000 0015   0000 0014 0000 0013   0000 0012 0000 0011
   zmm27: 0000 00A2 0000 00CC   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0017   0000 0016 0000 0015   0000 0014 0000 0013   0000 0012 0000 0011
   zmm26: 0000 00AA 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0017   0000 0016 0000 0015   0000 0014 0000 0013   0000 0012 0000 0011
   zmm25: 0000 00B1 0000 0006   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 001E 0000 001D   0000 001C 0000 001B   0000 001A 0000 0019
   zmm24: 0000 00B2 0000 00CC   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 001E 0000 001D   0000 001C 0000 001B   0000 001A 0000 0019
   zmm23: 0000 00BB 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 0000 0000 0000   0000 001E 0000 001D   0000 001C 0000 001B   0000 001A 0000 0019
  END

Nasm::X86::Tree::findAndSplit($t, $first, $key, $compare, $offset, $index)

Find a key in a tree which is known to contain at least one key splitting full nodes along the path to the key.

     Parameter  Description
  1  $t         Tree descriptor
  2  $first     Start node
  3  $key       Key to find
  4  $compare   Last comparison result variable
  5  $offset    Offset of last node found
  6  $index     Index within last node found

Nasm::X86::Tree::getKeysData($t, $offset, $zmmKeys, $zmmData, $work1, $work2)

Load the keys and data blocks for a node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $offset    Offset as a variable
  3  $zmmKeys   Numbered zmm for keys
  4  $zmmData   Numbered data for keys
  5  $work1     Optional first work register
  6  $work2     Optional second work register

Nasm::X86::Tree::putKeysData($t, $offset, $zmmKeys, $zmmData, $work1, $work2)

Save the key and data blocks for a node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $offset    Offset as a variable
  3  $zmmKeys   Numbered zmm for keys
  4  $zmmData   Numbered data for keys
  5  $work1     Optional first work register
  6  $work2     Optional second work register

Nasm::X86::Tree::getKeysDataNode($t, $offset, $zmmKeys, $zmmData, $zmmNode, $work1, $work2)

Load the keys, data and child nodes for a node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $offset    Offset as a variable
  3  $zmmKeys   Numbered zmm for keys
  4  $zmmData   Numbered data for keys
  5  $zmmNode   Numbered numbered for keys
  6  $work1     Optional first work register
  7  $work2     Optional second work register

Nasm::X86::Tree::putKeysDataNode($t, $offset, $zmmKeys, $zmmData, $zmmNode, $work1, $work2)

Save the keys, data and child nodes for a node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $offset    Offset as a variable
  3  $zmmKeys   Numbered zmm for keys
  4  $zmmData   Numbered data for keys
  5  $zmmNode   Numbered numbered for keys
  6  $work1     Optional first work register
  7  $work2     Optional second work register

Nasm::X86::Tree::getLengthInKeys($t, $zmm)

Get the length of the keys block in the numbered zmm and return it as a variable.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Zmm number

Nasm::X86::Tree::putLengthInKeys($t, $zmm, $length)

Get the length of the block in the numbered zmm from the specified variable.

     Parameter  Description
  1  $t         Tree
  2  $zmm       Zmm number
  3  $length    Length variable

Nasm::X86::Tree::getUpFromData11($t, $zmm, $transfer)

Get the up offset from the data block in the numbered zmm and return it as a variable.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Zmm number
  3  $transfer  Transfer register

Nasm::X86::Tree::putUpIntoData11($t, $offset, $zmm, $transfer)

Put the offset of the parent keys block expressed as a variable into the numbered zmm.

     Parameter  Description
  1  $t         Tree descriptor
  2  $offset    Variable containing up offset
  3  $zmm       Zmm number
  4  $transfer  Optional transfer register

Nasm::X86::Tree::getUpFromData($t, $zmm, $transfer)

Get the decompressed up offset from the data block in the numbered zmm and return it as a variable. The lowest 6 bits of an offset are always 0b011000. The up field becomes the count field for the root node which has no node above it. To differentiate between up and count, the lowest bit of the up field is set for offsets, and cleared for the count of the number of nodes in the tree held in the root node. Thus if this dword is set to zero it means that this is the count field for an empty tree.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Zmm number
  3  $transfer  Transfer register

Nasm::X86::Tree::getUpFromDataNM($t, $zmm, $transfer)

Get the compressed up offset//count from the data block in the numbered zmm and return it as a variable.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Zmm number
  3  $transfer  Transfer register

Nasm::X86::Tree::putUpIntoData($t, $offset, $zmm, $transfer)

Put the offset of the parent keys block expressed as a variable into the numbered zmm. Offsets always end in 0b01100 as long as only 64 byte allocations have been made in the arena. Offsets are indicated by setting the lowest bit in the dword containing the offset to 1.

     Parameter  Description
  1  $t         Tree descriptor
  2  $offset    Variable containing up offset
  3  $zmm       Zmm number
  4  $transfer  Transfer register

Nasm::X86::Tree::getCountFromData($t, $zmm, $transfer)

Get the number of keys in the tree. The number of keys in the tree is stored in the up field of the data block associated with the root. If the lowest bit in this field is set then the field is an offset, if it is clear then it is a count.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Zmm number
  3  $transfer  Transfer register

Nasm::X86::Tree::incCountInData($t, $zmm, $transfer)

Increment the count field in the up field of the data block associated with the root node. As the up field of the root node is never use to record an up offset we can use it to record the number of keys in the tree instead.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Zmm number
  3  $transfer  Transfer register

Nasm::X86::Tree::decCountInData($t, $zmm, $transfer)

Decrement the count field in the up field of the data block associate with the root node.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Zmm number
  3  $transfer  Transfer register

Nasm::X86::Tree::getLoop($t, $zmm, $transfer)

Return the value of the loop field as a variable.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Numbered zmm
  3  $transfer  Optional transfer register

Nasm::X86::Tree::putLoop($t, $value, $zmm, $transfer)

Set the value of the loop field from a variable.

     Parameter  Description
  1  $t         Tree descriptor
  2  $value     Variable containing offset of next loop entry
  3  $zmm       Numbered zmm
  4  $transfer  Optional transfer register

Nasm::X86::Tree::nodeFromData($t, $data, $node)

Load the the node block into the numbered zmm corresponding to the data block held in the numbered zmm.

     Parameter  Description
  1  $t         Tree descriptor
  2  $data      Numbered zmm containing data
  3  $node      Numbered zmm to hold node block

Nasm::X86::Tree::address($t)

Address of the arena containing a tree.

     Parameter  Description
  1  $t         Tree descriptor

Nasm::X86::Tree::allocBlock($t)

Allocate a block to hold a zmm register in the specified arena and return the offset of the block in a variable.

     Parameter  Description
  1  $t         Tree descriptor

Nasm::X86::Tree::testTree($t, $position, $zmm)

Set the Zero Flag to oppose the tree bit indexed by the specified variable in the numbered zmm register holding the keys of a node to indicate whether the data element indicated by the specified register is an offset to a sub tree in the containing arena or not.

     Parameter  Description
  1  $t         Tree descriptor
  2  $position  Variable holding index of position to test
  3  $zmm       Numbered zmm register holding the keys for a node in the tree

Nasm::X86::Tree::isTree($t, $register, $zmm)

Set the Zero Flag to oppose the tree bit in the numbered zmm register holding the keys of a node to indicate whether the data element indicated by the specified register is an offset to a sub tree in the containing arena or not.

     Parameter  Description
  1  $t         Tree descriptor
  2  $register  Word register holding a bit shifted into the position to test
  3  $zmm       Numbered zmm register holding the keys for a node in the tree

Nasm::X86::Tree::setOrClearTree($t, $set, $register, $zmm)

Set or clear the tree bit in the numbered zmm register holding the keys of a node to indicate that the data element indicated by the specified register is an offset to a sub tree in the containing arena.

     Parameter  Description
  1  $t         Tree descriptor
  2  $set       Set if true else clear
  3  $register  Register holding a single one in the lowest 14 bits at the insertion point
  4  $zmm       Numbered zmm register holding the keys for a node in the tree

Nasm::X86::Tree::setTree($t, $register, $zmm)

Set the tree bit in the numbered zmm register holding the keys of a node to indicate that the data element indexed by the specified register is an offset to a sub tree in the containing arena.

     Parameter  Description
  1  $t         Tree descriptor
  2  $register  Register holding data element index 0..13
  3  $zmm       Numbered zmm register holding the keys for a node in the tree

Nasm::X86::Tree::clearTree($t, $register, $zmm)

Clear the tree bit in the numbered zmm register holding the keys of a node to indicate that the data element indexed by the specified register is an offset to a sub tree in the containing arena.

     Parameter  Description
  1  $t         Tree descriptor
  2  $register  Register holding data element index 0..13
  3  $zmm       Numbered zmm register holding the keys for a node in the tree

Nasm::X86::Tree::getTreeBits($t, $zmm, $register)

Load the tree bits from the numbered zmm into the specified register.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Numbered zmm
  3  $register  Target register

Nasm::X86::Tree::putTreeBits($t, $zmm, $register)

Put the tree bits in the specified register into the numbered zmm.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Numbered zmm
  3  $register  Target register

Nasm::X86::Tree::expandTreeBitsWithZeroOrOne($t, $onz, $zmm, $point)

Insert a zero or one into the tree bits field in the numbered zmm at the specified point.

     Parameter  Description
  1  $t         Tree descriptor
  2  $onz       0 - zero or 1 - one
  3  $zmm       Numbered zmm
  4  $point     Register indicating point

Nasm::X86::Tree::expandTreeBitsWithZero($t, $zmm, $point)

Insert a zero into the tree bits field in the numbered zmm at the specified point.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Numbered zmm
  3  $point     Register indicating point

Nasm::X86::Tree::expandTreeBitsWithOne($t, $zmm, $point)

Insert a one into the tree bits field in the numbered zmm at the specified point.

     Parameter  Description
  1  $t         Tree descriptor
  2  $zmm       Numbered zmm
  3  $point     Register indicating point

LocateIntelEmulator()

Locate the Intel Software Development Emulator.

getInstructionCount()

Get the number of instructions executed from the emulator mix file.

Optimize(%options)

Perform code optimizations.

     Parameter  Description
  1  %options   Options

removeNonAsciiChars($string)

Return a copy of the specified string with all the non ascii characters removed.

     Parameter  Description
  1  $string    String

totalBytesAssembled()

Total size in bytes of all files assembled during testing.

Index

1 All8Structure - Create a structure consisting of 8 byte fields.

2 AllocateAll8OnStack - Create a local data descriptor consisting of the specified number of 8 byte local variables and return an array: (local data descriptor, variable definitions.

3 AllocateMemory - Allocate the specified amount of memory via mmap and return its address.

4 AndBlock - Short circuit and: execute a block of code to test conditions which, if all of them pass, allows the first block to continue successfully else if one of the conditions fails we execute the optional fail block.

5 Assemble - Assemble the generated code.

6 CallC - Call a C subroutine.

7 CheckGeneralPurposeRegister - Check that a register is in fact a general purpose register.

8 CheckMaskRegister - Check that a register is in fact a mask register.

9 CheckNumberedGeneralPurposeRegister - Check that a register is in fact a numbered general purpose register.

10 ChooseRegisters - Choose the specified numbers of registers excluding those on the specified list.

11 ClassifyInRange - Character classification: classify the utf32 characters in a block of memory of specified length using a range specification held in zmm0, zmm1 formatted in double words with each double word in zmm0 having the classification in the highest 8 bits and with zmm0 and zmm1 having the utf32 character at the start (zmm0) and end (zmm1) of each range in the lowest 18 bits.

12 ClassifyRange - Implementation of ClassifyInRange and ClassifyWithinRange.

13 ClassifyWithInRange - Bracket classification: Classify the utf32 characters in a block of memory of specified length using a range specification held in zmm0, zmm1 formatted in double words with the classification range in the high byte of each dword in zmm0 and the utf32 character at the start (zmm0) and end (zmm1) of each range in the lower 18 bits of each dword.

14 ClassifyWithInRangeAndSaveOffset - Alphabetic classification: classify the utf32 characters in a block of memory of specified length using a range specification held in zmm0, zmm1 formatted in double words with the classification code in the highest byte of each double word in zmm0 and the offset of the first element in the range in the highest byte of each dword in zmm1.

15 ClassifyWithInRangeAndSaveWordOffset - Alphabetic classification: classify the utf32 characters in a block of memory of specified length using a range specification held in zmm0, zmm1, zmm2 formatted in double words.

16 ClearMemory - Clear memory.

17 ClearRegisters - Clear registers by setting them to zero.

18 ClearZF - Clear the zero flag.

19 CloseFile - Close the file whose descriptor is in rax.

20 Comment - Insert a comment into the assembly code.

21 CommentWithTraceBack - Insert a comment into the assembly code with a traceback showing how it was generated.

22 ConvertUtf8ToUtf32 - Convert a string of utf8 to an allocated block of utf32 and return its address and length.

23 CopyMemory - Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi.

24 cr - Call a subroutine with a reordering of the registers.

25 CreateArena - Create an relocatable arena and returns its address in rax.

26 CreateLibrary - Create a library

27 CreateShortString - Create a description of a short string.

28 Cstrlen - Length of the C style string addressed by rax returning the length in r15.

29 Db - Layout bytes in the data segment and return their label.

30 Dbwdq - Layout data.

31 DComment - Insert a comment into the data segment.

32 Dd - Layout double words in the data segment and return their label.

33 DescribeArena - Describe a relocatable arena.

34 DescribeArray - Describe a dynamic array held in an arena.

35 DescribeQuarks - Return a descriptor for a set of quarks.

36 DescribeString - Describe a string.

37 DescribeTree - Return a descriptor for a tree with the specified options.

38 Dq - Layout quad words in the data segment and return their label.

39 Ds - Layout bytes in memory and return their label.

40 Dw - Layout words in the data segment and return their label.

41 Ef - Else if block for an If statement.

42 Else - Else block for an If statement.

43 executeFileViaBash - Execute the file named in the arena addressed by rax with bash.

44 Exit - Exit with the specified return code or zero if no return code supplied.

45 Extern - Name external references.

46 Fail - Fail block for an AndBlock.

47 For - For - iterate the block as long as register is less than limit incrementing by increment each time.

48 ForEver - Iterate for ever.

49 ForIn - For - iterate the full block as long as register plus increment is less than than limit incrementing by increment each time then increment the last block for the last non full block.

50 Fork - Fork.

51 FreeMemory - Free memory.

52 G - Define a global variable.

53 getBFromXmm - Get the byte from the numbered xmm register and return it in a variable.

54 getBFromZmm - Get the byte from the numbered zmm register and return it in a variable.

55 getBwdqFromMm - Get the numbered byte|word|double word|quad word from the numbered zmm register and return it in a variable.

56 getDFromXmm - Get the double word from the numbered xmm register and return it in a variable.

57 getDFromZmm - Get the double word from the numbered zmm register and return it in a variable.

58 getInstructionCount - Get the number of instructions executed from the emulator mix file.

59 GetNextUtf8CharAsUtf32 - Get the next utf8 encoded character from the addressed memory and return it as a utf32 char.

60 GetPid - Get process identifier.

61 GetPidInHex - Get process identifier in hex as 8 zero terminated bytes in rax.

62 GetPPid - Get parent process identifier.

63 getQFromXmm - Get the quad word from the numbered xmm register and return it in a variable.

64 getQFromZmm - Get the quad word from the numbered zmm register and return it in a variable.

65 GetUid - Get userid of current process.

66 getWFromXmm - Get the word from the numbered xmm register and return it in a variable.

67 getWFromZmm - Get the word from the numbered zmm register and return it in a variable.

68 Hash - Hash a string addressed by rax with length held in rdi and return the hash code in r15.

69 hexTranslateTable - Create/address a hex translate table and return its label.

70 If - If.

71 IfC - If the carry flag is set then execute the then block else the else block.

72 IfEq - If equal execute the then block else the else block.

73 IfGe - If greater than or equal execute the then block else the else block.

74 IfGt - If greater than execute the then block else the else block.

75 IfLe - If less than or equal execute the then block else the else block.

76 IfLt - If less than execute the then block else the else block.

77 IfNc - If the carry flag is not set then execute the then block else the else block.

78 IfNe - If not equal execute the then block else the else block.

79 IfNs - If signed less than execute the then block else the else block.

80 IfNz - If the zero flag is not set then execute the then block else the else block.

81 IfS - If signed greater than or equal execute the then block else the else block.

82 IfZ - If the zero flag is set then execute the then block else the else block.

83 InsertOneIntoRegisterAtPoint - Insert a one into the specified register at the point indicated by another register.

84 InsertZeroIntoRegisterAtPoint - Insert a zero into the specified register at the point indicated by another register.

85 K - Define a constant variable.

86 Label - Create a unique label or reuse the one supplied.

87 Link - Libraries to link with.

88 LoadBitsIntoMaskRegister - Load a bit string specification into a mask register.

89 LoadConstantIntoMaskRegister - Set a mask register equal to a constant.

90 loadFromZmm - Load the specified register from the offset located in the numbered zmm.

91 LoadRegFromMm - Load the specified register from the numbered zmm at the quad offset specified as a constant number.

92 LoadZmm - Load a numbered zmm with the specified bytes.

93 LocalData - Map local data.

94 LocateIntelEmulator - Locate the Intel Software Development Emulator.

95 Macro - Create a sub with optional parameters name=> the name of the subroutine so it can be reused rather than regenerated, comment=> a comment describing the sub.

96 MaskMemory22 - Write the specified byte into locations in the target mask that correspond to the locations in the source that contain the specified byte.

97 MaskMemoryInRange4_22 - Write the specified byte into locations in the target mask that correspond to the locations in the source that contain 4 bytes in the specified range.

98 Nasm::X86::Arena::allocate - Allocate the variable amount of space in the variable addressed arena and return the offset of the allocation in the arena as a variable.

99 Nasm::X86::Arena::allocBlock - Allocate a block to hold a zmm register in the specified arena and return the offset of the block in a variable.

100 Nasm::X86::Arena::allocZmmBlock - Allocate a block to hold a zmm register in the specified arena and return the offset of the block as a variable.

101 Nasm::X86::Arena::append - Append one arena to another.

102 Nasm::X86::Arena::arenaSize - Get the size of an arena.

103 Nasm::X86::Arena::chain - Return a variable with the end point of a chain of double words in the arena starting at the specified variable.

104 Nasm::X86::Arena::char - Append a character expressed as a decimal number to the specified arena.

105 Nasm::X86::Arena::checkYggdrasilCreated - Return a tree descriptor to the Yggdrasil world tree for an arena.

106 Nasm::X86::Arena::clear - Clear the arena addressed by rax.

107 Nasm::X86::Arena::CreateArray - Create a dynamic array held in an arena.

108 Nasm::X86::Arena::CreateQuarks - Create quarks in a specified arena.

109 Nasm::X86::Arena::CreateString - Create a string from a doubly link linked list of 64 byte blocks linked via 4 byte offsets in an arena and return its descriptor.

110 Nasm::X86::Arena::CreateTree - Create a tree in an arena.

111 Nasm::X86::Arena::DescribeArray - Describe a dynamic array held in an arena.

112 Nasm::X86::Arena::DescribeQuarks - Return a descriptor for a tree in the specified arena.

113 Nasm::X86::Arena::DescribeString - Describe a string and optionally set its first block .

114 Nasm::X86::Arena::DescribeString22 - Describe a string and optionally set its first block.

115 Nasm::X86::Arena::DescribeTree - Return a descriptor for a tree in the specified arena with the specified options.

116 Nasm::X86::Arena::dump - Dump details of an arena.

117 Nasm::X86::Arena::establishYggdrasil - Return a tree descriptor to the Yggdrasil world tree for an arena creating the world tree Yggdrasil if it has not already been created.

118 Nasm::X86::Arena::firstFreeBlock - Create and load a variable with the first free block on the free block chain or zero if no such block in the given arena.

119 Nasm::X86::Arena::freeBlock - Free a block in an arena by placing it on the free chain.

120 Nasm::X86::Arena::getZmmBlock - Get the block with the specified offset in the specified string and return it in the numbered zmm.

121 Nasm::X86::Arena::length - Get the currently used length of an arena.

122 Nasm::X86::Arena::m - Append the variable addressed content of variable size to the specified arena.

123 Nasm::X86::Arena::makeReadOnly - Make an arena read only.

124 Nasm::X86::Arena::makeWriteable - Make an arena writable.

125 Nasm::X86::Arena::nl - Append a new line to the arena addressed by rax.

126 Nasm::X86::Arena::out - Print the specified arena on sysout.

127 Nasm::X86::Arena::putChain - Write the double word in the specified variable to the double word location at the the specified offset in the specified arena.

128 Nasm::X86::Arena::putZmmBlock - Write the numbered zmm to the block at the specified offset in the specified arena.

129 Nasm::X86::Arena::q - Append a constant string to the arena.

130 Nasm::X86::Arena::ql - Append a quoted string containing new line characters to the specified arena.

131 Nasm::X86::Arena::read - Read a file specified by a variable addressed zero terminated string and place the contents of the file into the named arena.

132 Nasm::X86::Arena::setFirstFreeBlock - Set the first free block field from a variable.

133 Nasm::X86::Arena::updateSpace - Make sure that the variable addressed arena has enough space to accommodate content of the variable size.

134 Nasm::X86::Arena::write - Write the content of the specified arena to a file specified by a zero terminated string.

135 Nasm::X86::Arena::z - Append a trailing zero to the arena addressed by rax.

136 Nasm::X86::Array::address - Address of a string.

137 Nasm::X86::Array::allocBlock - Allocate a block to hold a zmm register in the specified arena and return the offset of the block in a variable.

138 Nasm::X86::Array::dump - Dump a array.

139 Nasm::X86::Array::get - Get an element from the array.

140 Nasm::X86::Array::pop - Pop an element from an array and return it in a variable.

141 Nasm::X86::Array::push - Push a variable element onto an array.

142 Nasm::X86::Array::put - Put an element into an array as long as it is with in its limits established by pushing.

143 Nasm::X86::Array::reload - Reload the specified array description.

144 Nasm::X86::Array::size - Return the size of an array as a variable.

145 Nasm::X86::LocalData::allocate8 - Add some 8 byte local variables and return an array of variable definitions.

146 Nasm::X86::LocalData::free - Free a local data area on the stack.

147 Nasm::X86::LocalData::start - Start a local data area on the stack.

148 Nasm::X86::LocalData::variable - Add a local variable.

149 Nasm::X86::LocalVariable::stack - Address a local variable on the stack.

150 Nasm::X86::Quarks::call - Call a subroutine via its quark number.

151 Nasm::X86::Quarks::callSubFromQuarkNumber - Call the sub associated with a quark number.

152 Nasm::X86::Quarks::callSubFromQuarkViaQuarks - Given the quark number for a lexical item and the quark set of lexical items call the associated method.

153 Nasm::X86::Quarks::callSubFromShortString - Given a short string call the associated subroutine if it exists.

154 Nasm::X86::Quarks::dump - Dump a set of quarks

155 Nasm::X86::Quarks::locateQuarkFromShortString - Locate (if possible) but do not create a quark from a short string.

156 Nasm::X86::Quarks::put - Create a quark from a string.

157 Nasm::X86::Quarks::putSub - Put a new subroutine definition into the sub quarks.

158 Nasm::X86::Quarks::quarkFromShortString - Create a quark from a short string.

159 Nasm::X86::Quarks::quarkFromSub - Create a quark from a subroutine definition.

160 Nasm::X86::Quarks::quarkToQuark - Given a variable quark number in one set of quarks find the corresponding quark in another set of quarks and return it in a variable.

161 Nasm::X86::Quarks::reload - Reload the description of a set of quarks.

162 Nasm::X86::Quarks::shortStringFromQuark - Load a short string from the quark with the specified number.

163 Nasm::X86::Quarks::subFromQuark - Get the offset of a subroutine as a variable from a set of quarks.

164 Nasm::X86::Quarks::subFromQuarkNumber - Get the sub associated with a sub quark by its number.

165 Nasm::X86::Quarks::subFromQuarkViaQuarks - Given the quark number for a lexical item and the quark set of lexical items get the offset of the associated method.

166 Nasm::X86::Quarks::subFromShortString - Given a short string get the offset of the associated subroutine or zero if no such subroutine exists.

167 Nasm::X86::ShortString::append - Append the right hand short string to the left hand short string.

168 Nasm::X86::ShortString::appendByte - Append the lowest variable byte to the specified string.

169 Nasm::X86::ShortString::clear - Clear a short string.

170 Nasm::X86::ShortString::len - Return the length of a short string in a variable.

171 Nasm::X86::ShortString::load - Load the variable addressed data with the variable length into the short string.

172 Nasm::X86::ShortString::loadConstantString - Load the a short string with a constant string.

173 Nasm::X86::ShortString::loadDwordBytes - Load the specified byte of each dword in the variable addressed data with the variable length into the short string.

174 Nasm::X86::ShortString::loadDwordWords - Load the specified word of each dword in the variable addressed data with the variable length into the short string.

175 Nasm::X86::ShortString::setLength - Set the length of the short string.

176 Nasm::X86::String::address - Address of a string.

177 Nasm::X86::String::allocBlock - Allocate a block to hold a zmm register in the specified arena and return the offset of the block in a variable.

178 Nasm::X86::String::append - Append the specified content in memory to the specified string.

179 Nasm::X86::String::appendShortString - Append the content of the specified short string.

180 Nasm::X86::String::clear - Clear the block by freeing all but the first block and putting the remainder on the free chain addressed by Yggdrasil .

181 Nasm::X86::String::concatenate - Concatenate two strings by appending a copy of the source to the target string.

182 Nasm::X86::String::deleteChar - Delete a character in a string.

183 Nasm::X86::String::dump - Dump a string to sysout.

184 Nasm::X86::String::getBlockLength - Get the block length of the numbered zmm and return it in a variable.

185 Nasm::X86::String::getCharacter - Get a character from a string at the variable position.

186 Nasm::X86::String::getNextAndPrevBlockOffsetFromZmm - Get the offsets of the next and previous blocks as variables from the specified zmm.

187 Nasm::X86::String::getZmmBlock - Get the block with the specified offset in the specified string and return it in the numbered zmm.

188 Nasm::X86::String::insertChar - Insert a character into a string.

189 Nasm::X86::String::len - Find the length of a string.

190 Nasm::X86::String::putNextandPrevBlockOffsetIntoZmm - Save next and prev offsets into a zmm representing a block.

191 Nasm::X86::String::putZmmBlock - Write the numbered zmm to the block at the specified offset in the specified arena.

192 Nasm::X86::String::saveToShortString - Place as much as possible of the specified string into the specified short string.

193 Nasm::X86::String::setBlockLengthInZmm - Set the block length of the numbered zmm to the specified length.

194 Nasm::X86::Structure::field - Add a field of the specified length with an optional comment.

195 Nasm::X86::StructureField::addr - Address a field in a structure by either the default register or the named register.

196 Nasm::X86::Sub::call - Call a sub passing it some parameters.

197 Nasm::X86::Sub::callTo - Call a sub passing it some parameters.

198 Nasm::X86::Sub::dispatch - Jump into the specified subroutine so that code of the target subroutine is executed instead of the code of the current subroutine allowing the target subroutine to be dispatched to process the parameter list of the current subroutine.

199 Nasm::X86::Sub::dispatchV - Dispatch the variable subroutine using the specified register.

200 Nasm::X86::Sub::V - Put the address of a subroutine into a stack variable so that it can be passed as a parameter.

201 Nasm::X86::Sub::via - Call a sub by reference passing it some parameters.

202 Nasm::X86::Tree::address - Address of the arena containing a tree.

203 Nasm::X86::Tree::allocBlock - Allocate a block to hold a zmm register in the specified arena and return the offset of the block in a variable.

204 Nasm::X86::Tree::allocKeysDataNode - Allocate a keys/data/node block and place it in the numbered zmm registers.

205 Nasm::X86::Tree::by - Call the specified block with each (key, data) from the specified tree in order.

206 Nasm::X86::Tree::clearTree - Clear the tree bit in the numbered zmm register holding the keys of a node to indicate that the data element indexed by the specified register is an offset to a sub tree in the containing arena.

207 Nasm::X86::Tree::decCountInData - Decrement the count field in the up field of the data block associate with the root node.

208 Nasm::X86::Tree::depth - Return the depth of a node within a tree.

209 Nasm::X86::Tree::dump - Dump a tree and all its sub trees.

210 Nasm::X86::Tree::expandTreeBitsWithOne - Insert a one into the tree bits field in the numbered zmm at the specified point.

211 Nasm::X86::Tree::expandTreeBitsWithZero - Insert a zero into the tree bits field in the numbered zmm at the specified point.

212 Nasm::X86::Tree::expandTreeBitsWithZeroOrOne - Insert a zero or one into the tree bits field in the numbered zmm at the specified point.

213 Nasm::X86::Tree::find - Find a key in a tree and test whether the found data is a sub tree.

214 Nasm::X86::Tree::findAndReload - Find a key in the specified tree and clone it is it is a sub tree.

215 Nasm::X86::Tree::findAndSplit - Find a key in a tree which is known to contain at least one key splitting full nodes along the path to the key.

216 Nasm::X86::Tree::findShortString - Find the data at the end of a key chain held in a short string.

217 Nasm::X86::Tree::getCountFromData - Get the number of keys in the tree.

218 Nasm::X86::Tree::getKeysData - Load the keys and data blocks for a node.

219 Nasm::X86::Tree::getKeysDataNode - Load the keys, data and child nodes for a node.

220 Nasm::X86::Tree::getLengthInKeys - Get the length of the keys block in the numbered zmm and return it as a variable.

221 Nasm::X86::Tree::getLoop - Return the value of the loop field as a variable.

222 Nasm::X86::Tree::getTreeBits - Load the tree bits from the numbered zmm into the specified register.

223 Nasm::X86::Tree::getUpFromData - Get the decompressed up offset from the data block in the numbered zmm and return it as a variable.

224 Nasm::X86::Tree::getUpFromData11 - Get the up offset from the data block in the numbered zmm and return it as a variable.

225 Nasm::X86::Tree::getUpFromDataNM - Get the compressed up offset//count from the data block in the numbered zmm and return it as a variable.

226 Nasm::X86::Tree::incCountInData - Increment the count field in the up field of the data block associated with the root node.

227 Nasm::X86::Tree::insert - Insert a dword into into the specified tree at the specified key.

228 Nasm::X86::Tree::insertDataOrTree - Insert either a key, data pair into the tree or create a sub tree at the specified key (if it does not already exist) and return the offset of the first block of the sub tree in the data variable.

229 Nasm::X86::Tree::insertShortString - Insert some data at the end of a chain of sub trees keyed by the contents of a short string.

230 Nasm::X86::Tree::insertTree - Insert a sub tree into the specified tree tree under the specified key.

231 Nasm::X86::Tree::insertTreeAndReload - Insert a new sub tree into the specified tree tree under the specified key and return a descriptor for it.

232 Nasm::X86::Tree::isTree - Set the Zero Flag to oppose the tree bit in the numbered zmm register holding the keys of a node to indicate whether the data element indicated by the specified register is an offset to a sub tree in the containing arena or not.

233 Nasm::X86::Tree::iterator - Iterate through a multi way tree starting either at the specified node or the first node of the specified tree.

234 Nasm::X86::Tree::Iterator::next - Next element in the tree.

235 Nasm::X86::Tree::leftMost - Return the offset of the left most node from the specified node.

236 Nasm::X86::Tree::leftOrRightMost - Return the offset of the left most or right most node.

237 Nasm::X86::Tree::nodeFromData - Load the the node block into the numbered zmm corresponding to the data block held in the numbered zmm.

238 Nasm::X86::Tree::print - Print a tree.

239 Nasm::X86::Tree::putKeysData - Save the key and data blocks for a node.

240 Nasm::X86::Tree::putKeysDataNode - Save the keys, data and child nodes for a node.

241 Nasm::X86::Tree::putLengthInKeys - Get the length of the block in the numbered zmm from the specified variable.

242 Nasm::X86::Tree::putLoop - Set the value of the loop field from a variable.

243 Nasm::X86::Tree::putTreeBits - Put the tree bits in the specified register into the numbered zmm.

244 Nasm::X86::Tree::putUpIntoData - Put the offset of the parent keys block expressed as a variable into the numbered zmm.

245 Nasm::X86::Tree::putUpIntoData11 - Put the offset of the parent keys block expressed as a variable into the numbered zmm.

246 Nasm::X86::Tree::reload - Reload the specified tree description.

247 Nasm::X86::Tree::reParent - Reparent the children of a node held in registers.

248 Nasm::X86::Tree::rightMost - Return the offset of the left most node from the specified node.

249 Nasm::X86::Tree::setOrClearTree - Set or clear the tree bit in the numbered zmm register holding the keys of a node to indicate that the data element indicated by the specified register is an offset to a sub tree in the containing arena.

250 Nasm::X86::Tree::setTree - Set the tree bit in the numbered zmm register holding the keys of a node to indicate that the data element indexed by the specified register is an offset to a sub tree in the containing arena.

251 Nasm::X86::Tree::size - Return a variable containing the number of keys in the specified tree.

252 Nasm::X86::Tree::splitFullLeftNode - Split a full left node block held in 28.

253 Nasm::X86::Tree::splitFullLeftOrRightNode - Split a full a full left node (held in 28.

254 Nasm::X86::Tree::splitFullRightNode - Split a full right node block held in 25.

255 Nasm::X86::Tree::splitFullRoot - Split a full root block held in 31.

256 Nasm::X86::Tree::splitNode - Split a non root node given its offset in an arena retaining the key being inserted in the node being split while putting the remainder to the left or right.

257 Nasm::X86::Tree::testTree - Set the Zero Flag to oppose the tree bit indexed by the specified variable in the numbered zmm register holding the keys of a node to indicate whether the data element indicated by the specified register is an offset to a sub tree in the containing arena or not.

258 Nasm::X86::Tree::transferTreeBitsFromLeft - Transfer tree bits when splitting a full left node.

259 Nasm::X86::Tree::transferTreeBitsFromLeftOrRight - Transfer tree bits when splitting a full left or right node.

260 Nasm::X86::Tree::transferTreeBitsFromParent - Transfer tree bits when splitting a full node.

261 Nasm::X86::Tree::transferTreeBitsFromRight - Transfer tree bits when splitting a full right node.

262 Nasm::X86::Variable::add - Add the right hand variable to the left hand variable and return the result as a new variable.

263 Nasm::X86::Variable::address - Get the address of a variable with an optional offset.

264 Nasm::X86::Variable::allocateMemory - Allocate the specified amount of memory via mmap and return its address.

265 Nasm::X86::Variable::and - And two variables.

266 Nasm::X86::Variable::arithmetic - Return a variable containing the result of an arithmetic operation on the left hand and right hand side variables.

267 Nasm::X86::Variable::assign - Assign to the left hand side the value of the right hand side.

268 Nasm::X86::Variable::boolean - Combine the left hand variable with the right hand variable via a boolean operator.

269 Nasm::X86::Variable::booleanC - Combine the left hand variable with the right hand variable via a boolean operator using a conditional move instruction.

270 Nasm::X86::Variable::booleanZF - Combine the left hand variable with the right hand variable via a boolean operator and indicate the result by setting the zero flag if the result is true.

271 Nasm::X86::Variable::call - Execute the call instruction for a target whose address is held in the specified variable

272 Nasm::X86::Variable::clearBit - Clear a bit in the specified mask register retaining the other bits.

273 Nasm::X86::Variable::clearMaskBit - Clear a bit in the specified mask register retaining the other bits.

274 Nasm::X86::Variable::clearMemory - Clear the memory described in this variable.

275 Nasm::X86::Variable::clone - Clone a variable.

276 Nasm::X86::Variable::copy - Copy one variable into another.

277 Nasm::X86::Variable::copyMemory - Copy from one block of memory to another.

278 Nasm::X86::Variable::copyRef - Copy a reference to a variable.

279 Nasm::X86::Variable::copyZF - Copy the current state of the zero flag into a variable.

280 Nasm::X86::Variable::copyZFInverted - Copy the opposite of the current state of the zero flag into a variable.

281 Nasm::X86::Variable::d - Dump the value of a variable on stderr and append a new line.

282 Nasm::X86::Variable::debug - Dump the value of a variable on stdout with an indication of where the dump came from.

283 Nasm::X86::Variable::dec - Decrement a variable.

284 Nasm::X86::Variable::divide - Divide the left hand variable by the right hand variable and return the result as a new variable.

285 Nasm::X86::Variable::division - Return a variable containing the result or the remainder that occurs when the left hand side is divided by the right hand side.

286 Nasm::X86::Variable::dump - Dump the value of a variable to the specified channel adding an optional title and new line if requested.

287 Nasm::X86::Variable::eq - Check whether the left hand variable is equal to the right hand variable.

288 Nasm::X86::Variable::equals - Equals operator.

289 Nasm::X86::Variable::err - Dump the value of a variable on stderr.

290 Nasm::X86::Variable::errNL - Dump the value of a variable on stderr and append a new line.

291 Nasm::X86::Variable::for - Iterate the block limit times.

292 Nasm::X86::Variable::freeMemory - Free the memory addressed by this variable for the specified length.

293 Nasm::X86::Variable::ge - Check whether the left hand variable is greater than or equal to the right hand variable.

294 Nasm::X86::Variable::getBFromZmm - Get the byte from the numbered zmm register and put it in a variable.

295 Nasm::X86::Variable::getConst - Load the variable from a constant in effect setting a variable to a specified value.

296 Nasm::X86::Variable::getDFromZmm - Get the double word from the numbered zmm register and put it in a variable.

297 Nasm::X86::Variable::getQFromZmm - Get the quad word from the numbered zmm register and put it in a variable.

298 Nasm::X86::Variable::getReg - Load the variable from the named registers.

299 Nasm::X86::Variable::getWFromZmm - Get the word from the numbered zmm register and put it in a variable.

300 Nasm::X86::Variable::gt - Check whether the left hand variable is greater than the right hand variable.

301 Nasm::X86::Variable::inc - Increment a variable.

302 Nasm::X86::Variable::incDec - Increment or decrement a variable.

303 Nasm::X86::Variable::isRef - Check whether the specified variable is a reference to another variable.

304 Nasm::X86::Variable::le - Check whether the left hand variable is less than or equal to the right hand variable.

305 Nasm::X86::Variable::loadZmm - Load bytes from the memory addressed by the specified source variable into the numbered zmm register.

306 Nasm::X86::Variable::lt - Check whether the left hand variable is less than the right hand variable.

307 Nasm::X86::Variable::max - Maximum of two variables.

308 Nasm::X86::Variable::min - Minimum of two variables.

309 Nasm::X86::Variable::minusAssign - Implement minus and assign.

310 Nasm::X86::Variable::mod - Divide the left hand variable by the right hand variable and return the remainder as a new variable.

311 Nasm::X86::Variable::ne - Check whether the left hand variable is not equal to the right hand variable.

312 Nasm::X86::Variable::or - Or two variables.

313 Nasm::X86::Variable::out - Dump the value of a variable on stdout.

314 Nasm::X86::Variable::outNL - Dump the value of a variable on stdout and append a new line.

315 Nasm::X86::Variable::plusAssign - Implement plus and assign.

316 Nasm::X86::Variable::pop - Pop a variable from the stack.

317 Nasm::X86::Variable::printErrMemoryInHexNL - Write the memory addressed by a variable to stderr.

318 Nasm::X86::Variable::printMemoryInHexNL - Write, in hexadecimal, the memory addressed by a variable to stdout or stderr.

319 Nasm::X86::Variable::printOutMemoryInHexNL - Write the memory addressed by a variable to stdout.

320 Nasm::X86::Variable::printOutZeroString - Print the variable addressed zero terminated string on stdout.

321 Nasm::X86::Variable::push - Push a variable onto the stack.

322 Nasm::X86::Variable::putBIntoXmm - Place the value of the content variable at the byte in the numbered xmm register.

323 Nasm::X86::Variable::putBIntoZmm - Place the value of the content variable at the byte in the numbered zmm register.

324 Nasm::X86::Variable::putBwdqIntoMm - Place the value of the content variable at the byte|word|double word|quad word in the numbered zmm register.

325 Nasm::X86::Variable::putDIntoXmm - Place the value of the content variable at the double word in the numbered xmm register.

326 Nasm::X86::Variable::putDIntoZmm - Place the value of the content variable at the double word in the numbered zmm register.

327 Nasm::X86::Variable::putQIntoXmm - Place the value of the content variable at the quad word in the numbered xmm register.

328 Nasm::X86::Variable::putQIntoZmm - Place the value of the content variable at the quad word in the numbered zmm register.

329 Nasm::X86::Variable::putWIntoXmm - Place the value of the content variable at the word in the numbered xmm register.

330 Nasm::X86::Variable::putWIntoZmm - Place the value of the content variable at the word in the numbered zmm register.

331 Nasm::X86::Variable::setBit - Set a bit in the specified register retaining the other bits.

332 Nasm::X86::Variable::setMask - Set the mask register to ones starting at the specified position for the specified length and zeroes elsewhere.

333 Nasm::X86::Variable::setMaskBit - Set a bit in the specified mask register retaining the other bits.

334 Nasm::X86::Variable::setMaskFirst - Set the first bits in the specified mask register.

335 Nasm::X86::Variable::setReg - Set the named registers from the content of the variable.

336 Nasm::X86::Variable::setZmm - Load bytes from the memory addressed by specified source variable into the numbered zmm register at the offset in the specified offset moving the number of bytes in the specified variable.

337 Nasm::X86::Variable::str - The name of the variable.

338 Nasm::X86::Variable::sub - Subtract the right hand variable from the left hand variable and return the result as a new variable.

339 Nasm::X86::Variable::times - Multiply the left hand variable by the right hand variable and return the result as a new variable.

340 Nasm::X86::Variable::zBroadCastD - Broadcast a double word in a variable into the numbered zmm.

341 NasmX86::Library::load - Load a library and return the addresses of its subroutines as variables

342 OnSegv - Request a trace back followed by exit on a segv signal.

343 OpenRead - Open a file, whose name is addressed by rax, for read and return the file descriptor in rax.

344 OpenWrite - Create the file named by the terminated string addressed by rax for write.

345 Optimize - Perform code optimizations.

346 OrBlock - Short circuit or: execute a block of code to test conditions which, if one of them is met, leads on to the execution of the pass block, if all of the tests fail we continue withe the test block.

347 Pass - Pass block for an OrBlock.

348 PeekR - Peek at register on stack.

349 PopEax - We cannot pop a double word from the stack in 64 bit long mode using pop so we improvise.

350 PopMask - Pop Mask registers.

351 PopR - Pop registers from the stack.

352 PopRR - Pop registers from the stack without tracking.

353 PopZmm - Pop zmm registers.

354 PrintErrMemory - Print the memory addressed by rax for a length of rdi on stderr.

355 PrintErrMemoryInHex - Dump memory from the address in rax for the length in rdi on stderr.

356 PrintErrMemoryInHexNL - Dump memory from the address in rax for the length in rdi and then print a new line.

357 PrintErrMemoryNL - Print the memory addressed by rax for a length of rdi followed by a new line on stderr.

358 PrintErrNL - Print a new line to stderr.

359 PrintErrRaxInDec - Print rax in decimal on stderr

360 PrintErrRaxInDecNL - Print rax in decimal on stderr followed by a new line

361 PrintErrRaxInHex - Write the content of register rax in hexadecimal in big endian notation to stderr.

362 PrintErrRaxInHexNL - Write the content of register rax in hexadecimal in big endian notation to stderr followed by a new line.

363 PrintErrRegisterInHex - Print the named registers as hex strings on stderr.

364 PrintErrSpace - Print one or more spaces to stderr.

365 PrintErrString - Print a constant string to stderr.

366 PrintErrStringNL - Print a constant string followed by a new line to stderr.

367 PrintErrTraceBack - Print sub routine track back on stderr.

368 PrintErrUtf32 - Print the utf 8 character addressed by rax to stderr.

369 PrintErrUtf8Char - Print the utf 8 character addressed by rax to stderr.

370 PrintErrZF - Print the zero flag without disturbing it on stderr.

371 PrintMemory - Print the memory addressed by rax for a length of rdi on the specified channel.

372 PrintMemoryInHex - Dump memory from the address in rax for the length in rdi on the specified channel.

373 PrintMemoryNL - Print the memory addressed by rax for a length of rdi on the specified channel followed by a new line.

374 PrintNL - Print a new line to stdout or stderr.

375 PrintOneRegisterInHex - Print the named register as a hex string.

376 PrintOutMemory - Print the memory addressed by rax for a length of rdi on stdout.

377 PrintOutMemoryInHex - Dump memory from the address in rax for the length in rdi on stdout.

378 PrintOutMemoryInHexNL - Dump memory from the address in rax for the length in rdi and then print a new line.

379 PrintOutMemoryNL - Print the memory addressed by rax for a length of rdi followed by a new line on stdout.

380 PrintOutNL - Print a new line to stderr.

381 PrintOutRaxInDec - Print rax in decimal on stdout

382 PrintOutRaxInDecNL - Print rax in decimal on stdout followed by a new line

383 PrintOutRaxInHex - Write the content of register rax in hexadecimal in big endian notation to stout.

384 PrintOutRaxInHexNL - Write the content of register rax in hexadecimal in big endian notation to stdout followed by a new line

385 PrintOutRaxInReverseInHex - Write the content of register rax to stderr in hexadecimal in little endian notation.

386 PrintOutRegisterInHex - Print the named registers as hex strings on stdout.

387 PrintOutRegistersInHex - Print the general purpose registers in hex.

388 PrintOutRflagsInHex - Print the flags register in hex.

389 PrintOutRipInHex - Print the instruction pointer in hex.

390 PrintOutSpace - Print one or more spaces to stdout.

391 PrintOutString - Print a constant string to stdout.

392 PrintOutStringNL - Print a constant string followed by a new line to stdout.

393 PrintOutTraceBack - Print sub routine track back on stdout.

394 PrintOutUtf32 - Print the utf 8 character addressed by rax to stdout.

395 PrintOutUtf8Char - Print the utf 8 character addressed by rax to stdout.

396 PrintOutZF - Print the zero flag without disturbing it on stdout.

397 PrintRaxInDec - Print rax in decimal on the specified channel

398 PrintRaxInHex - Write the content of register rax in hexadecimal in big endian notation to the specified channel.

399 PrintRaxInHex22 - Write the content of register rax in hexadecimal in big endian notation to the specified channel.

400 PrintRegisterInHex - Print the named registers as hex strings.

401 PrintSpace - Print one or more spaces to the specified channel.

402 PrintString - Print a constant string to the specified channel.

403 PrintStringNL - Print a constant string to the specified channel followed by a new line.

404 PrintTraceBack - Trace the call stack.

405 PrintUtf32 - Print the specified number of utf32 characters at the specified address to the specified channel.

406 PrintUtf8Char - Print the utf 8 character addressed by rax to the specified channel.

407 PushMask - Push several Mask registers.

408 PushR - Push registers onto the stack.

409 PushRAssert - Check that the stack ash the expected depth.

410 PushRR - Push registers onto the stack without tracking.

411 PushZmm - Push several zmm registers.

412 putIntoZmm - Put the specified register into the numbered zmm at the specified offset in the zmm.

413 R - Define a reference variable.

414 Rb - Layout bytes in the data segment and return their label.

415 Rbwdq - Layout data.

416 RComment - Insert a comment into the read only data segment.

417 Rd - Layout double words in the data segment and return their label.

418 ReadChar - Read a character from stdin and return it in rax else return -1 in rax if no character was read

419 ReadFile - Read a file into memory.

420 ReadTimeStampCounter - Read the time stamp counter and return the time in nanoseconds in rax.

421 RegistersAvailable - Add a new set of registers that are available.

422 RegistersFree - Remove the current set of registers known to be free.

423 RegisterSize - Return the size of a register.

424 removeNonAsciiChars - Return a copy of the specified string with all the non ascii characters removed.

425 ReorderSyscallRegisters - Map the list of registers provided to the 64 bit system call sequence.

426 RestoreFirstFour - Restore the first 4 parameter registers.

427 RestoreFirstFourExceptRax - Restore the first 4 parameter registers except rax so it can return its value.

428 RestoreFirstFourExceptRaxAndRdi - Restore the first 4 parameter registers except rax and rdi so we can return a pair of values.

429 RestoreFirstSeven - Restore the first 7 parameter registers.

430 RestoreFirstSevenExceptRax - Restore the first 7 parameter registers except rax which is being used to return the result.

431 RestoreFirstSevenExceptRaxAndRdi - Restore the first 7 parameter registers except rax and rdi which are being used to return the results.

432 Rq - Layout quad words in the data segment and return their label.

433 Rs - Layout bytes in read only memory and return their label.

434 Rutf8 - Layout a utf8 encoded string as bytes in read only memory and return their label.

435 Rw - Layout words in the data segment and return their label.

436 SaveFirstFour - Save the first 4 parameter registers making any parameter registers read only.

437 SaveFirstSeven - Save the first 7 parameter registers.

438 SaveRegIntoMm - Save the specified register into the numbered zmm at the quad offset specified as a constant number.

439 SetLabel - Create (if necessary) and set a label in the code section returning the label so set.

440 SetMaskRegister - Set the mask register to ones starting at the specified position for the specified length and zeroes elsewhere.

441 SetZF - Set the zero flag.

442 Start - Initialize the assembler.

443 StatSize - Stat a file whose name is addressed by rax to get its size in rax.

444 StringLength - Length of a zero terminated string.

445 Structure - Create a structure addressed by a register.

446 Subroutine - Create a subroutine that can be called in assembler code.

447 SubroutineStartStack - Initialize a new stack frame.

448 Then - Then block for an If statement.

449 totalBytesAssembled - Total size in bytes of all files assembled during testing.

450 unlinkFile - Unlink the named file.

451 UnReorderSyscallRegisters - Recover the initial values in registers that were reordered.

452 V - Define a variable.

453 Variable - Create a new variable with the specified name initialized via an optional expression.

454 WaitPid - Wait for the pid in rax to complete.

455 xmm - Add xmm to the front of a list of register expressions.

456 ymm - Add ymm to the front of a list of register expressions.

457 zmm - Add zmm to the front of a list of register expressions.

Installation

This module is written in 100% Pure Perl and, thus, it is easy to read, comprehend, use, modify and install via cpan:

  sudo cpan install Nasm::X86

Author

philiprbrenan@gmail.com

http://www.appaapps.com

Copyright

Copyright (c) 2016-2021 Philip R Brenan.

This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.