The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

Name

Nasm::X86 - Generate Nasm assembler code

Synopsis

Write and execute x64 instructions from perl, 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 and then print it.

  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

  Exit;                                                                         # Return to operating system
  Assemble =~ m(("$t\n" x 8))s;                                                 # Assemble and execute

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 "202104014".

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

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

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

RestoreFirstFour()

Restore the first 4 parameter registers

RestoreFirstFourExceptRax()

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

SaveFirstSeven()

Save the first 7 parameter registers

RestoreFirstSeven()

Restore the first 7 parameter registers

RestoreFirstSevenExceptRax()

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

RestoreFirstSevenExceptRaxAndRdi()

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

RegisterSize($r)

Return the size of a register

     Parameter  Description
  1  $r         Register

ClearRegisters(@registers)

Clear registers by setting them to zero

     Parameter   Description
  1  @registers  Registers

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()

Write a new line

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)

Write a constant string to sysout.

     Parameter  Description
  1  $string    String

Example:

    Start;

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

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

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

PrintOutRaxInReverseInHex()

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

Example:

    Start;
    Mov rax, 0x88776655;
    Shl rax, 32;
    Or  rax, 0x44332211;
    PrintOutRaxInHex;

    PrintOutRaxInReverseInHex;  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    Exit;
    ok Assemble =~ m(8877 6655 4433 2211 1122 3344 5566 7788)s;

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;

PrintOutRipInHex()

Print the instruction pointer in hex

PrintOutRflagsInHex()

Print the flags register in hex

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;

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

    Start;                                                                        # Start the program
    GetUid;                                                                       # Userid
    PrintOutRegisterInHex rax;
    Exit;                                                                         # Return to operating system
    my $r = Assemble;
    ok $r =~ m(rax:( 0000){3});

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

    Start;                                                                        # Start the program
    GetUid;                                                                       # Userid
    PrintOutRegisterInHex rax;
    Exit;                                                                         # Return to operating system
    my $r = Assemble;
    ok $r =~ m(rax:( 0000){3});

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

    Start;                                                                        # Start the program
    GetUid;                                                                       # Userid
    PrintOutRegisterInHex rax;
    Exit;                                                                         # Return to operating system
    my $r = Assemble;
    ok $r =~ m(rax:( 0000){3});

GetUid()

Get userid of current process

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

    Start;                                                                        # Start the program
    GetUid;                                                                       # Userid
    PrintOutRegisterInHex rax;
    Exit;                                                                         # Return to operating system
    my $r = Assemble;
    ok $r =~ m(rax:( 0000){3});

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

PopR(@r)

Pop registers from the stack

     Parameter  Description
  1  @r         Register

PeekR($r)

Peek at register on stack

     Parameter  Description
  1  $r         Register

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

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

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

ClearMemory()

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

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 stat

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

    PrintOutRegisterInHex rax;
    Close(rax);                                                                   # Close file
    PrintOutRegisterInHex rax;
    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

Close($fdes)

Close a file descriptor

     Parameter  Description
  1  $fdes      File descriptor

Example:

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

    Close(rax);                                                                   # Close file  # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲

    PrintOutRegisterInHex rax;
    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

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($r =~ s([^0x0-0x7f]) ()gsr, readFile($0) =~ s([^0x0-0x7f]) ()gsr)>-1;# 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 $q = Rs my $t = 'ab';

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

    Mov rsi, $q;                                                                  # Address of memory to copy
    Mov rdi, length $t;                                                           # Length of memory  to copy
    $s->m;                                                                        # Copy memory into byte string

    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

    Exit;                                                                         # Return to operating system
    Assemble =~ m(($t x 8));                                                      # Assemble and execute

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::copy($byteString)

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

     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

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

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

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::copy - Append the byte string addressed by rdi to the byte string addressed by rax

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

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

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

9 ClearRegisters - Clear registers by setting them to zero

10 Close - Close a file descriptor

11 Comment - Insert a comment into the assembly code

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

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

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

15 Dbwdq - Layout data

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

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

18 Ds - Layout bytes in memory and return their label

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

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

21 For - For

22 Fork - Fork

23 FreeMemory - Free memory via mmap.

24 GetPid - Get process identifier

25 GetPPid - Get parent process identifier

26 GetUid - Get userid of current process

27 If - If

28 Label - Create a unique label

29 LocalData - Map local data

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

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

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

33 LocalData::variable - Add a local variable

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

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

36 PeekR - Peek at register on stack

37 PopR - Pop registers from the stack

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

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

40 PrintOutNl - Write a new line

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

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

43 PrintOutRegisterInHex - Print any register as a hex string

44 PrintOutRegistersInHex - Print the general purpose registers in hex

45 PrintOutRflagsInHex - Print the flags register in hex

46 PrintOutRipInHex - Print the instruction pointer in hex

47 PrintOutString - Write a constant string to sysout.

48 PushR - Push registers onto the stack

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

50 Rbwdq - Layout data

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

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

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

54 RegisterSize - Return the size of a register

55 RestoreFirstFour - Restore the first 4 parameter registers

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

57 RestoreFirstSeven - Restore the first 7 parameter registers

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

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

60 ReverseBytesInRax - Reverse the bytes in rax

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

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

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

64 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

65 SaveFirstFour - Save the first 4 parameter registers

66 SaveFirstSeven - Save the first 7 parameter registers

67 SetLabel - Set a label in the code section

68 Start - Initialize the assembler

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

70 Structure - Create a structure addressed by a register

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

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

73 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.