Inline::ASM

perlから他言語を使うInlineモジュールの中にアセンブリを扱う
Inline::ASMがあることは以前から知っていたのですが、使ったことはありませんでした。
Inline::ASM - Write Perl Subroutines in assembler. - metacpan.org
ためしに触ってみたらすんなり動かすことが出来なかったのでメモ。

SYNOPSISを信じて下のコードを動かしたらエラーが出ました。
(Win7 + Strawberry Perl + nasm)

#!perl
print "9 + 16 = ", add(9, 16), "\n";
use Inline ASM => 'DATA',
           AS => 'nasm',
           PROTO => {add => 'int(int,int)'};

__DATA__
__ASM__
global add
section .text
add:
    mov eax,[esp+4]
    add eax,[esp+8]
    ret

エラー
error_pl_fbdc.o:error_pl_fbdc.c:(.text+0x601): undefined reference to `add'

アセンブリコードのシンボル名にアンダースコアつけないとダメかなと思って
つけてみましたが、また別のエラーが・・・。

エラー
Use of inherited AUTOLOAD for non-method main::add() is deprecated at error.pl line 2.

アンダースコアつけてないヤツもglobalしなきゃだめか?と思って追加してみたところうまくいきました。

#!perl
print "9 + 16 = ", add(9, 16), "\n";
use Inline ASM => 'DATA',
           AS => 'nasm',
           PROTO => {add => 'int(int,int)'};

__DATA__
__ASM__
global _add
global add
section .text
_add:
    mov eax,[esp+4]
    add eax,[esp+8]
    ret

出力
9 + 16 = 25

おまけでHello, World!しておきました。

#!perl
use DynaLoader;
my $path = "$ENV{SystemRoot}\\system32\\user32.dll";
my $libref = DynaLoader::dl_load_file($path);
my $sym = DynaLoader::dl_find_symbol($libref, "MessageBoxA");

call_msgbox($sym, 0, "title", "Hello, World!", 0); 
use Inline ASM => 'DATA',
           AS => 'nasm',
           PROTO => {call_msgbox => 'void(long,long,char*,char*,long)'};
__END__
__ASM__
GLOBAL _call_msgbox
GLOBAL call_msgbox
SECTION .text
_call_msgbox:
    mov ebx,esp
    mov eax,[ebx+4]
    push dword [ebx+8]
    push dword [ebx+12]
    push dword [ebx+16]
    push dword [ebx+20]
    call eax
    ret