Name

Nasm::X86 - Generate Nasm assembler code

Synopsis

Write and execute x64 instructions using perl as a macro assembler as shown in the following examples.

Avx512 instructions

Use avx512 instructions to reorder data using 512 bit zmm* registers:

Start;
my $q = Rs my $s = join '', ('a'..'p')x4;
Mov rax, Ds('0'x128);

Vmovdqu32 zmm0, "[$q]";
Vprolq    zmm1, zmm0, 32;
Vmovdqu32 "[rax]", zmm1;

Mov rdi, length $s;
PrintOutMemory;
Exit;

ok $s       =~ m(abcdefghijklmnopabcdefghijklmnopabcdefghijklmnopabcdefghijklmnop)s;
ok Assemble =~ m(efghabcdmnopijklefghabcdmnopijklefghabcdmnopijklefghabcdmnopijkl)s;

Dynamic string held in an arena

Create a dynamic byte string, add some content to it, write the byte string to a file and then execute it:.

Start;
my $s = CreateByteString;                                                     # Create a string
$s->ql(<<END);                                                                # Write code to execute
#!/usr/bin/bash
whoami
ls -la
pwd
END
$s->write;                                                                    # Write code to a temporary file
$s->bash;                                                                     # Execute the temporary file
$s->unlink;                                                                   # Execute the temporary file
Exit;                                                                         # Return to operating system

my $u = qx(whoami); chomp($u);
ok Assemble =~ m($u);

Process management

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

Start;                                                                        # Start the program
Fork;                                                                         # Fork

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

Exit;                                                                         # Return to operating system

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

Read a file

Read this file:

Start;                                                                        # Start the program
Mov rax, Rs($0);                                                              # File to read
ReadFile;                                                                     # Read file
PrintOutMemory;                                                               # Print memory
Exit;                                                                         # Return to operating system

my $r = Assemble;                                                             # Assemble and execute
ok index($r, readFile($0)) > -1;                                              # Output contains this file

Installation

You will need the Intel Software Development Emulator and the Networkwide Assembler installed on your test system. For full details of how to do this see: https://github.com/philiprbrenan/NasmX86/blob/main/.github/workflows/main.yml

Description

Generate Nasm assembler code

Version "20210419".

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)

Set a label in the code section

   Parameter  Description
1  $l         Label

Example:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

  my $l = Label;
  Jmp $l;

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

  Exit;

  is_deeply Assemble, <<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:

  Start;
  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;
  Exit;
  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:

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

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

  Mov rdi, length $s;
  PrintOutMemory;
  Exit;
  ok Assemble =~ m(Hello World);

  Start;

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

  Mov(rax, 1);
  Mov(rbx, 2);
  Mov(rcx, 3);
  Mov(rdx, 4);
  Mov(r8,  5);
  Lea r9,  "[rax+rbx]";
  PrintOutRegistersInHex;
  Exit;
  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;

Db(@bytes)

Layout bytes in the data segment and return their label

   Parameter  Description
1  @bytes     Bytes to layout

Dw(@words)

Layout words in the data segment and return their label

   Parameter  Description
1  @words     Words to layout

Dd(@dwords)

Layout double words in the data segment and return their label

   Parameter  Description
1  @dwords    Double words to layout

Dq(@qwords)

Layout quad words in the data segment and return their label

   Parameter  Description
1  @qwords    Quad words to layout

Rb(@bytes)

Layout bytes in the data segment and return their label

   Parameter  Description
1  @bytes     Bytes to layout

Rw(@words)

Layout words in the data segment and return their label

   Parameter  Description
1  @words     Words to layout

Rd(@dwords)

Layout double words in the data segment and return their label

   Parameter  Description
1  @dwords    Double words to layout

Rq(@qwords)

Layout quad words in the data segment and return their label

   Parameter  Description
1  @qwords    Quad words to layout

Registers

Operations on registers

SaveFirstFour()

Save the first 4 parameter registers

Example:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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:

  Start;
  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 fof syscall  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  PrintOutRegisterInHex rdi;

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

  Exit;                                                                         # Return to operating system
  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:

  Start;
  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 fof syscall
  PrintOutRegisterInHex rax;
  PrintOutRegisterInHex rdi;


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

  PrintOutRegisterInHex rax;
  PrintOutRegisterInHex rdi;

  Exit;                                                                         # Return to operating system
  ok Assemble =~ m(rax:.*08.*rdi:.*9.*rax:.*1.*rdi:.*2.*)s;

ReorderXmmRegisters(@registers) = map {"xmm$_"} @_;)

Map the list of xmm registers provided to 0-31

   Parameter                        Description
1  @registers) = map {"xmm$_"} @_;  Registers

