NAME

Inline::ASM - Write Perl Subroutines in assembler.

SYNOPSIS

   print "9 + 16 = ", add(9, 16), "\n";
   print "9 - 16 = ", subtract(9, 16), "\n";

   use Inline ASM => 'DATA', 
	      AS => 'as',
	      PROTO => {add => 'int(int,int)'};

   use Inline ASM => 'DATA',
	      AS => 'nasm',
	      ASFLAGS => '-f elf',
	      PROTO => {subtract => 'int(int,int)'};

   __END__
   __ASM__

   .text
   .globl    add

   add:      movl 4(%esp),%eax
             addl 8(%esp),%eax
             ret
   __ASM__
	     GLOBAL subtract
	     SECTION .text

   subtract: mov eax,[esp+4]
             sub eax,[esp+8]
             ret

DESCRIPTION

Inline::ASM allows you to write Perl subroutines in assembly language. Of course, many C compilers allow you to put assembly right in your C code, so this module does not provide any new functionality. It does, however, provide a feature most C compilers don't: you can mix different assembler syntaxes in the same file!

Using Inline::ASM

Inline::ASM is almost exactly the same as Inline::C. It makes sure the globals you requested are declared global, compiles the source code and the XS wrappers, and then creates one loadable module for each code segment.

There are some shortcomings of extending Perl with assembly. Perl is written in C (and Perl), and makes heavy use of macros to provide a consistent API when it's compiled with different options. For example, the C programmer usually doesn't care if Perl is compiled with threads or without, because the all API calls are resolved to a particular Perl interpreter using macros.

Inline::ASM tries to make your life simpler by overloading the PROTO or PROTOTYPE hints to do some menial macro processing for you. See ASM Configuration Options, below.

Function Definitions

Inline::C uses a Parse::RecDescent grammar to find function definitions in C code. Because assembler is a much simpler syntax, and both NASM and GNU AS have pseudo-ops for declaring global symbols, Inline::ASM runs your code through a regular expression to search for the pseudo-ops.

For example, in NASM, you declare global symbols like so:

           GLOBAL myfunction
   myfunction:
	   mov eax,10

In GNU AS, you declare global symbols like so:

.globl myfunction
myfunction:
        mov $10,%eax

Inline::C gets all the information it needs from your C code. In particular, it's easy to find out what to pass a function, because the function header tells you:

void foo(int a, char *b) { ... }

The corresponding assembler code doesn't tell you very much:

foo:

So Inline::ASM will only bind to symbols you ask for via the PROTO option. PROTO simply gives Inline::ASM the rest of the information about the symbol. It won't make any difference to the assembler code, but it will allow Perl to bind to it.

ASM Configuration Options

For information on how to specify Inline configuration options, see Inline. This section describes the configuration options only available for Inline::ASM. All Inline and Inline::C options are also supported. See Inline::C for additional information.

AS

Specifies the assembler command to use. Can also be used to specify flags; in the case of the GASP assembler, you must specify flags here. Any flags in ASFLAGS will be passed to GNU as, rather than GASP.

ASFLAGS

Specifies flags to pass to the assembler.

Supported Assemblers

These assemblers have been tested with Inline::ASM:

  1. GNU AS

    GNU AS is a bare-bones assembler with no macro support. It works fine.

  2. GASP (GNU Assembler Preprocessor)

    GASP is a macro preprocessor designed to emit code for AS to assembler. This system works fine, except that in order to pass options to 'gasp' you must specify them in the AS configuration option, rather than ASFLAGS. The ASFLAGS are passed only to GNU as, which is automatically invoked on the output of running the GASP preprocessor.

  3. NASM (Netwide Assembler)

    NASM is an assembler with Intel syntax which works in Linux and Windows. Unfortunately,

ASM-Perl Bindings

This section describes how the `Perl' variables get mapped to `ASM' variables and back again.

Brian Ingersion (INGY@cpan.org) gives a very good description of how Perl types are translated to C types and back. That discussion is relevant to the way Inline::ASM works too, since all your variables pass through a C layer (XS) before getting to Assembler, and again on their way back to Perl. See Inline::C for that diatribe.

The biggest difference between Inline::C and Inline::ASM is that you don't get the luxury of sitting in a macro-rich C environment. You have to do some work.

The Perl API in Assembler (EXPERIMENTAL)

If you're using any Perl API calls, you need to pass a special variable to your assembler function: pTHX. This is actually a macro in C land, magically passed to all API calls. For example, this harmless snippet of C code:

return newSVpv("Hello, World!", 0);

is really doing this:

return Perl_newSVpv(aTHX_ "Hello, World!", 0);

Depending on your setup, aTHX_ might be undefined, empty, or a PerlInterpreter structure. In the perl that ships with RedHat Linux 6.2, this becomes:

return Perl_newSVpv("Hello, World!", 0);

aTHX_ is a C macro which, depending on your setup, defines either a Perl interpreter or nothing. On perl 5.005_03 on my RedHat 6.2 box, aTHX_ is resolved to "". With ActivePerl 623, aTHX_ resolves to some pthreads calls which get the currently running interpeter.

Your assembler code doesn't know anything about Perl, so the user-level API is not available. You need to explicitly call Perl_newSVpv, passing it a Perl interpreter if your Perl expects one.

You can test if Perl wants a parameter running this code:

use Inline C => <<END;
void foo(pTHX_ int a) {
   printf("This perl interpreter is defined: %p\n", aTHX);
   return Perl_newSViv(aTHX_ a);
};
END

If the code compiles, Perl has been configured to pass a PerlInterpreter using the macros aTHX and pTHX. If the code fails because the macros weren't defined, or because of a parse error on the printf line, then the Perl interpreter is kept in a global variable and the macros aren't required.

You can get Inline::ASM to pass the Perl parameter to your assembler function by asking for it like this:

   print "9 + 16 = ", add(9, 16), "\n";

   use Inline ASM => 'DATA',
	      AS => 'as',
	      PROTO => {add => 'SV*(pTHX,int,int)};

   __END__

   .text
   .globl    add
   .extern   Perl_newSViv

   add:      movl 4(%esp),%ebx
             movl 8(%esp),%eax
             addl 12(%esp),%eax
	     pushl %eax
	     pushl %ebx
	     call Perl_newSViv
	     leave
             ret

Note that if your Perl configuration doesn't define the pTHX macro, this will cause a compile error. So basically you can't write portable assembler extensions.

Of course, if you want a portable solution, use Inline::C.

Examples

Example #1 - Greetings

This example takes a string argument (a name) and prints a greeting. The function is called with a string, then a number. Perl forces the number to a string.

   greet('Ingy');
   greet(42);

   use Inline ASM => <<'END', PROTO => { greet => 'void(char*)'};

   .data
   gstr:   .string "Hello %s!\n"

   .text
   .globl  greet

   greet:  movl 4(%esp),%eax
	   pushl %eax
	   pushl $gstr
	   call printf
	   leave
	   ret
   END

SEE ALSO

For general information about Inline see Inline.

For information on supported languages and platforms see Inline::Support.

For information on writing your own Inline Language Support Module, see Inline-API.

Inline's mailing list is inline@perl.org

To subscribe, send email to inline-subscribe@perl.org

WARNING

Do NOT use assembler to write Perl extensions! It's sick and wrong!

AUTHOR

Neil Watkiss <NEILW@cpan.org>

COPYRIGHT

Copyright (c) 2001, Neil Watkiss.

All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.

(see http://www.perl.com/perl/misc/Artistic.html)