ソフトウェアでのゼロによる浮動小数点除算エラーの識別

C ライブラリヘルパ関数 _fp_trapveneer() は、例外が発生するたびに呼び出されます。この関数の呼び出し時、レジスタの状態は、例外が発生したときから変更されていません。そのため、ブレークポイントを関数 _fp_trapveneer() に設定し、LR を検査することにより、例外を返した演算が含まれている関数のアドレスをアプリケーションコードで見つけることができます。

例えば、Example 38 の C コードは、次の文字列を使用してコマンドラインからコンパイルされます。

armcc --fpmode ieee_full

コンパイラによって生成されるアセンブリ言語コードが逆アセンブルされると、デバッガによってExample 39 に示す出力が生成されます。

Example 38. ゼロ除算エラーのトラップ

#include <stdio.h>
#include <fenv.h>

int main(void)
{    float a, b, c;
    // 無効演算例外のトラップを有効にし、他のすべての例外のトラップを無効にする
    __ieee_status(FE_IEEE_MASK_ALL_EXCEPT, FE_IEEE_MASK_DIVBYZERO);
    c = 0;
    a = b / c;
    printf("b / c = %f, ", a); // ゼロ除算エラーをトラップする
    return 0;
}

Example 39. ゼロ除算エラーの逆アセンブリ

main:
    00008080 E92D4010  PUSH     {r4,lr}
    00008084 E3A01C02  MOV      r1,#0x200
    00008088 E3A00C9F  MOV      r0,#0x9f00
    0000808C EB000F1A  BL       __ieee_status              <0xbcfc>
    00008090 E59F0020  LDR      r0,0x80b8
    00008094 E3A01000  MOV      r1,#0
    00008098 EB000DEA  BL       _fdiv                      <0xb848>
    0000809C EB000DBD  BL       _f2d                       <0xb798>
    000080A0 E1A02000  MOV      r2,r0
    000080A4 E1A03001  MOV      r3,r1
    000080A8 E28F000C  ADR      r0,{pc}+0x14 ; 0x80bc
    000080AC EB000006  BL       __0printf                  <0x80cc>
    000080B0 E3A00000  MOV      r0,#0
    000080B4 E8BD8010  POP      {r4,pc}
    000080B8 40A00000  <Data>   0x00 0x00 0xA0 '@'
    000080BC 202F2062  <Data>   'b' ' ' '/' ' '
    000080C0 203D2063  <Data>   'c' ' ' '=' ' '
    000080C4 202C6625  <Data>   '%' 'f' ',' ' '
    000080C8 00000000  <Data>   0x00 0x00 0x00 0x00

_fp_trapveneer にブレークポイントを設定し、デバッグモニタで逆アセンブリを実行すると、以下が生成されます。

> go
Stopped at 0x0000BF6C due to SW Instruction BreakpointStopped at 0x0000BF6C:TRAPV_S\_fp_trapveneer

次に、レジスタを調べると、以下が示されます。

  r0:0x40A00000     r1:0x00000000     r2:0x00000000     r3:0x00000000
  r4:0x0000C1DC     r5:0x0000C1CC     r6:0x00000000     r7:0x00000000
  r8:0x00000000     r9:0x00000000    r10:0x0000C0D4    r11:0x00000000
 r12:0x08000004     SP:0x07FFFFF8     LR:0x0000809C     PC:0x0000BF6C
CPSR: nzcvIFtSVC

リンクレジスタ LR に含まれているアドレスは、0x809c(例外の原因となった命令 BL _fdiv の後の命令のアドレス)に設定されます。

Show/hide関連項目

Copyright © 2010 ARM. All rights reserved.ARM DUI 0472BJ
Non-ConfidentialID011811