欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

標(biāo)題: Bus Error [打印本頁(yè)]

作者: 51黑tt    時(shí)間: 2016-3-5 18:10
標(biāo)題: Bus Error
在x86+Linux上寫的程序,在PC機(jī)上運(yùn)行得很好。可是使用ARM的gcc進(jìn)行交叉編譯,再送到DaVinci目標(biāo)板上運(yùn)行的時(shí)候,出現(xiàn)了Bus error。
出現(xiàn)的位置如下(其中Debug的內(nèi)容是我在程序中添加的調(diào)試信息):
root@211.69.193.189:~# arm_v5t_le-gcc -g shit.c
root@211.69.193.189:~# ./a.out
Debug: malloc space for the actual data: temp_buf = 0x13118
Debug: in my_recvn()
Debug: nleft = 52
Bus error
打開調(diào)試器進(jìn)行調(diào)試:
root@211.69.193.189:~# gdb a.out
GNU gdb 6.3 (MontaVista 6.3-20.0.22.0501131 2005-07-22)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "armv5tl-montavista-linuxeabi"...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) run // 運(yùn)行程序
Starting program: /home/zpf/a.out
Debug: in get_program_info()
Debug: in conn_server(char *err_buf_ptr)
Debug: gonna create a socket
Debug: gonna fill in the serv_addr structure
Debug: gonna connect to a server
Debug: gonna send LIN_RST
Debug: in my_sendn()
Debug: send 4 bytes to server:
Debug: gonna receive LIN_RSP
Debug: in my_recvn()
Debug: nleft = 3
Debug: received first 3 bytes from server: 7
Debug: gonna check if 3rd byte is the package type
Debug: received package length = 55
Debug: malloc space for the actual data: temp_buf = 0x13118
Debug: in my_recvn()
Debug: nleft = 52

Program received signal SIGBUS, Bus error. // 在這里出現(xiàn)了錯(cuò)誤
0x00009624 in alloc_prog_mem (detail_buf=0x13118 "\001\002",
err_buf_ptr=0xbefffc40 "") at shit.c:631
631 g_data_ptr->progtype_num = *(short *)ptr ;
(gdb) print ptr // 查看一下ptr的值
$1 = 0x13119 "\002" // 地址起始是奇數(shù)!!!
(gdb) set ptr=0x1311a // 想改一下
(gdb) continue
Continuing.

Program terminated with signal SIGBUS, Bus error.
The program no longer exists. // 可惜程序已經(jīng)退出
(gdb) quit

其中,g_data_ptr->progtype_num是一個(gè)short類型的值。
把強(qiáng)制類型轉(zhuǎn)換改為用memcpy()寫值之后,再調(diào)試
root@211.69.193.189:~# gdb test
GNU gdb 6.3 (MontaVista 6.3-20.0.22.0501131 2005-07-22)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "armv5tl-montavista-linuxeabi"...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) break 626 // 把剛剛的那句強(qiáng)制類型轉(zhuǎn)換變成內(nèi)存拷貝
Breakpoint 1 at 0x9630: file test.c, line 626.
(gdb) run
Starting program: /home/zpf/test
Debug: in get_program_info()
Debug: in conn_server(char *err_buf_ptr)
Debug: gonna create a socket
Debug: gonna fill in the serv_addr structure
Debug: gonna connect to a server
Debug: gonna send LIN_RST
Debug: in my_sendn()
Debug: send 4 bytes to server:
Debug: gonna receive LIN_RSP
Debug: in my_recvn()
Debug: nleft = 3
Debug: received first 3 bytes from server: 7
Debug: gonna check if 3rd byte is the package type
Debug: received package length = 55
Debug: malloc space for the actual data: temp_buf = 0x13118
Debug: in my_recvn()
Debug: nleft = 52

Breakpoint 1, alloc_prog_mem (detail_buf=0x13118 "\001\002",
err_buf_ptr=0xbefffc40 "") at test.c:626
warning: Source file is more recent than executable.