Example:

  Start;
  my $t = GenTree(2,2);                                                         # Tree description
  $t->node->&*;                                                                 # Root
  Movdqa xmm1, xmm0;

  if (1)                                                                        # New left node
   {$t->node->&*;                                                               # Node in xmm0
    Movdqa xmm2, xmm0;                                                          # Left is in xmm2


    ReorderXmmRegisters my @x = (1,0);                                          # Insert left under root  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $t->insertLeft->&*;
    UnReorderXmmRegisters @x;
    $t->dump->("Left");                                                         # Left node after insertion
   }

  if (1)                                                                        # New right node in xmm0
   {$t->node->&*;
    Movdqa xmm3, xmm0;                                                          # Right is in xmm3


    ReorderXmmRegisters my @x = (1,0);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $t->insertRight->&*;
    UnReorderXmmRegisters @x;
    $t->dump->("Right");                                                        # Right node after insertion
   }

  Movdqa xmm0, xmm1;
  $t->dump->("Root");                                                           # Root node after insertions
  $t->isRoot->&*;
  If {PrintOutStringNL "root"} sub {PrintOutStringNL "NOT root"};

  PushR xmm0;                                                                   # Dump underlying  byte string
  PopR rdi, rax;
  $t->byteString->dump;

  Exit;                                                                         # Return to operating system

  is_deeply Assemble, <<END;                                                    # Test tree so produced
Left
ArenaTreeNode at: 0000 0000 0000 00B0
   up: 0000 0000 0000 0010
 left: 0000 0000 0000 0000
right: 0000 0000 0000 0000
Right
ArenaTreeNode at: 0000 0000 0000 0150
   up: 0000 0000 0000 0010
 left: 0000 0000 0000 0000
right: 0000 0000 0000 0000
Root
ArenaTreeNode at: 0000 0000 0000 0010
   up: 0000 0000 0000 0000
 left: 0000 0000 0000 00B0
right: 0000 0000 0000 0150
root
Byte String
  Size: 0000 0000 0000 1000
  Used: 0000 0000 0000 01E0
END

UnReorderXmmRegisters(@registers)

Recover the initial values in the xmm registers that were reordered

   Parameter   Description
1  @registers  Registers

Example:

  Start;
  my $t = GenTree(2,2);                                                         # Tree description
  $t->node->&*;                                                                 # Root
  Movdqa xmm1, xmm0;

  if (1)                                                                        # New left node
   {$t->node->&*;                                                               # Node in xmm0
    Movdqa xmm2, xmm0;                                                          # Left is in xmm2

    ReorderXmmRegisters my @x = (1,0);                                          # Insert left under root
    $t->insertLeft->&*;

    UnReorderXmmRegisters @x;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $t->dump->("Left");                                                         # Left node after insertion
   }

  if (1)                                                                        # New right node in xmm0
   {$t->node->&*;
    Movdqa xmm3, xmm0;                                                          # Right is in xmm3

    ReorderXmmRegisters my @x = (1,0);
    $t->insertRight->&*;

    UnReorderXmmRegisters @x;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    $t->dump->("Right");                                                        # Right node after insertion
   }

  Movdqa xmm0, xmm1;
  $t->dump->("Root");                                                           # Root node after insertions
  $t->isRoot->&*;
  If {PrintOutStringNL "root"} sub {PrintOutStringNL "NOT root"};

  PushR xmm0;                                                                   # Dump underlying  byte string
  PopR rdi, rax;
  $t->byteString->dump;

  Exit;                                                                         # Return to operating system

  is_deeply Assemble, <<END;                                                    # Test tree so produced
Left
ArenaTreeNode at: 0000 0000 0000 00B0
   up: 0000 0000 0000 0010
 left: 0000 0000 0000 0000
right: 0000 0000 0000 0000
Right
ArenaTreeNode at: 0000 0000 0000 0150
   up: 0000 0000 0000 0010
 left: 0000 0000 0000 0000
right: 0000 0000 0000 0000
Root
ArenaTreeNode at: 0000 0000 0000 0010
   up: 0000 0000 0000 0000
 left: 0000 0000 0000 00B0
right: 0000 0000 0000 0150
root
Byte String
  Size: 0000 0000 0000 1000
  Used: 0000 0000 0000 01E0
END

RegisterSize($r)

Return the size of a register

   Parameter  Description
1  $r         Register

Example:

  Start;

  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;

  ReverseBytesInRax;
  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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:

  Start;

  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;
  Exit;
  ok Assemble =~ m(k0: 0000 0000 0000 0008.*k1: 0000 0000 0000 0000)s;

SetRegisterToMinusOne($register)

Set the specified register to -1

   Parameter  Description
1  $register  Register to set

Example:

  Start;

  SetRegisterToMinusOne rax;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  Exit;                                                                         # Return to operating system
  ok Assemble =~ m(rax: FFFF FFFF FFFF FFFF);

SetZF()

Set the zero flag

Example:

  Start;

  SetZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutZF;
  ClearZF;
  PrintOutZF;

  SetZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutZF;

  SetZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutZF;
  ClearZF;
  PrintOutZF;
  Exit;                                                                         # Return to operating system
  ok Assemble =~ m(ZF=1.*ZF=0.*ZF=1.*ZF=1.*ZF=0)s;

ClearZF()

Set the zero flag

Example:

  Start;
  SetZF;
  PrintOutZF;

  ClearZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutZF;
  SetZF;
  PrintOutZF;
  SetZF;
  PrintOutZF;

  ClearZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutZF;
  Exit;                                                                         # Return to operating system
  ok Assemble =~ m(ZF=1.*ZF=0.*ZF=1.*ZF=1.*ZF=0)s;

Structured Programming

Structured programming constructs

If($then, $else)

If

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

