Linuxプログラムの調整

8092 ワード

http://blog.csdn.net/zhaoyuping/article/details/8931662
Linuxプログラムのデバッグ--Bus エロエロ
Buss Errorとは何ですか?
1つ  バスエラーです.
   誘発原因:
   CPUは、性能面を考慮して、データへのアクセスを要求する場合は、アドレスの配置が必要です.アドレス配置ではないと発見された場合、SIGBUS信号はプロセスに送信され、プロセスにcore dumpが生成される.RISCはSPARC(マイクロプロセッサーアーキテクチャ)を含み、このタイプのチップである.x 86シリーズのCPUは、不整合アクセスをサポートしています.また、スイッチを無効にするメカニズムも提供しています.x 86アーキテクチャは、整列されたアクセスを要求しない場合、必ず性能の代償があります.例えば、intへのアクセスは、4バイトが揃うべきであり、アドレスは4の倍数であり、ショートに対しては2バイトが揃うべきであり、アドレスは2の倍数であるべきである.
   Buss Errerはマシンの物理的な問題や無効な物理的なアドレスへのアクセスのためかもしれませんが、これは非常にまれです.
   Linuxプラットフォームでは、Malloc()を実行し、十分なRAMがない場合、Linuxは、Malloc()を失敗させて戻るのではなく、現在のプロセスにSIGBUS信号を配信する.          注:この点に対して懐疑的な態度をとり、機会があれば自分でテストして現在のシステムの反応を確認することができます.
SIGBUSとSIGS EGV信号の一般的な違いは以下の通りです.   1)SIGBUS(Bus error)は、ポインタに対応するアドレスが有効アドレスであることを意味するが、バスはこのポインタを正常に使用できない.通常は配置されていないデータのアクセスに起因します.    2)SIGS EGV(Segment fault)は、ポインタが対応するアドレスが無効アドレスであり、物理メモリがないことを意味します.
 
二番目  例プログラム:
1 int main(){  6嗳if defined(__u GNUC_u u_)  7菗if defined(_櫣i 386__u u_)  8       9     __asm_(「%esp)popf」) 10胪elif defined(_ku x 86_64_u) 11       12     __asm_(「%rsp)popf」); 13嗳endif 14璣endif 24.    shart array[16]; 25 26    int*p=(int*)&array[1]; 27.    *p=1; 28 29    return 1; 30}
 ショートタイプのサイズは2バイトで、その住所は必ず2の倍数です.intポインタでは、データにアクセスするためのアドレスは4の倍数であり、arrary[1]のアドレスをint*に変換してアクセスすることができ、システムはSIGBUS信号を発し、プログラムがクラッシュする.
   wiki上の例:
    http://en.wikipedia.org/wiki/Bus_error萼Bus_error_example
#include <stdlib.h> 
 
 int main( int argc, char ** argv) { 
 int * iptr; 
 char * cptr; 
 
 #if defined(__GNUC__) 
 # if defined(__i386__) 
 
__asm__( "pushf/n orl $0x40000,(%esp)/n popf" ) ; 
 # elif defined(__x86_64__)  
 
__asm__( "pushf/n orl $0x40000,(%rsp)/n popf" ) ; 
 # endif 
 #endif 
 
 
cptr = malloc( sizeof ( int ) + 1) ; 
 
 
iptr = ( int * ) ++ cptr; 
 
 
 * iptr = 42 ; 
 
 return 0 ; 
 } 
 
$ gcc -ansi sigbus.c -o sigbus
$ ./sigbus 
Bus error
$ gdb ./sigbus
(gdb) r
Program received signal SIGBUS , Bus error.
0x080483ba in main ()
(gdb) x/i $pc
0x80483ba <main+54>: mov DWORD PTR [eax],0x2a
(gdb) p/x $eax
$1 = 0x804a009
(gdb) p/t $eax & (sizeof(int) - 1)
$2 = 1
 

 

三,编译器和硬件平台相关性

 

    上述已经描述,对于x86平台,默认允许非对齐访问,只不过会有性能代价。开启检测可以使用上述代码中的宏。

 

    这段程序如果用Sun Studio编译器的话,运行就没有问题。这是因为Sun Studio默认对32位编译使用的参数是-xmemalign=8i,其中i选项设置明确指明不产生SIGBUS信号。
    不过如果编译成64位程序,Sun Studio使用的-xmemalign=8s,其中s选项设置意味对这种非对齐访问产生SIGBUS信号,则仍旧会遇到这个错误。

 

    如果坚持在SPARC上使用GCC去编译这种代码,可以如下进行:

    GCC有一个Type Attributes特性,例如在需人工对齐的变量后加上:__attribute__ ((aligned (4))); 其意义就是指定偏移量为4的倍数。比如:

 short array[10] __attribute__ ((aligned (4)));
    ただし、この属性はLinkerコネクタに見える変数にのみ有効です.つまり、local variableには無効です.また、このような特性的作用は粒度が比較的大きいので、ここでは第一の要素だけに作用し、配列の各メンバにオフセット量を設定しない.必ずlocal variableまたは配列の各メンバーに対してオフセット量設定を行うなら、unionタイプを使用することができます.
 union {
short s;
int i;
}
 