626 memcpy(&(g_data_ptr->prog_num), ptr, 2) ; // 在這一句中斷
(gdb) print ptr // 再看看ptr
$1 = 0x1311b "\003" // 還是奇數(shù)地址
(gdb) continue // 繼續(xù)執(zhí)行
Continuing.
Debug: sum_progtype = 2 , sum_prog = 3
Debug: gonna malloc space for progtype_ptr
Debug: gonna malloc space for prog_ptr
Debug: in mv_pkg2prog_list()
Debug: gonna set ProgramType program_type_name
Debug: ProgramType program_type_name set OK
Debug: in $ == *ptr, j = 0
Debug: g_data_ptr->progtype_ptr[j].prog_ptr = temp_prog_ptr
Debug: in @ == *ptr, ptr = 0x13126
Debug: temp_prog_ptr->format = *ptr
Debug: temp_prog_ptr->program_id = *(int *)ptr
Debug: gonna set Program program_name
Debug: Program program_name set OK
Debug: finished one loop of while
Debug: in @ == *ptr, ptr = 0x1312f
Debug: temp_prog_ptr->format = *ptr
Debug: temp_prog_ptr->program_id = *(int *)ptr
Debug: gonna set Program program_name
Debug: Program program_name set OK
Debug: finished one loop of while
Debug: gonna set ProgramType program_type_name
Debug: ProgramType program_type_name set OK
Debug: in $ == *ptr, j = 1
Debug: g_data_ptr->progtype_ptr[j].prog_ptr = temp_prog_ptr
Debug: in @ == *ptr, ptr = 0x13142
Debug: temp_prog_ptr->format = *ptr
Debug: temp_prog_ptr->program_id = *(int *)ptr
Debug: gonna set Program program_name
Debug: Program program_name set OK
Debug: finished one loop of while
program type[0]
program_type_id = 1
program_type_name = love
program_num = 2
prog_ptr = 0x131d8
program[0]
program_id = 1001
program_name = you
format = 1
program[1]
program_id = 1002
program_name = me
format = 2
program type[1]
program_type_id = 2
program_type_name = hatred
program_num = 1
prog_ptr = 0x13248
program[0]
program_id = 2005
program_name = kill
format = 5
Debug: gonna return an OK
Debug: Entering send_exit_requstion()
Debug: in conn_server(char *err_buf_ptr)
Debug: gonna create a socket
Debug: gonna fill in the serv_addr structure
Debug: gonna connect to a server
Debug: gonna send EXIT_RST
Debug: in my_sendn()
Debug: send 4 bytes to server:
Debug: in my_recvn()
Debug: nleft = 4
Debug: gonna return an OK

Program exited normally. // 執(zhí)行通過了!!!!
(gdb)

總結(jié):
問題總算找到了,就是我企圖在一個(gè)奇數(shù)地址起始的地方強(qiáng)制類型轉(zhuǎn)換得到一個(gè)short值。
在Intel系列處理器上,可以在任一奇數(shù)內(nèi)存地址儲(chǔ)存任何變量或數(shù)組,不會(huì)導(dǎo)致任何致命的錯(cuò)誤影響,只是效率可能會(huì)降低。但在DaVinci上,這一點(diǎn)不行。所以必須對(duì)大于一個(gè)字節(jié)的數(shù)據(jù)類型小心謹(jǐn)慎,比較安全的方法是使用內(nèi)存拷貝函數(shù)memcpy(),或者使用下面的代替方法:
// 先定義一個(gè)聯(lián)合體
union {
short short_val ;
char short_byte[2] ;
} myshort ;
// 然后,把程序中本來應(yīng)該是
// g_data_ptr->progtype_num = *(short *)ptr ;
// ptr += 2 ;
// 這兩句的地方換成下面五句:
myshort.short_byte[0] = *ptr ;
ptr++ ;
myshort.short_byte[1] = *ptr ;
ptr++ ;
g_data_ptr->progtype_num = myshort.short_val ;
// 當(dāng)然,最簡(jiǎn)單的方法是換成下面兩句:
// memcpy(&(g_data_ptr->progtype_num), ptr, 2) ;
// ptr += 2 ;

