CELLプロセッサ--libc 解析 take.3 (可変引数関数)

HOME > 社内活動 > CELLプロセッサ > cell > libc > libc 解析 take.3 (可変引数関数)

libc 解析 take.3 (可変引数関数)-CELLプロセッサ

topics

"PPE Serviced SPE C Library Functions" ...

image

"PPE Serviced SPE C Library Functions" の 3 回目、可変引数関数の場合 について解説します。

可変引数関数の場合

以下は fprintf() を例に説明します。まずは、生成されたソースコード (fprintf.S) です。

#include "spe_c99_ops.h"
#include "spe_posix1_ops.h"

#define OPCLASS SPE_C99_CLASS
#define NAME    fprintf
#define PARMS   2
#define OPCODE  SPE_C99_VFPRINTF
#define RETVAL  1

#include "spu_syscall_va.S"

非可変引数関数の場合は spu_syscall.S をインクルードしていましたが、可 変引数関数の場合は spu_syscall_va.S をインクルードしています。

注意すべき点としては、非可変引数関数と同様に命令列をスタック上にセー ブして、このスタック上の命令が実行されること以外にも、

可変引数関数の場合、引数がどれだけあるかわからないので、引数の書いて ある可能性のあるレジスタ (つまり全ての揮発性レジスタ) を全てスタックにセー ブする必要があります。

レジスタをセーブする命令もスタック上で実行されますが、メモリ使用量を 削減するため?に命令自体の書き換えを行っています。

これらのレジスタは va_list 形式 (パラメータと呼び出し関数のスタックへ のアドレス) で管理。

というところでしょうか。では実際に逆アセ結果を見てみます。まず前半の レジスタをセーブする部分です。

00000000 :
 0:   40 fd 70 02     il      $2,-1312     // save_regs_1: の命令列へのスタック相対値をロード
 4:   24 ff c0 cf     stqd    $79,-16($1)  // 内部使用するレジスタの値を先にセーブ
 8:   24 ff 80 ce     stqd    $78,-32($1)  //
 c:   24 ff 40 cd     stqd    $77,-48($1)  //
10:   24 ff 00 cc     stqd    $76,-64($1)  //
14:   33 80 0f cf     lqr     $79,90       // save_regs_1: の命令列を $79 にロード
18:   18 00 80 cc     a       $76,$1,$2    // save_regs_1: の命令列をおくアドレスをロード
1c:   33 80 10 ce     lqr     $78,a0       // save_regs_2: の命令列を $78 にロード
20:   42 00 09 02     ila     $2,12        // 命令列 (save_regs_*) のループ回数をロード
24:   33 80 11 cd     lqr     $77,b0       // save_regs_3: の命令列を $77 にロード
28:   24 00 26 4f     stqd    $79,0($76)   // 命令列 (save_regs_1) をスタックにセーブ
2c:   24 00 a6 4d     stqd    $77,32($76)  // 命令列 (save_regs_3) をスタックにセーブ
30:   1c f0 00 cd     ai      $77,$1,-64   // レジスタをセーブするアドレスをロード
34:   00 40 00 00     sync
38:   35 20 26 4f     bisl    $79,$76      // スタック上の命令列にジャンプ
3c:   1c 04 26 cd     ai      $77,$77,16
      ...

00000090 :
90:   24 00 66 4e     stqd    $78,16($76)  // 命令列 (save_regs_2) をスタックにセーブ
94:   00 40 00 00     sync
98:   1c ff c1 02     ai      $2,$2,-1     // ループカウンタをデクリメント
9c:   1c ff 27 4e     ai      $78,$78,-4   // 命令列 (save_regs_2) のレジスタ指定値を -4

000000a0 :
a0:   24 ff e6 cb     stqd    $75,-16($77) // 4 つのレジスタをセーブ
a4:   24 ff a6 ca     stqd    $74,-32($77) // レジスタ番号はループ毎に -4 される
a8:   24 ff 66 c9     stqd    $73,-48($77) // 1 回目: 75, 74, 73, 72
ac:   24 ff 26 c8     stqd    $72,-64($77) // 2 回目: 71, 70, 69, 68

000000b0 :
b0:   1c f0 26 cd     ai      $77,$77,-64  // レジスタをセーブするアドレスを設定 (-16*4)
b4:   21 7f fb 82     brnz    $2,90        // スタック上の save_regs_1 にジャンプ
b8:   35 00 27 80     bi      $79          // 3c: にジャンプ
bc:   00 00 00 00     stop