Example:

  Start;
  Mov rax, 0;
  Test rax,rax;

  If  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

   {PrintOutRegisterInHex rax;
   } sub
   {PrintOutRegisterInHex rbx;
   };
  Mov rax, 1;
  Test rax,rax;

  If  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

   {PrintOutRegisterInHex rcx;
   } sub
   {PrintOutRegisterInHex rdx;
   };
  Exit;
  ok Assemble =~ m(rbx.*rcx)s;

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

For

   Parameter   Description
1  $body       Body
2  $register   Register
3  $limit      Limit on loop
4  $increment  Increment

Example:

  Start;                                                                        # Start the program

  For  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

   {PrintOutRegisterInHex rax
   } rax, 16, 1;
  Exit;                                                                         # Return to operating system
  my $r = Assemble;
  ok $r =~ m(( 0000){3} 0000)i;
  ok $r =~ m(( 0000){3} 000F)i;

S($body, %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  $body      Body
2  %options   Options.

Example:

  Start;
  Mov rax, 0x44332211;
  PrintOutRegisterInHex rax;


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

   {PrintOutRegisterInHex rax;
    Inc rax;
    PrintOutRegisterInHex rax;
   };

  Call $s;

  PrintOutRegisterInHex rax;
  Exit;
  my $r = Assemble;
  ok $r =~ m(0000 0000 4433 2211.*2211.*2212.*0000 0000 4433 2212)s;

Comment(@comment)

Insert a comment into the assembly code

   Parameter  Description
1  @comment   Text of comment

Example:

  Start;

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

  my $s = "Hello World";
  Mov rax, Rs($s);
  Mov rdi, length $s;
  PrintOutMemory;
  Exit;
  ok Assemble =~ m(Hello World);

Print

Print

PrintOutNL()

Print a new line to stdout

Example:

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

  PrintOutNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

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

  PrintOutNL;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

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

PrintOutString($string)

Print a constant string to sysout.

   Parameter  Description
1  $string    String

Example:

  Start;

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

  Exit;
  ok Assemble =~ m(Hello World);

PrintOutStringNL($string)

Print a constant string to sysout followed by new line

   Parameter  Description
1  $string    String

Example:

  Start;
  my $t = GenTree(2,2);                                                         # Tree description
  $t->node->&*;                                                                 # Root
  Movdqa xmm1, xmm0;

  if (1)                                                                        # New left node
   {$t->node->&*;                                                               # Node in xmm0
    Movdqa xmm2, xmm0;                                                          # Left is in xmm2

    ReorderXmmRegisters my @x = (1,0);                                          # Insert left under root
    $t->insertLeft->&*;
    UnReorderXmmRegisters @x;
    $t->dump->("Left");                                                         # Left node after insertion
   }

  if (1)                                                                        # New right node in xmm0
   {$t->node->&*;
    Movdqa xmm3, xmm0;                                                          # Right is in xmm3

    ReorderXmmRegisters my @x = (1,0);
    $t->insertRight->&*;
    UnReorderXmmRegisters @x;
    $t->dump->("Right");                                                        # Right node after insertion
   }

  Movdqa xmm0, xmm1;
  $t->dump->("Root");                                                           # Root node after insertions
  $t->isRoot->&*;

  If {PrintOutStringNL "root"} sub {PrintOutStringNL "NOT root"};  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


  PushR xmm0;                                                                   # Dump underlying  byte string
  PopR rdi, rax;
  $t->byteString->dump;

  Exit;                                                                         # Return to operating system

  is_deeply Assemble, <<END;                                                    # Test tree so produced
Left
ArenaTreeNode at: 0000 0000 0000 00B0
   up: 0000 0000 0000 0010
 left: 0000 0000 0000 0000
right: 0000 0000 0000 0000
Right
ArenaTreeNode at: 0000 0000 0000 0150
   up: 0000 0000 0000 0010
 left: 0000 0000 0000 0000
right: 0000 0000 0000 0000
Root
ArenaTreeNode at: 0000 0000 0000 0010
   up: 0000 0000 0000 0000
 left: 0000 0000 0000 00B0
right: 0000 0000 0000 0150
root
Byte String
  Size: 0000 0000 0000 1000
  Used: 0000 0000 0000 01E0
END

PrintOutRaxInHex()

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

Example:

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

  PrintOutRaxInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

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

  PrintOutRaxInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

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

ReverseBytesInRax()

Reverse the bytes in rax

Example:

  Start;

  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;


  ReverseBytesInRax;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;

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

  is_deeply Assemble, <<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;

PrintOutRaxInReverseInHex()

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

Example:

  Start;
  Mov rax, 0x07654321;
  Shl rax, 32;
  Or  rax, 0x07654321;
  PrintOutRaxInHex;
  PrintOutNL;

  PrintOutRaxInReverseInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutNL;
  Push rax;
  Mov rax, rsp;
  Mov rdi, 8;
  PrintOutMemoryInHex;
  PrintOutNL;
  Mov rax, 4096;
  Push rax;
  Mov rax, rsp;
  Mov rdi, 8;
  PrintOutMemoryInHex;
  PrintOutNL;
  Exit;
  is_deeply Assemble, <<END;
0765 4321 0765 4321
2143 6507 2143 6507
0765 4321 0765 4321
0010 0000 0000 0000
END

PrintOutRegisterInHex(@r)

Print any register as a hex string

   Parameter  Description
1  @r         Name of the register to print

Example:

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

  PrintOutRegisterInHex r8;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  Exit;
  ok Assemble =~ m(r8: 6867 6665 6463 6261)s;

PrintOutRegistersInHex()

Print the general purpose registers in hex

Example:

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

  PrintOutRegistersInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  Exit;
  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;

PrintOutZF()

Print the zero flag without disturbing it

Example:

  Start;
  SetZF;

  PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  ClearZF;

  PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  SetZF;

  PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  SetZF;

  PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  ClearZF;

  PrintOutZF;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  Exit;                                                                         # Return to operating system
  ok Assemble =~ m(ZF=1.*ZF=0.*ZF=1.*ZF=1.*ZF=0)s;

Processes

Create and manage processes

Fork()

Fork

Example:

  Start;                                                                        # Start the program

  Fork;                                                                         # Fork  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲


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

  Exit;                                                                         # Return to operating system

  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:

  Start;                                                                        # Start the program
  Fork;                                                                         # Fork

  Test rax,rax;
  If                                                                            # Parent
   {Mov rbx, rax;
    WaitPid;
    PrintOutRegisterInHex rax;
    PrintOutRegisterInHex rbx;

    GetPid;                                                                     # Pid of parent as seen in parent  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov rcx,rax;
    PrintOutRegisterInHex rcx;
   }
  sub                                                                           # Child
   {Mov r8,rax;
    PrintOutRegisterInHex r8;

    GetPid;                                                                     # Child pid as seen in child  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov r9,rax;
    PrintOutRegisterInHex r9;
    GetPPid;                                                                    # Parent pid as seen in child
    Mov r10,rax;
    PrintOutRegisterInHex r10;
   };

  Exit;                                                                         # Return to operating system

  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:

  Start;

  GetPidInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  Exit;                                                                         # Return to operating system
  ok Assemble =~ m(rax: 00);

GetPPid()

Get parent process identifier

Example:

  Start;                                                                        # Start the program
  Fork;                                                                         # Fork

  Test rax,rax;
  If                                                                            # Parent
   {Mov rbx, rax;
    WaitPid;
    PrintOutRegisterInHex rax;
    PrintOutRegisterInHex rbx;
    GetPid;                                                                     # Pid of parent as seen in parent
    Mov rcx,rax;
    PrintOutRegisterInHex rcx;
   }
  sub                                                                           # Child
   {Mov r8,rax;
    PrintOutRegisterInHex r8;
    GetPid;                                                                     # Child pid as seen in child
    Mov r9,rax;
    PrintOutRegisterInHex r9;

    GetPPid;                                                                    # Parent pid as seen in child  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Mov r10,rax;
    PrintOutRegisterInHex r10;
   };

  Exit;                                                                         # Return to operating system

  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:

  Start;                                                                        # Start the program

  GetUid;                                                                       # Userid  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  Exit;                                                                         # Return to operating system

  my $r = Assemble;
  ok $r =~ m(rax:( 0000){3});

WaitPid()

Wait for the pid in rax to complete

Example:

  Start;                                                                        # Start the program
  Fork;                                                                         # Fork

  Test rax,rax;
  If                                                                            # Parent
   {Mov rbx, rax;

    WaitPid;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

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

  Exit;                                                                         # Return to operating system

  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:

  Start;
  for(1..10)

   {ReadTimeStampCounter;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;
   }
  Exit;
  my @s = split /
/, Assemble;
  my @S = sort @s;
  is_deeply \@s, \@S;

Stack

Manage data on the stack

Push, Pop, Peek

Generic versions of push, pop, peek

PushR(@r)

Push registers onto the stack

   Parameter  Description
1  @r         Register

Example:

  Start;
  Mov rax, 0x11111111;
  Mov rbx, 0x22222222;

  PushR rax;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  Mov rax, 0x33333333;
  PeekR rbx;
  PopR rax;
  PrintOutRegisterInHex rax;
  PrintOutRegisterInHex rbx;
  Exit;
  ok Assemble =~ m(rax: 0000 0000 1111 1111.*rbx: 0000 0000 1111 1111)s;

PopR(@r)

Pop registers from the stack

   Parameter  Description
1  @r         Register

Example:

  Start;
  Mov rax, 0x11111111;
  Mov rbx, 0x22222222;
  PushR rax;
  Mov rax, 0x33333333;
  PeekR rbx;

  PopR rax;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  PrintOutRegisterInHex rbx;
  Exit;
  ok Assemble =~ m(rax: 0000 0000 1111 1111.*rbx: 0000 0000 1111 1111)s;

PeekR($r)

Peek at register on stack

   Parameter  Description
1  $r         Register

Example:

  Start;
  Mov rax, 0x11111111;
  Mov rbx, 0x22222222;
  PushR rax;
  Mov rax, 0x33333333;

  PeekR rbx;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PopR rax;
  PrintOutRegisterInHex rax;
  PrintOutRegisterInHex rbx;
  Exit;
  ok Assemble =~ m(rax: 0000 0000 1111 1111.*rbx: 0000 0000 1111 1111)s;

Declarations

Declare variables and structures

Structures

Declare a structure

Structure($register)

Create a structure addressed by a register

   Parameter  Description
1  $register  Register locating the structure

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

StructureField::addr($field)

Address a field in a structure

   Parameter  Description
1  $field     Field

All8Structure($base, $N)

Create a structure consisting of 8 byte fields

   Parameter  Description
1  $base      Base register
2  $N         Number of variables required

Stack Frame

Declare local variables in a frame on the stack

LocalData()

Map local data

LocalData::start($local)

Start a local data area on the stack

   Parameter  Description
1  $local     Local data descriptor

LocalData::free($local)

Free a local data area on the stack

   Parameter  Description
1  $local     Local data descriptor

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

LocalVariable::stack($variable)

Address a local variable on the stack

   Parameter  Description
1  $variable  Variable

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

Memory

Allocate and print memory

PrintOutMemoryInHex()

Dump memory from the address in rax for the length in rdi

Example:

  Start;
  Mov rax, 0x07654321;
  Shl rax, 32;
  Or  rax, 0x07654321;
  PrintOutRaxInHex;
  PrintOutNL;
  PrintOutRaxInReverseInHex;
  PrintOutNL;
  Push rax;
  Mov rax, rsp;
  Mov rdi, 8;

  PrintOutMemoryInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutNL;
  Mov rax, 4096;
  Push rax;
  Mov rax, rsp;
  Mov rdi, 8;

  PrintOutMemoryInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutNL;
  Exit;
  is_deeply Assemble, <<END;
0765 4321 0765 4321
2143 6507 2143 6507
0765 4321 0765 4321
0010 0000 0000 0000
END

PrintOutMemory()

Print the memory addressed by rax for a length of rdi

Example:

  Start;
  Comment "Print a string from memory";
  my $s = "Hello World";
  Mov rax, Rs($s);
  Mov rdi, length $s;

  PrintOutMemory;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  Exit;
  ok Assemble =~ m(Hello World);

AllocateMemory()

Allocate the amount of memory specified in rax via mmap and return the address of the allocated memory in rax

Example:

  Start;
  my $N = 2048;
  my $q = Rs('a'..'p');
  Mov rax, $N;

  AllocateMemory;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;

  Vmovdqu8 xmm0, "[$q]";
  Vmovdqu8 "[rax]", xmm0;
  Mov rdi,16;
  PrintOutMemory;
  PrintOutNL;

  Mov rdi, $N;
  FreeMemory;
  PrintOutRegisterInHex rax;
  Exit;
  ok Assemble =~ m(abcdefghijklmnop)s;

  Start;
  my $N = 4096;
  my $S = RegisterSize rax;
  Mov rax, $N;

  AllocateMemory;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  Mov rdi, $N;
  ClearMemory;
  PrintOutRegisterInHex rax;
  PrintOutMemoryInHex;
  Exit;

  my $r = Assemble;
  if ($r =~ m((0000.*0000))s)
   {is_deeply length($1), 9776;
   }

FreeMemory()

Free memory via mmap. The address of the memory is in rax, the length to free is in rdi

Example:

  Start;
  my $N = 2048;
  my $q = Rs('a'..'p');
  Mov rax, $N;
  AllocateMemory;
  PrintOutRegisterInHex rax;

  Vmovdqu8 xmm0, "[$q]";
  Vmovdqu8 "[rax]", xmm0;
  Mov rdi,16;
  PrintOutMemory;
  PrintOutNL;

  Mov rdi, $N;

  FreeMemory;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  Exit;
  ok Assemble =~ m(abcdefghijklmnop)s;

  Start;
  my $N = 4096;
  my $S = RegisterSize rax;
  Mov rax, $N;
  AllocateMemory;
  PrintOutRegisterInHex rax;
  Mov rdi, $N;
  ClearMemory;
  PrintOutRegisterInHex rax;
  PrintOutMemoryInHex;
  Exit;

  my $r = Assemble;
  if ($r =~ m((0000.*0000))s)
   {is_deeply length($1), 9776;
   }

ClearMemory()

Clear memory - the address of the memory is in rax, the length in rdi

Example:

  Start;
  my $N = 4096;
  my $S = RegisterSize rax;
  Mov rax, $N;
  AllocateMemory;
  PrintOutRegisterInHex rax;
  Mov rdi, $N;

  ClearMemory;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  PrintOutMemoryInHex;
  Exit;

  my $r = Assemble;
  if ($r =~ m((0000.*0000))s)
   {is_deeply length($1), 9776;
   }

CopyMemory()

Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi

Files

Process a file

OpenRead()

Open a file, whose name is addressed by rax, for read and return the file descriptor in rax

Example:

  Start;                                                                        # Start the program
  Mov rax, Rs($0);                                                              # File to read

  OpenRead;                                                                     # Open file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  CloseFile;                                                                    # Close file
  PrintOutRegisterInHex rax;

  Mov rax, Rs(my $f = "zzz.txt");                                               # File to write
  OpenWrite;                                                                    # Open file
  CloseFile;                                                                    # Close file
  Exit;                                                                         # Return to operating system

  my $r = Assemble;
  ok $r =~ m(( 0000){3} 0003)i;                                                 # Expected file number
  ok $r =~ m(( 0000){4})i;                                                      # Expected file number
  ok -e $f;                                                                     # Created file
  unlink $f;

OpenWrite()

Create the file named by the terminated string addressed by rax for write

Example:

  Start;                                                                        # Start the program
  Mov rax, Rs($0);                                                              # File to read
  OpenRead;                                                                     # Open file
  PrintOutRegisterInHex rax;
  CloseFile;                                                                    # Close file
  PrintOutRegisterInHex rax;

  Mov rax, Rs(my $f = "zzz.txt");                                               # File to write

  OpenWrite;                                                                    # Open file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  CloseFile;                                                                    # Close file
  Exit;                                                                         # Return to operating system

  my $r = Assemble;
  ok $r =~ m(( 0000){3} 0003)i;                                                 # Expected file number
  ok $r =~ m(( 0000){4})i;                                                      # Expected file number
  ok -e $f;                                                                     # Created file
  unlink $f;

CloseFile()

Close the file whose descriptor is in rax

Example:

  Start;                                                                        # Start the program
  Mov rax, Rs($0);                                                              # File to read
  OpenRead;                                                                     # Open file
  PrintOutRegisterInHex rax;

  CloseFile;                                                                    # Close file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;

  Mov rax, Rs(my $f = "zzz.txt");                                               # File to write
  OpenWrite;                                                                    # Open file

  CloseFile;                                                                    # Close file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  Exit;                                                                         # Return to operating system

  my $r = Assemble;
  ok $r =~ m(( 0000){3} 0003)i;                                                 # Expected file number
  ok $r =~ m(( 0000){4})i;                                                      # Expected file number
  ok -e $f;                                                                     # Created file
  unlink $f;

StatSize()

Stat a file whose name is addressed by rax to get its size in rax

Example:

  Start;                                                                        # Start the program
  Mov rax, Rs($0);                                                              # File to stat

  StatSize;                                                                     # Stat the file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutRegisterInHex rax;
  Exit;                                                                         # Return to operating system

  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));
   }

