tokuhirom's blog.

'; DROP DATABASE database();

Perl5 のスタック

phg

唐突ですが、perl5 のスタックについて解説します。Perl5 は stack machine なので、何本かのスタックがあります。これらは構造体 my_perl の中にはいっていて、ithread ありの場合には引数でひきまわされ、なしの場合には global 変数になります。

argument stack

  • stack_sp
  • stack_base
  • stack_max
中身
SV*

引数/返り値のひきわたしなどにつかうメインスタックです。

savestack

  • savestack
  • savestack_ix
  • savestack_max
中身
ANY *

スコープにはいったときに保存して、でるときにリストアするようなデータを一時保存するためのスタックである。

scope の中では、SAVEINT, SAVEI8 などのマクロをつかって、ポインタと元の値を savestack につむことができる。ここでセーブされた値は、スコープをぬけるときに元にもどる。

scope にはいる際に scopestack に現在のインデックスが push され、でるときに pop される。この際、スコープの中でセーブスタックがのびていれば、そのセーブされた値はリストアされる。

スコープスタック

  • scopestack
  • scopestack_ix
  • scopestack_max
中身
savestack_ix

scope に enter したときにつまれる。enter すると、push_scope(); がよばれ、scopestack に現在の savestack_ix の値が push される。

leave したときに pop される。この時の savestack_ix の値が、pop したものよりも大きいと、scope.c の Perl_leave_scope が呼ばれる。

scope にはいる際に scopestack に現在のインデックスが push され、でるときに pop される。この際、スコープの中でセーブスタックがのびていれば、そのセーブされた値はリストアされる。

一時変数スタック

  • tmps_stack
  • tmps_ix
  • tmps_floor
  • tmps_max

一時変数を保存するためのスタックである。XS について詳しい人ならば、mortal 変数というとわかりやすいに違いない。mortal な変数がつまれる領域がここである。

ここに詰まれた変数は、スコープからぬけるときに開放される。XS のマクロでいうと FREETMPS; にあたる。FREETMPS は scope.c の Perl_free_tmps を呼ぶことになる。

markstack

  • markstack
  • markstack_ptr
  • markstack_max
中身
stack pointer

スタックマーカ変数である。関数コールの際につかわれる。

markstack には現在のスタックポインタ(sp)の位置を push しておく。その後、XPUSHs() などで引数スタックにどんどん値を push していく。そして関数をすかさずコールする。コールされた関数の中で markstack を pop する。これにより、どこまでが引数かがわかるというわけ。

これにかかわるマクロは以下の2つだ。これらは pp.h に定義されている(push-pop.h の略だとおもう)

    #define PUSHMARK(p)     \
        STMT_START {                                    \
            if (++PL_markstack_ptr == PL_markstack_max) \
            markstack_grow();                           \
            *PL_markstack_ptr = (I32)((p) - PL_stack_base);\
        } STMT_END
    #define POPMARK         (*PL_markstack_ptr--)

XSUB を書く場合につかう dAXMARK; がまさに POPMARK; している(実際には直接 dAXMARK を呼ぶことはなくて、dXSARGS を呼ぶのだが、dXSARGS が中で dAXMARK をよんでいる)。

    #define dAXMARK                         \
        I32 ax = POPMARK;       \
        register SV **mark = PL_stack_base + ax++

curstack

  • curstack
  • curstackinfo
  • mainstack(curstack の base)

stackinfo 構造体がつまれれている。現在のコンテキスト情報がはいっている。詳細は後で。

libbfd を perl からつかってみました

http://github.com/tokuhirom/p5-devel-bfd/tree/master

libbfd は GNU binutils のバックエンドライブラリで、バイナリアンの人が楽をするためのツールと聞きおよんでおります。

というわけで、perl からよべるライブラリをつくってみた。んでもって、nm みたいなのを適当に実装してみました。nm が実装できるぶんの機能しか実装してないですが。

use strict;
use warnings;
use Devel::BFD;

my $fname = shift @ARGV or die "Usage: $0 path/to/libs.a";
my $f = Devel::BFD->openr($fname);
my @table = $f->symtable();
for my $row (@table) {
    printf "%08X %s\n", $row->{value}, $row->{name};
}

得に使い道があるとはおもいませんが、Perl をつかって nm したいという欲望に耐えられないときなどにご利用ください。