katsuhiro -> katsuhiro/refmon -> katsuhiro/refmon/stack_dump

スタックのイメージについて

fp を使う場合

ローカル変数を用いる場合、関数開始時の sp が ip に保存されてスタックに積まれる。

関数のプロローグ、およびエピローグコード(g++ 3.3.5 最適化なし)

mov   ip, sp
stmdb sp!, {fp, ip, lr, pc} ; これが終わったあとを sp_new とする
sub   fp, ip, #4
sub   sp, sp, #8 ; これが終わったあとを sp_after_sub とする
...
ldmia fp, {fp, sp, pc}

stmdb では DB が指定されているので、sp を sp-16 の値まで減らしてからリストの左側にあるレジスタから fp, ip, lr, pc の順にプッシュする。プッシュの方向はアドレスが増加する(絵で言うと下向き)方向である。
出口には ldmia がある。ここでは IA が指定されているので、fp <- 積んである元の fp、sp <- 元の ip、pc <- 元の lr と読み込んでから(「元の〜」はスタックに積んだ値です)、sp を sp+12 する。

接尾辞意味
DADecrement After(メモリアクセス後にポインタを減らす)
IAIncrement After(メモリアクセス後にポインタを増やす)
DBDecrement Before(メモリアクセス前にポインタを減らす)
IBIncrement Before(メモリアクセス前にポインタを増やす)

スタックの様子

0x00000000
|
|______| __ sp_after_sub
|_local|
|_local| __ sp_new
|_float|(浮動小数点のバックアップが
|_float| 来るとしたら、この位置)
|__fp__|
|__ip__|
|__lr__| __ fp
|__pc__| __ sp, ip
|
0xffffffff

ネストした呼び出しを行ったときの様子

0x00000000
|
|______| __ sp_after_sub2
|_local|
|_local| __ sp_new2
|__fp1_|
|__ip2_|
|__lr2_| __ fp2
|__pc2_| __ sp_after_sub1, ip2
|_local|
|_local| __ sp_new1
|__fp0_|
|__ip1_|
|__lr1_| __ fp1
|__pc1_| __ sp, ip1
|
0xffffffff

fp を使わない場合

関数の開始から終了まで sp は不変であるとみなす。
fp を使う関数との差はあまりないように思える。 ローカル変数も浮動小数点レジスタのバックアップも行われることがある。

レジスタを変更する場合、保存すべきレジスタは全て積まれる。このとき stmdb 命令が使われることが多い。

stmdb sp!, {r0, r1, ..., lr}
(関数本体)
ldmia sp!, {r0, r1, ..., lr}

大切なのは「lr や fp がどこにあるのか」だが、これは命令を解析して得るほかない。
stm 命令の下位 15ビットがストアするレジスタのリストになっている。リファレンス参照のこと。

コード例

str lr, [sp, #-4]!
(関数本体)
ldr pc, [sp], #4

//date(coreutils-5.2.1) の __dcgettext
str lr, [sp, #-4]!
mov ip, #0
sub sp, sp, #8
(関数本体)
add sp, sp, #8
ldr pc, [sp], #4

//date(coreutils-5.2.1) の _IO_file_doallocate
stmdb sp!, {r4, r5, r6, lr}
ldr r3, [r0, #56]
sub sp, sp, #104
(関数本体)
add sp, sp, #104
ldmia sp!, {r4, r5, r6, pc}

//date(coreutils-5.2.1) の __mmap
stmdb   sp!, {r0, r1, r2, r3}
mov     r0, sp
swi     0x0090005a
add     sp, sp, #16     ; 0x10
cmn     r0, #4096       ; 0x1000
movcc   pc, lr
b       35c60 <__syscall_error>

浮動小数点レジスタのバックアップについて

以下の関数で使用されていた

//date(coreutils-5.2.1, static linked) の _dl_catch_error
stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
sfm f4, 4, [sp, #-48]!
(...)
sub sp, sp, #252
(関数本体)
add sp, sp, #252
lfm f4, 4, [sp], #48
ldmia sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc}

sfm 命令とは?

ARM の命令セットリファレンスには、sfm という命令はない。

objdump では特殊な stc 命令を sfm という名前で表示するようだ。

objdump によって sfm f4, 4, [sp, #-48]! と翻訳される機械語
16進 e    d    2    d    4    2    0c
2進  1110 1101 0010 1101 0100 0010 00001100
これを stc 命令のフィールドに当てはめると
     cond 110P UNWL Rn   CRd  cp#  offset_8
                    =13  =4   =2   =12

今のところだめなやつ

00342f90 <__select>:
  342f90:       e59fc068        ldr     ip, [pc, #104]  ; 343000 <.text+0x33af30>
  342f94:       e59cc000        ldr     ip, [ip]
  342f98:       e33c0000        teq     ip, #0  ; 0x0
  342f9c:       1a000006        bne     342fbc <__select+0x2c>
  342fa0:       e52d4004        str     r4, [sp, #-4]!
  342fa4:       e59d4004        ldr     r4, [sp, #4]
  342fa8:       ef90008e        swi     0x0090008e

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-09-13 (土) 08:26:39