ReadFile()

Read a file whose name is addressed by rax into memory. The address of the mapped memory and its length are returned in registers rax,rdi

Example:

  Start;                                                                        # Start the program
  Mov rax, Rs($0);                                                              # File to read

  ReadFile;                                                                     # Read file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutMemory;                                                               # Print memory
  Exit;                                                                         # Return to operating system
  my $r = Assemble;                                                             # Assemble and execute
  ok index(removeNonAsciiChars($r), removeNonAsciiChars(readFile $0)) >= 0;     # Output contains this file

Strings

Operations on Strings

CreateByteString()

Create an relocatable string of bytes in an arena and returns its address in rax

Example:

  Start;                                                                        # Start the program

  my $s = CreateByteString;                                                     # Create a string  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  $s->q(my $t = 'ab');                                                          # Append a constant to the byte string
  $s->nl;                                                                       # New line

  Mov rdi, rax;                                                                 # Save source byte string

  CreateByteString;                                                             # Create target byte string  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  $s->copy;                                                                     # Copy source to target

  Xchg rdi, rax;                                                                # Swap source and target byte strings
  $s->copy;                                                                     # Copy source to target
  Xchg rdi, rax;                                                                # Swap source and target byte strings
  $s->copy;


  Xchg rdi, rax;
  $s->copy;
  Xchg rdi, rax;
  $s->copy;

  $s->out;                                                                      # Print byte string

  $s->clear;                                                                    # Clear byte string
  Exit;                                                                         # Return to operating system
  my $T = "$t