對(duì)于這個(gè)問題的進(jìn)一步探討:

在DaVinci上應(yīng)該注意內(nèi)存編址模式的問題。
struct {
char struc_char ;
int struc_int ;
short struc_short ;
long struct_long ;
} struc_val ;
在寬松模式下,盡管struc_char只有1個(gè)字節(jié),struc_short占2個(gè)字節(jié),但編譯器可能給這兩個(gè)變量分別分配了4個(gè)字節(jié),結(jié)果整個(gè)結(jié)構(gòu)的大小變成了16個(gè)字節(jié),而在編譯器設(shè)為緊湊模式時(shí),則正好是11個(gè)字節(jié)。根據(jù)計(jì)算機(jī)數(shù)據(jù)總線的位數(shù),不同的編址模式存取數(shù)據(jù)的速度不一樣。我認(rèn)為在符合總線字長(zhǎng)的情況下,效率是最高的,因?yàn)橹恍柽M(jìn)行一次總線操作。
內(nèi)存編址模式會(huì)影響字節(jié)對(duì)齊方式,字節(jié)對(duì)齊操作可以解決以下兩個(gè)主要的問題:
1.訪存效率問題;一般的編譯器要對(duì)內(nèi)存進(jìn)行對(duì)齊,在處理變量時(shí),編譯器會(huì)根據(jù)一定的設(shè)置將長(zhǎng)短不同的變量的數(shù)據(jù)長(zhǎng)度進(jìn)行對(duì)齊以加快內(nèi)存處理速度。
2.強(qiáng)制類型轉(zhuǎn)換問題:在x86上,字節(jié)不對(duì)齊的操作只會(huì)影響效率,但是在DaVinci上,可能就是一個(gè)Bus error, 因?yàn)樗蟊仨氉止?jié)對(duì)齊。
字節(jié)對(duì)齊的準(zhǔn)則
1.數(shù)據(jù)類型自身的對(duì)齊值:對(duì)于char型數(shù)據(jù),其自身對(duì)齊值為1,對(duì)于short型為2,對(duì)于int,long,float,double類型,其自身對(duì)齊值為4字節(jié)。
2.結(jié)構(gòu)體的自身對(duì)齊值:其成員中自身對(duì)齊值最大的那個(gè)值。
3.指定對(duì)齊值:#pragma pack (value)時(shí)的指定對(duì)齊值value。
4.數(shù)據(jù)成員、結(jié)構(gòu)體和類的有效對(duì)齊值:自身對(duì)齊值和指定對(duì)齊值中小的那個(gè)值。
對(duì)于平時(shí)定義變量,盡可能先定義長(zhǎng)度為4的倍數(shù)的變量,然后是長(zhǎng)度是2的變量,最后是長(zhǎng)度為1的變量。

通過測(cè)試,GCC編譯器是按照4字節(jié)對(duì)齊存放于內(nèi)存的。而我還沒有發(fā)現(xiàn)更改編址模式的參數(shù)。程序如下:
#include

int main()
{
struct {
char struc_char ;
int struc_int ;
short struc_short ;
long struct_long ;
} struc_val ;
char c_char ;
int i_int ;
short s_short ;
long l_long ;

printf("sizeof(struc_val) = %d\n", sizeof(struc_val));
printf("sizeof(c_char) = %d\n", sizeof(c_char));
printf("sizeof(i_int) = %d\n", sizeof(i_int));
printf("sizeof(s_short) = %d\n", sizeof(s_short));
printf("sizeof(l_long) = %d\n", sizeof(l_long));

printf("address of struc_val = %p\n", &struc_val);
printf("address of struc_char = %p\n", &(struc_val.struc_char));
printf("address of struc_int = %p\n", &(struc_val.struc_int));
printf("address of struc_short = %p\n", &(struc_val.struc_short));
printf("address of struct_long = %p\n", &(struc_val.struct_long));
printf("address of c_char = %p\n", &c_char);
printf("address of i_int = %p\n", &i_int);
printf("address of s_short = %p\n", &s_short);
printf("address of l_long = %p\n", &l_long);

return 0 ;
}
測(cè)試結(jié)果:
sizeof(struc_val) = 16
sizeof(c_char) = 1
sizeof(i_int) = 4
sizeof(s_short) = 2
sizeof(l_long) = 4
address of struc_val = 0xbf885278
address of struc_char = 0xbf885278
address of struc_int = 0xbf88527c
address of struc_short = 0xbf885280
address of struct_long = 0xbf885284
address of c_char = 0xbf885277
address of i_int = 0xbf885270
address of s_short = 0xbf88526e
address of l_long = 0xbf885268

