0

私には意味をなさないセグメンテーション違反があります。この関数が 538 回呼び出されると失敗しますが、パラメーターに問題はありません。同じ式を gdb に入力すると、問題なく実行されます。私は si を使用してそれに忍び寄り、レジスターを見ましたが、それでも意味がありません。これを理解するにはどうすればよいですか?

奇妙なことの 1 つは、"bit" 引数が障害で 0 から 1 に変更されたと gdb が報告することです。「ビット」は、他の何かに再利用されたレジスターにあると思います。

私も最適化せずにこれを試しました。より多くの指示が含まれていましたが、結果は同じでした。

以下で、gdb を使用して、コードがアクセスしようとしているのと同じ場所に問題なくアクセスしていることに注意してください。

コード:

void Bits::set(int bit)
{
    if (bit >= _size*16) BUG;
    _dat[bit/16] |= 1 << (bit & 15);
}

gdb 実行:

Breakpoint 1, Bits::set (this=0x68374, bit=0) at util.cpp:181
181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x3964c <_ZN4Bits3setEi+36>: ldr     r3, [r0, #4]
(gdb) si
0x00039650      181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x39650 <_ZN4Bits3setEi+40>: mov     r1, #1
(gdb)
0x00039654      181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x39654 <_ZN4Bits3setEi+44>: ldrh    r2, [r12, r3]
(gdb)
0x00039658      181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x39658 <_ZN4Bits3setEi+48>: orr     r2, r2, r1, lsl lr
(gdb)
0x0003965c      181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x3965c <_ZN4Bits3setEi+52>: strh    r2, [r12, r3]
(gdb) p _dat
$18 = (short *) 0x4ee74
(gdb) p *_dat
$19 = -3784
(gdb) p $r2
$20 = 61753
(gdb) p $r12
$21 = 0
(gdb) p/x $r3
$22 = 0x4ee74
(gdb) si

Program received signal SIGSEGV, Segmentation fault.
0x0003965c in Bits::set (this=0x68374, bit=1) at util.cpp:181
181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x3965c <_ZN4Bits3setEi+52>: strh    r2, [r12, r3]
(gdb)

ちなみにここではgdbserverを使っています。ターゲット応答は次のとおりです。

50:/mnt/home/rw # ./gdbserver x:12 cx Andersen_Studio.cxc
Process cx created; pid = 226
Listening on port 12
Remote debugging from host 192.168.1.40

pc : [<0003965c>]    lr : [<00000000>]    Tainted: P
sp : 7ffffdb4  ip : 00000000  fp : 7ffffe84
r10: 2ada7884  r9 : 0000c6c8  r8 : 2ada8d28
r7 : 00000002  r6 : 0005c0b8  r5 : 00000000  r4 : 0006dc10
r3 : 0004ee74  r2 : 0000f139  r1 : 00000001  r0 : 00068374
Flags: Nzcv  IRQs on  FIQs on  Mode USER_32  Segment user
Control: C000317F  Table: 017EC000  DAC: 00000015

詳細: コマンドを手動で実行すると、障害は発生しません。

Breakpoint 1, Bits::set (this=0x6c75c, bit=0) at util.cpp:181
181         _dat[bit/16] |= 1 << (bit & 15);
(gdb) c 538
Will ignore next 537 crossings of breakpoint 1.  Continuing.

Breakpoint 1, Bits::set (this=0x68374, bit=0) at util.cpp:181
181         _dat[bit/16] |= 1 << (bit & 15);
(gdb) p _dat[bit/16] |= 1 << (bit & 15)
$25 = -3783
(gdb) dis 1
(gdb) c
Continuing.

_dat[0] を参照するだけでは役に立ちませんが、たとえば _dat[0]=0 と入力すると問題が回避されます。

(後で編集)

関数用に生成されたコードを確認する場合は、最適化をオフにすることにしました。最適化されていないコードは次のとおりです。

(gdb) disass
Dump of assembler code for function _ZN4Bits3setEi:
   0x0006a1d8 <+0>:     mov     r12, sp
   0x0006a1dc <+4>:     push    {r11, r12, lr, pc}
   0x0006a1e0 <+8>:     sub     r11, r12, #4
   0x0006a1e4 <+12>:    sub     sp, sp, #8
   0x0006a1e8 <+16>:    str     r0, [r11, #-16]
   0x0006a1ec <+20>:    str     r1, [r11, #-20]
=> 0x0006a1f0 <+24>:    ldr     r3, [r11, #-16]
   0x0006a1f4 <+28>:    ldr     r3, [r3]
   0x0006a1f8 <+32>:    lsl     r2, r3, #4
   0x0006a1fc <+36>:    ldr     r3, [r11, #-20]
   0x0006a200 <+40>:    cmp     r3, r2
   0x0006a204 <+44>:    blt     0x6a220 <_ZN4Bits3setEi+72>
   0x0006a208 <+48>:    ldr     r0, [pc, #108]  ; 0x6a27c <_ZN4Bits3setEi+164>
   0x0006a20c <+52>:    ldr     r1, [pc, #108]  ; 0x6a280 <_ZN4Bits3setEi+168>
   0x0006a210 <+56>:    mov     r2, #180        ; 0xb4
   0x0006a214 <+60>:    bl      0xa00c <printf>
   0x0006a218 <+64>:    mov     r0, #1
   0x0006a21c <+68>:    bl      0xa09c <exit>
   0x0006a220 <+72>:    ldr     r1, [r11, #-16]
   0x0006a224 <+76>:    ldr     r2, [r11, #-20]
   0x0006a228 <+80>:    asr     r3, r2, #31
   0x0006a22c <+84>:    lsr     r3, r3, #28
   0x0006a230 <+88>:    add     r3, r2, r3
   0x0006a234 <+92>:    asr     r0, r3, #4
   0x0006a238 <+96>:    mov     r3, r0
   0x0006a23c <+100>:   lsl     r2, r3, #1
   0x0006a240 <+104>:   ldr     r3, [r1, #4]
   0x0006a244 <+108>:   add     r12, r2, r3
   0x0006a248 <+112>:   ldr     r1, [r11, #-16]
   0x0006a24c <+116>:   mov     r3, r0
   0x0006a250 <+120>:   lsl     r2, r3, #1
   0x0006a254 <+124>:   ldr     r3, [r1, #4]
   0x0006a258 <+128>:   add     r1, r2, r3
   0x0006a25c <+132>:   ldr     r3, [r11, #-20]
   0x0006a260 <+136>:   and     r2, r3, #15
   0x0006a264 <+140>:   mov     r3, #1
   0x0006a268 <+144>:   lsl     r3, r3, r2
   0x0006a26c <+148>:   ldrh    r2, [r1]
   0x0006a270 <+152>:   orr     r3, r2, r3
   0x0006a274 <+156>:   strh    r3, [r12]
   0x0006a278 <+160>:   ldmdb   r11, {r11, sp, pc}
   0x0006a27c <+164>:   andeq   r8, r8, r0, lsr r12
   0x0006a280 <+168>:   andeq   r8, r8, r4, asr r12
End of assembler dump.
(gdb)

_dat[0] = 0; を挿入してみました。「悪い」ステートメントの前に、それが障害を引き起こしました。_dat[0]++; を試しました。そしてそれも失敗しました。

4

3 に答える 3

1

gdb を使用してメモリを変更しても問題ないように見えるため、この特定の行でセグメンテーション違反が発生する理由がわかりません。ただし、Bits コンストラクターで「this」を出力し、それを障害の「this」と比較すると、おそらくここから離れた場所で、メモリの破損に苦しんでいることがわかります。したがって、私はこの一連の調査を中断し、問題が別の場所にあると仮定して続行します。

(後で)

私は問題を発見しました。これはビットへの初期化されていないポインタ (驚き!) であり、表面的には正しいかのように見えるほど十分に信頼できるものでした。私を正しい方向に向けたアイデアは、printf で行ったばかりの「ログを記録する」アイデアでした。

于 2013-04-06T23:07:01.157 に答える
-1

1) つまり、ARM アセンブリ命令 strh r2, [r12, r3] を実行するとアクセス違反が発生すると言っているのです。

2) Q: 0x4ee74 (r3 に含まれる) は有効ですか?

3) Q: 0000f139 (r2 に含まれる) は有効ですか? マニュアルから:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0068b/BABDJCHA.html

ワードおよびハーフワード転送のアドレス整列:

アドレスは 4 の倍数でなければなりません。

システムにシステム コプロセッサ (cp15) がある場合は、アライメント チェックを有効にできます。アライメント チェックが有効になっている場合、アライメントされていない転送によってアライメント例外が発生します。

システムにシステム コプロセッサ (cp15) がない場合、または位置合わせチェックが無効になっている場合:

アラインされていないロードは、Rd を破損します。

アラインされていない保存では、メモリ内の 4 バイトが破損します。メモリ内の破損した場所は [アドレス AND NOT b11] です。

于 2013-04-06T18:00:00.933 に答える