" x 8;                                                           # Expected response
  ok Assemble =~ m($T)s;                                                        # Assemble and execute

ByteString::makeReadOnly($byteString)

Make a byte string read only

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::makeWritable($byteString)

Make a byte string writable

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::allocate($byteString)

Allocate the amount of space indicated in rdi in the byte string addressed by rax and return the offset of the allocation in the arena in rdi

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::m($byteString)

Append the content with length rdi addressed by rsi to the byte string addressed by rax

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::q($byteString, $const)

Append a quoted string == a constant to the byte string addressed by rax

   Parameter    Description
1  $byteString  Byte string descriptor
2  $const       Constant

ByteString::ql($byteString, $const)

Append a quoted string containing new line characters to the byte string addressed by rax

   Parameter    Description
1  $byteString  Byte string descriptor
2  $const       Constant

ByteString::char($byteString, $char)

Append a character expressed as a decimal number to the byte string addressed by rax

   Parameter    Description
1  $byteString  Byte string descriptor
2  $char        Decimal number of character to be appended

ByteString::nl($byteString)

Append a new line to the byte string addressed by rax

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::z($byteString)

Append a trailing zero to the byte string addressed by rax

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::rdiInHex()

Add the content of register rdi in hexadecimal in big endian notation to a byte string

ByteString::copy($byteString)

