Generate and run x64 Advanced Vector Extensions assembler programs from Perl


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. Full documentation is available on CPAN.

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/ and in the t folder. The test cases are run by the GitHub Action at steps Test and Prove.

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 expressions constructed from user defined unary and binary operators 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 add and subtract bytes using 512 bit zmm registers:

``` my $a = Vz a, Rb((map {"0x${}0"} 0..9, 'a'..'f')x4); my $b = Vz b, Rb((map {"0x0${}"} 0..9, 'a'..'f')x4);

$a ->loadZmm(0); # Show variable in zmm0 $b ->loadZmm(1); # Show variable in zmm1

($a + $b)->loadZmm(2); # Add bytes and show in zmm2 ($a - $b)->loadZmm(3); # Subtract bytes and show in zmm3

PrintOutRegisterInHex "zmm$_" for 0..3;

is_deeply Assemble, <

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:

``` use Nasm::X86 qw(:all);

my $s = CreateByteString; # Create a string $s->ql(<code to execute


whoami ls -lapwd END

$s->write; # Write code to a temporary file $s->bash; # Execute the temporary file $s->unlink; # Unlink the temporary file my $u = qx(whoami); chomp($u); # Check we got the expected response ok Assemble =~ m($u); # Assemble, run, test output ```

Process management

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

``` use Nasm::X86 qw(:all);

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

my $r = Assemble; # Assemble test and run

# 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 and print it out

Read this file and print it out:

``` use Nasm::X86 qw(:all);

Mov rax, Rs($0); # File to read ReadFile; # Read file PrintOutMemory; # Print memory my $r = Assemble; # Assemble and execute ok index($r, readFile($0)) > -1; # Output contains this file ```

Call functions in Libc

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

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

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

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

ok Assemble(eq => <

For documentation see: CPAN