ということで 38: のジャンプ実行時のスタックが以下だとすると、

         |   Stack    | high memory
         |   Parms    |
         |            |
         |------------|
         |  Link Reg  |
         |------------|
         | Back Chain |        <---- input SP
         |------------|
         |  Reg 79    |
         |------------|
         |  Reg 78    |
         |------------|
         |  Reg 77    |
         |------------|
         |  Reg 76    |
         |------------|
         |            |
         |------------|
         //   ...    //
         |------------|
         |            |
         |============|
         |save_regs_3 |
         |------------|
         |            |
         |------------|
         |save_regs_1 | <---- $76
         `------------'
                        low memory

39: 時点のスタックがこうなります。

         |   Stack    | high memory
         |   Parms    |
         |            |
         |------------|
         |  Link Reg  |
         |------------|
         | Back Chain |        <---- input SP
         |------------|
         |  Reg 79    |
         |------------|
         |  Reg 78    |
         |------------|
         |  Reg 77    |
         |------------|
         |  Reg 76    |
         |------------|
         |  Reg 75    |
         |------------|
         //   ...    //
         |------------|
         |  Reg  4    |
         |------------|
         |            |
         |------------|
         |            |
         |------------|
         |            |
         |============|
         |save_regs_3 |
         |------------|
         |save_regs_2 |
         |------------|
         |save_regs_1 | <---- $76
         `------------'
                        low memory

次に後半の引数セーブと stop を実行する部分です。

3c:   1c 04 26 cd     ai      $77,$77,16    // 2 つ以上引数がある場合のアドレス調整
                                            // この場合は Reg 4 分インクリメント
40:   24 ff e6 81     stqd    $1,-16($77)   // 現在の sp (call_stack) をセーブ
44:   24 ff a6 cd     stqd    $77,-32($77)  // パラメータへのアドレス (next_arg) をセーブ
48:   24 ff 66 84     stqd    $4,-48($77)   // 引数 2 (format) をセーブ
4c:   24 ff 26 83     stqd    $3,-64($77)   // 引数 1 (stream) をセーブ
50:   1c f0 26 cd     ai      $77,$77,-64   // 引数 1 のアドレスをロード
54:   41 11 80 03     ilhu    $3,8960       // OPCODE(0x23) をロード
58:   43 ff ff 84     ila     $4,3ffff      // マスク値を生成
5c:   33 80 0c cf     lqr     $79,c0        // call_ppe_1: の命令列をロード
60:   3e c1 00 85     cwd     $5,4($1)      // マスク値を生成
64:   80 73 41 84     selb    $3,$3,$77,$4  // [24:31] OPCODE, [0:17] 引数のアドレス
68:   b9 f3 c1 85     shufb   $79,$3,$79,$5 // $3 を命令列 2 word 目に挿入
6c:   24 00 26 4f     stqd    $79,0($76)    // 命令列をスタックにセーブ
70:   00 40 00 00     sync
74:   35 20 26 02     bisl    $2,$76        // スタック上の 命令列にジャンプ
78:   34 ff 00 83     lqd     $3,-64($1)    // 返り値を $3 にロード
7c:   3f e3 01 82     shlqbyi $2,$3,12
80:   23 80 00 02     stqr    $2,0          // errno をセーブ
84:   35 00 00 00     bi      $0            // 呼び出し関数に復帰
        ...
000000c0 :
c0:   00 00 21 00     stop                  // stop OPCLASS
c4:   00 00 00 00     stop                  // ここに OPCODE + 引数のアドレス が入る
c8:   35 00 01 00     bi      $2            // 78: にジャンプ
cc:   00 20 00 00     lnop

よって、スタック上の stop OPCLASS 命令を発行して SPE が停止した時のス タックはこのようになります。

         |   Stack    | high memory
         |   Parms    |
         |            |
         |------------|
         |  Link Reg  |
         |------------|
         | Back Chain |<-----. <---- input SP
         |------------|      |
         |  Reg 79    |      |
         |------------|      |
         |  Reg 78    |      |
         |------------|      |
         //   ...    //      |
         |------------|      |
         |  Reg  6    |      |
         |------------|      |
         |  Reg  5    |<--.  |
         |------------|   |  |
         | call_stack |------'
         |------------|   |   
         |  next_arg  |---'
         |------------| 
         | format (r4)|
         |------------|
         | stream (r3)| <---- start of parameters
         |============|
         |            |
         |------------|
         |            |
         |------------|
         | call_ppe_1 | <---- $76
         `------------'
                        low memory

トラックバック

トラックバックURL:

コメントを投稿


※上に表示されている番号を入力してください



HOME |  企業情報 |  事業内容 |  採用情報 |  社内活動 |  お問合せ |  サイトマップ
.
Copyright(c)2006 Sijam.Inc all rights Reserved
システム開発 株式会社シジャム