Linuxプログラムのデバッグ--Bus Errer(2)
私たちはよく二つのメモリの入れ替えを発見します.  dump(dump)の一つは、通常は不正なアドレス上で値付け操作を行います.一つはバスエラーです.  error)通常はポインタ強制変換であり、CPUがデータを読み出すことは一定のバス規則に違反する.バスエラーの例は以下のとおりです.  玣include  int  メール(){int  i[5];int  j;i[0]=65536+2;i[1]=65536*3+4;j=*(int  *)(char  *)i+2))      printf("size"  保存先  要点  is  %dj=%d",sizeof(int)、j);return  0;とりあえずバイト順の問題をテストしないと、j結果がいくらであろうと、普通のRISCのCPUでは、一般的なunixマシンにはバスが発生します.  errorです.windowsマシンでvcのclを使いました.  borland bcc 32とgnuのgccコンパイル実行は大丈夫です.興味があれば、*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************問題です.以下は私の意見です.ハードウェアの観点から見て、メモリは小さいほうですよね.各ブロックには固定サイズがあります.今は4の整数倍、あるいはintサイズの整数倍、あるいはアドレスラインの総数の整数倍があります.なぜですか?ハードウェアがいいです.例を挙げると、int型は4バイトです.サイズが大きく、かつ、最初のバイトアドレスが制限されていない場合、このintは2つのメモリブロックの間にまたがっている可能性があります(または他の人が言っている「2ページのメモリの間にまたがって」)、ハードウェアはどうやってデータを取りますか?ハードウェアに詳しい人は、メモリアクセスは「クロスクロス」を使うことを知っています.アドレスを決めるということは、メモリブロックごとに反発し合っているということです.このデータを読むのは面倒ではないでしょうか?アドレスが4の整数倍となっていると、問題が解決され、効率も高くなります.プログラミングの観点から言えば、虚メモリを使ってページ内にマッピング関係があります.当然、上記の問題を招きます.unixはこのエラーが発生しました.私の観点を使います.説明できるはずです.ビルの主が言っているvcについては、奇数アドレスをintポインタに変換して値を取ると、問題が発生するはずです.なぜ2倍数が4倍以外の倍数で正確に実行できるのですか?おそらく、操作システムのメモリマッピングに関連して、unixでは「完全に整列」が採用される可能性があります.原則として、windowsは虚メモリに境界を加えているかもしれません.つまり実際の虚ページは実際のページより少なくとも2バイト以上少ないです.越境防止のためにシステムが崩壊するのを目的にしているかもしれません.構造体のsizeofの問題を考えて、ついでに、これは>=内部変数と大きさ、大きさの法則をよく見ていますか?これも「境界」です.問題は、コンパイラがデータのアクセス速度を求めるために行うちょっとした事前処理といえる.  メール(){int  a[4]={0,0,0,0}int  *pi=(int  *)(((char)  *)a)+1)、*pi=3;printf("a 0"  is  %d「  「a 1」  is  %d「  ピー  is  %d",a[0],a[1]、**pi];printf("sizof"  要点  is  %d「sizeof(int);return  0;}同様にGCCでHPUXをコンパイルするのはバスエラーです.(他のUNIXマシンにも出ています.以前はやったことがあります.)WINDOWSに持ってきます.  2000のマシンは使いやすいです.a 0  is  768 a 1  is  0 pi  is  3サイズ  要点  is  4***は今バイトの序を考えていません.どうしてwindowsで使えるのですか?32桁のプログラムをコンパイルしたのではないですか?特殊な処理もしたのですか?理論的には間違いがあったのです.おかしなことが***************************************************************************************************************************************************の****************************************************************************************************************************が******************************************************************どのunixですか?Solarisで覚えています.似たようなバスがあります  errorのです.linuxとscoの下でいくつかのテストを行います.コンパイラのデフォルトの配置方式を採用しても、奇数アドレスがintアドレスに強制的に変換された場合、プログラムは正常に実行されます.linuxとscoの下でコンパイラがスタックから非整列構造体非配置空間になる方法には少し違いがあります.上述した構造体で、linuxは偶数アドレスから始まります.scoは奇数アドレスからオープンします.始めます...上記のようなことは抜きにして、まず話さないでください.1.各オペレーティングシステムは自分のプロセスをロードして、スケジュールしています.つまり、虚メモリから実際のメモリにマッピングして、それぞれのOSは自分の特徴があります.彼らは自分の状況によっていくつかの小さな確率のイベントを避けることができます.「境界」小確率イベントとも言えるはずです.スペースを割り当てる時に手足を動かすのは、分配者にとって難しくないはずです.データにアクセスします.3.非整合方式を採用するとプログラムの効率が低下します.本によってはこれらに言及する可能性があります.コンパイラにどのような方式を採用するかを決めさせてください.すべてのコンパイラはシステムによって来ます.4.アドレス変換の値を取る時に、ビットコピーをできるだけ使うようにします.このような違いのosも気をつけなくてください.5.OSはどう対応してもいいです.  error問題は、コンパイラがどのように最適化されても、ハードウェアアクセス時の境界問題は常に存在し、移植可能システムを開発する時には、この問題を見逃すべきではないと思います.いわゆるタイプはありません.2.cpuアクセスデータはコマンドでハードウェアアクセスデータを制御します.通常はcache、レジスタを先に読みます.イメージが少しあれば、交差点の信号機の制御下の車の流れと同じです.「マイコン原理」を見てください.助けになるかもしれません.3、ハードは境界問題に遭遇する時、警告があると思います.各OSは違っています.4、Solarisの特徴は、「当分は深く掘りすぎないようにしてください.十分な資料がない限り、この問題と大体の可能性の原因は同じです.把握しないということではなく、コンピュータというものが多すぎます.多くの原因が分かります.」ハードウエアの問題は避けることを採用して、大きな代価を払って解決に行きます.