Append the byte string addressed by rdi to the byte string addressed by rax

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::clear($byteString)

Clear the byte string addressed by rax

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::write($byteString)

Write the content in a byte string addressed by rax to a temporary file and replace the byte string content with the name of the temporary file

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::read($byteString)

Read the file named in the byte string (terminated with a zero byte) addressed by rax and place it into the byte string after clearing the byte string to remove the file name contained therein.

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::out($byteString)

Print the specified byte string addressed by rax on sysout

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::bash($byteString)

Execute the file named in the byte string addressed by rax with bash

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::unlink($byteString)

Unlink the file named in the byte string addressed by rax with bash

   Parameter    Description
1  $byteString  Byte string descriptor

ByteString::dump($byteString)

Dump details of a byte string

   Parameter    Description
1  $byteString  Byte string descriptor

GenTree($keyLength, $dataLength)

Generate a set of routines to manage a tree held in a byte string with key and data fields of specified widths. Allocate a byte string to contain the tree, return its address in xmm0=(0, tree).

   Parameter    Description
1  $keyLength   Fixed key length in bytes
2  $dataLength  Fixed data length in bytes

Example:

  Start;

  my $t = GenTree(2,2);                                                         # Tree description  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  $t->node->&*;                                                                 # Root
  Movdqa xmm1, xmm0;

  if (1)                                                                        # New left node
   {$t->node->&*;                                                               # Node in xmm0
    Movdqa xmm2, xmm0;                                                          # Left is in xmm2

    ReorderXmmRegisters my @x = (1,0);                                          # Insert left under root
    $t->insertLeft->&*;
    UnReorderXmmRegisters @x;
    $t->dump->("Left");                                                         # Left node after insertion
   }

  if (1)                                                                        # New right node in xmm0
   {$t->node->&*;
    Movdqa xmm3, xmm0;                                                          # Right is in xmm3

    ReorderXmmRegisters my @x = (1,0);
    $t->insertRight->&*;
    UnReorderXmmRegisters @x;
    $t->dump->("Right");                                                        # Right node after insertion
   }

  Movdqa xmm0, xmm1;
  $t->dump->("Root");                                                           # Root node after insertions
  $t->isRoot->&*;
  If {PrintOutStringNL "root"} sub {PrintOutStringNL "NOT root"};

  PushR xmm0;                                                                   # Dump underlying  byte string
  PopR rdi, rax;
  $t->byteString->dump;

  Exit;                                                                         # Return to operating system

  is_deeply Assemble, <<END;                                                    # Test tree so produced
