# Generate and run [x64](https://en.wikipedia.org/wiki/X86-64) [Advanced Vector Extensions](https://en.wikipedia.org/wiki/AVX-512) assembler programs from [Perl](http://www.perl.org/) 

![Test](https://github.com/philiprbrenan/Nasmx86/workflows/Test/badge.svg)


This [Perl](http://www.perl.org/) [module](https://en.wikipedia.org/wiki/Modular_programming) generates and runs [x64](https://en.wikipedia.org/wiki/X86-64) [Advanced Vector Extensions](https://en.wikipedia.org/wiki/AVX-512) assembler programs using [Perl](http://www.perl.org/) 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](https://metacpan.org/pod/Nasm::X86).


The [GitHub Action](https://docs.github.com/en/free-pro-team@latest/actions/quickstart) in this repo shows how to [install](https://en.wikipedia.org/wiki/Installation_(computer_programs)) [nasm](https://github.com/netwide-assembler/nasm) and the [Intel Software Development Emulator](https://software.intel.com/content/www/us/en/develop/articles/intel-software-development-emulator.html) used
to assemble and then run the programs generated by this [module](https://en.wikipedia.org/wiki/Modular_programming). 

Test cases can be seen at the end of [file](https://en.wikipedia.org/wiki/Computer_file) [lib/Nasm/X86.pm](https://github.com/philiprbrenan/NasmX86/blob/main/lib/Nasm/X86.pm).
The [test](https://en.wikipedia.org/wiki/Software_testing) cases are run by the
[githubaction](https://github.com/philiprbrenan/NasmX86/blob/main/.github/workflows/main.yml#L54)
at
[this](https://github.com/philiprbrenan/NasmX86/blob/ca87d729f32a89cbbe97d5ce9112f9cf614ccb23/.github/workflows/main.yml#L54.)
step.


This [module](https://en.wikipedia.org/wiki/Modular_programming) provides Dynamic [string](https://en.wikipedia.org/wiki/String_(computer_science)), [array](https://en.wikipedia.org/wiki/Dynamic_array), [tree](https://en.wikipedia.org/wiki/Tree_(data_structure)) and Quarks in [arena](https://en.wikipedia.org/wiki/Region-based_memory_management): every data
structure is [process](https://en.wikipedia.org/wiki/Process_management_(computing)) friendly because the Arenas are completely [relocatable](https://en.wikipedia.org/wiki/Relocation_%28computing%29) and
so can be moved directly between different processes via a [file](https://en.wikipedia.org/wiki/Computer_file) or a socket.


Please feel free to join in with this interesting project - we need all the [help](https://en.wikipedia.org/wiki/Online_help) we can get.

# Useful links

- [x86 instructions](https://hjlebbink.github.io/x86doc/)

- [Avx512 SIMD x86 instructions](https://www.officedaytime.com/simd512e/)

- [Linux system calls](https://filippo.io/linux-syscall-table/)

- [Linux error codes](https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html)

- [Network wide assembler](https://www.nasm.us/xdoc/2.15.05/html/nasmdoc0.html)

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

- [Ascii table](https://www.asciitable.com/)


# Avx512 instructions

Use [Advanced Vector Extensions](https://en.wikipedia.org/wiki/AVX-512) 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, <<END;
  zmm0: F0E0 D0C0 B0A0 9080   7060 5040 3020 1000   F0E0 D0C0 B0A0 9080   7060 5040 3020 1000   F0E0 D0C0 B0A0 9080   7060 5040 3020 1000   F0E0 D0C0 B0A0 9080   7060 5040 3020 1000
  zmm1: 0F0E 0D0C 0B0A 0908   0706 0504 0302 0100   0F0E 0D0C 0B0A 0908   0706 0504 0302 0100   0F0E 0D0C 0B0A 0908   0706 0504 0302 0100   0F0E 0D0C 0B0A 0908   0706 0504 0302 0100
  zmm2: FFEE DDCC BBAA 9988   7766 5544 3322 1100   FFEE DDCC BBAA 9988   7766 5544 3322 1100   FFEE DDCC BBAA 9988   7766 5544 3322 1100   FFEE DDCC BBAA 9988   7766 5544 3322 1100
  zmm3: E1D2 C3B4 A596 8778   695A 4B3C 2D1E 0F00   E1D2 C3B4 A596 8778   695A 4B3C 2D1E 0F00   E1D2 C3B4 A596 8778   695A 4B3C 2D1E 0F00   E1D2 C3B4 A596 8778   695A 4B3C 2D1E 0F00
END
```


# Dynamic [string](https://en.wikipedia.org/wiki/String_(computer_science)) held in an [arena](https://en.wikipedia.org/wiki/Region-based_memory_management) 

Create a dynamic byte [string](https://en.wikipedia.org/wiki/String_(computer_science)), add some content to it, write the byte [string](https://en.wikipedia.org/wiki/String_(computer_science)) to
a [file](https://en.wikipedia.org/wiki/Computer_file) and then execute it:

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

  my $s = CreateByteString;          # Create a [string](https://en.wikipedia.org/wiki/String_(computer_science))   $s->ql(<<END);                     # Write [code](https://en.wikipedia.org/wiki/Computer_program) to execute
#!/usr/bin/bash
whoami
ls -lapwd
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;                        # Unlink the temporary [file](https://en.wikipedia.org/wiki/Computer_file) 
  my $u = qx(whoami); chomp($u);     # Check we got the expected response
  ok Assemble =~ m($u);              # Assemble, run, [test](https://en.wikipedia.org/wiki/Software_testing) output
```


# Process management


Start a child [process](https://en.wikipedia.org/wiki/Process_management_(computing)) and wait for it, printing out the [process](https://en.wikipedia.org/wiki/Process_management_(computing)) identifiers of
each [process](https://en.wikipedia.org/wiki/Process_management_(computing)) 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](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;
   };

  my $r = Assemble;              # Assemble [test](https://en.wikipedia.org/wiki/Software_testing) and run

  #    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](https://en.wikipedia.org/wiki/Computer_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](https://en.wikipedia.org/wiki/Computer_file) 
  PrintOutMemory;                                                               # Print [memory](https://en.wikipedia.org/wiki/Computer_memory) 
  my $r = Assemble;                                                             # Assemble and execute
  ok index($r, readFile($0)) > -1;                                              # Output contains this [file](https://en.wikipedia.org/wiki/Computer_file) 
```

# Call functions in Libc

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

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

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

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

  ok Assemble(eq => <<END);
Hello World
END
```


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