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:
GNU AS
GNU AS is a bare-bones assembler with no macro support. It works fine.
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.
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)