Left
ArenaTreeNode at: 0000 0000 0000 00B0
   up: 0000 0000 0000 0010
 left: 0000 0000 0000 0000
right: 0000 0000 0000 0000
Right
ArenaTreeNode at: 0000 0000 0000 0150
   up: 0000 0000 0000 0010
 left: 0000 0000 0000 0000
right: 0000 0000 0000 0000
Root
ArenaTreeNode at: 0000 0000 0000 0010
   up: 0000 0000 0000 0000
 left: 0000 0000 0000 00B0
right: 0000 0000 0000 0150
root
Byte String
  Size: 0000 0000 0000 1000
  Used: 0000 0000 0000 01E0
END

Assemble

Assemble generated code

Start()

Initialize the assembler

Example:

  Start;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  PrintOutString "Hello World";
  Exit;
  ok Assemble =~ m(Hello World);

Exit($c)

Exit with the specified return code or zero if no return code supplied

   Parameter  Description
1  $c         Return code

Example:

  Start;
  PrintOutString "Hello World";

  Exit;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

  ok Assemble =~ m(Hello World);

Assemble(%options)

Assemble the generated code

   Parameter  Description
1  %options   Options

Example:

  Start;
  PrintOutString "Hello World";
  Exit;

  ok Assemble =~ m(Hello World);  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

Private Methods

Label()

Create a unique 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

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

ByteString::updateSpace($byteString)

Make sure that the byte string addressed by rax has enough space to accommodate content of length rdi

   Parameter    Description
1  $byteString  Byte string descriptor

removeNonAsciiChars($string)

Return a copy of the specified string with all the non ascii characters removed

   Parameter  Description
1  $string    String

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 amount of memory specified in rax via mmap and return the address of the allocated memory in rax

4 Assemble - Assemble the generated code

5 ByteString::allocate - Allocate the amount of space indicated in rdi in the byte string addressed by rax and return the offset of the allocation in the arena in rdi

6 ByteString::bash - Execute the file named in the byte string addressed by rax with bash

7 ByteString::char - Append a character expressed as a decimal number to the byte string addressed by rax

8 ByteString::clear - Clear the byte string addressed by rax

9 ByteString::copy - Append the byte string addressed by rdi to the byte string addressed by rax

10 ByteString::dump - Dump details of a byte string

11 ByteString::m - Append the content with length rdi addressed by rsi to the byte string addressed by rax

12 ByteString::makeReadOnly - Make a byte string read only

13 ByteString::makeWritable - Make a byte string writable

14 ByteString::nl - Append a new line to the byte string addressed by rax

15 ByteString::out - Print the specified byte string addressed by rax on sysout

16 ByteString::q - Append a quoted string == a constant to the byte string addressed by rax

17 ByteString::ql - Append a quoted string containing new line characters to the byte string addressed by rax

18 ByteString::rdiInHex - Add the content of register rdi in hexadecimal in big endian notation to a byte string

19 ByteString::read - Read the file named in the byte string (terminated with a zero byte) addressed by rax and place it into the byte string after clearing the byte string to remove the file name contained therein.