所以對(duì)于一個(gè)32位的數(shù)據(jù)來講,如果其沒有在4字節(jié)整除的內(nèi)存地址處存放,那么處理器就需要2個(gè)總線周期對(duì)其進(jìn)行訪問。
0x08 | byte8 | byte9 | byteA | byteB |
0x04 | byte4 | byte5 | byte6 | byte7 |
0x00 | byte0 | byte1 | byte2 | byte3 |
對(duì)于我剛剛的那個(gè)出現(xiàn)Bus error的程序,假設(shè)指針ptr剛好是指向了byte3(地址是0x0),然后想進(jìn)行short強(qiáng)制類型轉(zhuǎn)換,使用byte3,byte4來構(gòu)成一個(gè)short類型的值,由于第一次總線的數(shù)據(jù)只有byte0,byte1,byte2,byte3,取不到byte4,這在DaVinci板子上,就是一個(gè)Bus error了,因?yàn)闆]有達(dá)到邊界對(duì)齊。如果ptr指的是byte2(地址0x02),就沒有問題了。因?yàn)?x02地址值是sizeof(short)的整數(shù)倍。
理解SIGBUS與SIGSEGV

Q: SIGSEGV我能理解,但有時(shí)碰上SIGBUS,這該如何理解。

A: nkwht@SMTH

nkwht用Google獲取這樣一些知識(shí)。有多種可能導(dǎo)致SIGBUS信號(hào):

1) 硬件故障,不用說,程序員最常碰上的肯定不是這種情形。

2) Linux平臺(tái)上執(zhí)行malloc(),如果沒有足夠的RAM,Linux不是讓malloc()失敗返回,
而是向當(dāng)前進(jìn)程分發(fā)SIGBUS信號(hào)。

注: 對(duì)該點(diǎn)執(zhí)懷疑態(tài)度,有機(jī)會(huì)可自行測(cè)試確認(rèn)當(dāng)前系統(tǒng)反應(yīng)。

3) 某些架構(gòu)上訪問數(shù)據(jù)時(shí)有對(duì)齊的要求,比如只能從4字節(jié)邊界上讀取一個(gè)4字節(jié)的
數(shù)據(jù)類型。IA-32架構(gòu)沒有硬性要求對(duì)齊,盡管未對(duì)齊的訪問降低執(zhí)行效率。另外
一些架構(gòu),比如SPARC、m68k,要求對(duì)齊訪問,否則向當(dāng)前進(jìn)程分發(fā)SIGBUS信號(hào)。

SIGBUS與SIGSEGV信號(hào)一樣,可以正常捕獲。SIGBUS的缺省行為是終止當(dāng)前進(jìn)程并產(chǎn)
生core dump。

A: Marc Rochkind <
rochkind@basepath.com>

SIGBUS與SIGSEGV信號(hào)的一般區(qū)別如下:

1) SIGBUS(Bus error)意味著指針?biāo)鶎?duì)應(yīng)的地址是有效地址,但總線不能正常使用該
指針。通常是未對(duì)齊的數(shù)據(jù)訪問所致。

2) SIGSEGV(Segment fault)意味著指針?biāo)鶎?duì)應(yīng)的地址是無效地址,沒有物理內(nèi)存對(duì)
應(yīng)該地址。










歡迎光臨 (http://www.raoushi.com/bbs/) Powered by Discuz! X3.1