Generate and run x64 Advanced Vector Extensions assembler programs from Perl

Test

This Perl module generates and runs x64 Advanced Vector Extensions assembler programs using Perl as a powerful macro assembler. It contains methods to perform useful macro functions such as dumping x/y/zmm* registers to facilitate the debugging of the generated programs or interacting with the operating system.

The GitHub Action in this repo shows how to install nasm and the Intel Software Development Emulator used to assemble and then run the programs generated by this module.

Test cases can be seen at the end of file lib/Nasm/X86.pm. The test cases are run by the GitHub Action.

This module is part of the Perl Zero project: using Perl 5 to create a minimal, modern version of Perl which generates x86 assembler code directly. Perl Zero is process friendly: every data structure used is completely relocatable and so can be moved directly between different processes via a file or a socket. A Perl Zero program is a single expression with no key words: only user defined infix operators and expressions are used to construct programs. Perl Zero leverages Perl 5 as its macro assembler and CPAN as its module repository. Please feel free to join in.

Useful links

Avx512 instructions

Use Advanced Vector Extensions 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](https://en.wikipedia.org/wiki/Computer_program) to execute
#!/usr/bin/bash
whoami
ls -la
pwd
END

  $s->write;                                                                    # Write [code](https://en.wikipedia.org/wiki/Computer_program) to a temporary [file](https://en.wikipedia.org/wiki/Computer_file) 
  $s->bash;                                                                     # Execute the temporary [file](https://en.wikipedia.org/wiki/Computer_file) 
  $s->unlink;                                                                   # Execute the temporary [file](https://en.wikipedia.org/wiki/Computer_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](https://en.wikipedia.org/wiki/Computer_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](https://perldoc.perl.org/perlsub.html)                                                                           # 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](https://en.wikipedia.org/wiki/Fork_(system_call)) 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](https://en.wikipedia.org/wiki/Fork_(system_call)) 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 and print it out

Read this file and print it out:

Start;                                                                        # Start the [program](https://en.wikipedia.org/wiki/Computer_program)   Mov rax, Rs($0);                                                              # File to read
ReadFile;                                                                     # Read [file](https://en.wikipedia.org/wiki/Computer_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](https://en.wikipedia.org/wiki/Computer_file)   ```


For documentation see: [CPAN](https://metacpan.org/pod/Nasm::X86)