20 ByteString::unlink - Unlink the file named in the byte string addressed by rax with bash

21 ByteString::updateSpace - Make sure that the byte string addressed by rax has enough space to accommodate content of length rdi

22 ByteString::write - Write the content in a byte string addressed by rax to a temporary file and replace the byte string content with the name of the temporary file

23 ByteString::z - Append a trailing zero to the byte string addressed by rax

24 ClearMemory - Clear memory - the address of the memory is in rax, the length in rdi

25 ClearRegisters - Clear registers by setting them to zero

26 ClearZF - Set the zero flag

27 CloseFile - Close the file whose descriptor is in rax

28 Comment - Insert a comment into the assembly code

29 CopyMemory - Copy memory, the target is addressed by rax, the length is in rdi, the source is addressed by rsi

30 CreateByteString - Create an relocatable string of bytes in an arena and returns its address in rax

31 Db - Layout bytes in the data segment and return their label

32 Dbwdq - Layout data

33 Dd - Layout double words in the data segment and return their label

34 Dq - Layout quad words in the data segment and return their label

35 Ds - Layout bytes in memory and return their label

36 Dw - Layout words in the data segment and return their label

37 Exit - Exit with the specified return code or zero if no return code supplied

38 For - For

39 Fork - Fork

40 FreeMemory - Free memory via mmap.

41 GenTree - Generate a set of routines to manage a tree held in a byte string with key and data fields of specified widths.

42 GetPid - Get process identifier

43 GetPidInHex - Get process identifier in hex as 8 zero terminated bytes in rax

44 GetPPid - Get parent process identifier

45 GetUid - Get userid of current process

46 hexTranslateTable - Create/address a hex translate table and return its label

47 If - If

48 Label - Create a unique label

49 LocalData - Map local data

50 LocalData::allocate8 - Add some 8 byte local variables and return an array of variable definitions

51 LocalData::free - Free a local data area on the stack

52 LocalData::start - Start a local data area on the stack

53 LocalData::variable - Add a local variable

54 LocalVariable::stack - Address a local variable on the stack

55 OpenRead - Open a file, whose name is addressed by rax, for read and return the file descriptor in rax

56 OpenWrite - Create the file named by the terminated string addressed by rax for write

57 PeekR - Peek at register on stack

58 PopR - Pop registers from the stack

59 PrintOutMemory - Print the memory addressed by rax for a length of rdi

60 PrintOutMemoryInHex - Dump memory from the address in rax for the length in rdi

61 PrintOutNL - Print a new line to stdout

62 PrintOutRaxInHex - Write the content of register rax to stderr in hexadecimal in big endian notation

63 PrintOutRaxInReverseInHex - Write the content of register rax to stderr in hexadecimal in little endian notation

64 PrintOutRegisterInHex - Print any register as a hex string

65 PrintOutRegistersInHex - Print the general purpose registers in hex

66 PrintOutRflagsInHex - Print the flags register in hex

67 PrintOutRipInHex - Print the instruction pointer in hex

68 PrintOutString - Print a constant string to sysout.

69 PrintOutStringNL - Print a constant string to sysout followed by new line

70 PrintOutZF - Print the zero flag without disturbing it

71 PushR - Push registers onto the stack

72 Rb - Layout bytes in the data segment and return their label

73 Rbwdq - Layout data

74 Rd - Layout double words in the data segment and return their label

75 ReadFile - Read a file whose name is addressed by rax into memory.

76 ReadTimeStampCounter - Read the time stamp counter and return the time in nanoseconds in rax

77 RegisterSize - Return the size of a register

78 removeNonAsciiChars - Return a copy of the specified string with all the non ascii characters removed

79 ReorderSyscallRegisters - Map the list of registers provided to the 64 bit system call sequence

80 ReorderXmmRegisters - Map the list of xmm registers provided to 0-31

81 RestoreFirstFour - Restore the first 4 parameter registers

82 RestoreFirstFourExceptRax - Restore the first 4 parameter registers except rax so it can return its value

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

84 RestoreFirstSeven - Restore the first 7 parameter registers

85 RestoreFirstSevenExceptRax - Restore the first 7 parameter registers except rax which is being used to return the result

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

87 ReverseBytesInRax - Reverse the bytes in rax

88 Rq - Layout quad words in the data segment and return their label

89 Rs - Layout bytes in read only memory and return their label

90 Rw - Layout words in the data segment and return their label

91 S - 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

92 SaveFirstFour - Save the first 4 parameter registers

93 SaveFirstSeven - Save the first 7 parameter registers

94 SetLabel - Set a label in the code section

95 SetRegisterToMinusOne - Set the specified register to -1

96 SetZF - Set the zero flag

97 Start - Initialize the assembler

98 StatSize - Stat a file whose name is addressed by rax to get its size in rax

99 Structure - Create a structure addressed by a register

100 Structure::field - Add a field of the specified length with an optional comment

101 StructureField::addr - Address a field in a structure

102 UnReorderSyscallRegisters - Recover the initial values in registers that were reordered

103 UnReorderXmmRegisters - Recover the initial values in the xmm registers that were reordered

104 WaitPid - Wait for the pid in rax to complete

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.