当前位置:首页 » 编程软件 » gcc编译出来的库出现buserror

gcc编译出来的库出现buserror

发布时间: 2022-11-13 05:30:35

1. gcc编译出现错误怎么办

有时候我们编译一个大的项目的时候,会出现很多错误使得屏幕堆满了很多无用的信息。一般情况下我们需要找到首次出现错误的地方,在gcc中添加编译选项可以使编译停止在第一次出现错误的地方:

$ gcc -Wfatal-errors foo.c // GCC 4.0 and later$ g++ -Wfatal-errors foo.cpp
$ g++ -fmax-errors=N foo.cpp // 在出现第 N 此错误的时候停止编译,GCC 4.6 and later

2. 为什么程序会出现Bus Error

最近在论坛上看到一个程序员在询问Bus Error的问题。他有一个非常简单的测试程序,将一个short数组中第二个成员变量的地址附给一个int型的指针,接着给该指针赋值,大致代码如下:
short array[10];
int * p = (int *) &array[1];*p = 1;
运行的平台是Solaris for SPARC,使用的编译器是GCC,程序执行到指针赋值的时候的出现Bus Error出错信息,程序coremp。他觉得非常奇怪,代码在X86平台运行的很好。其实这个问题完全是由于CPU硬件不同所造成的。
Bus Error通常都是因为非对齐访问造成的。CPU在设计上为了性能上的考虑,要求待访问,操作的数据地址都要对齐。如果发现没有对齐的访问,就会向当前进程发出SIGBUS信号,使程序崩溃。RISC包括SPARC都是这种类型的芯片。而X86架构就没有这种对齐要求。所以这段代码在Solaris 10 for X86下面没有问题,当然这是有性能的代价。Bus Error也有可能是因为机器物理问题或者访问无效物理地址,但这种情况非常少见。
上面的代码正是这种非对齐访问造成的Bus Error。short是两个字节,其地址偏移量必是2的倍数。而对于int指针来说,需要偏移量地址是4的倍数的数据,所以直接用int指针来操作地址,就很有可能导致系统发出SIGBUS信号,程序崩溃。
这段程序如果用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;}

3. 如何解决bus error

在x86+linux上写的程序,在PC机上运行得很好。可是使用ARM的gcc进行交叉编译,再送到DaVinci目标板上运行的时候,出现了Bus error。
出现的位置如下(其中Debug的内容是我在程序中添加的调试信息):
[email protected]:~# arm_v5t_le-gcc -g shit.c
[email protected]:~# ./a.out
Debug: malloc space for the actual data: temp_buf = 0x13118
Debug: in my_recvn()
Debug: nleft = 52
Bus error
打开调试器进行调试:
[email protected]:~# 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 ing" 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".

4. 为什么程序会出现Bus Error

最近在论坛上看到一个程序员在询问Bus Error的问题。他有一个非常简单的测试程序,将一个short数组中第二个成员变量的地址附给一个int型的指针,接着给该指针赋值,大致代码如下:

short array[10];
int * p = (int *) &array[1];
*p = 1;
运行的平台是Solaris for SPARC,使用的编译器是GCC,程序执行到指针赋值的时候的出现Bus Error出错信息,程序coremp。他觉得非常奇怪,代码在X86平台运行的很好。其实这个问题完全是由于CPU硬件不同所造成的。

Bus Error通常都是因为非对齐访问造成的。CPU在设计上为了性能上的考虑,要求待访问,操作的数据地址都要对齐。如果发现没有对齐的访问,就会向当前进程发出SIGBUS信号,使程序崩溃。RISC包括SPARC都是这种类型的芯片。而X86架构就没有这种对齐要求。所以这段代码在Solaris 10 for X86下面没有问题,当然这是有性能的代价。Bus Error也有可能是因为机器物理问题或者访问无效物理地址,但这种情况非常少见。

上面的代码正是这种非对齐访问造成的Bus Error。short是两个字节,其地址偏移量必是2的倍数。而对于int指针来说,需要偏移量地址是4的倍数的数据,所以直接用int指针来操作地址,就很有可能导致系统发出SIGBUS信号,程序崩溃。

这段程序如果用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;
}

5. 为什么程序会出现Bus Error

最近在论坛上看到一个程序员在询问Bus Error的问题。他有一个非常简单的测试程序,将一个short数组中第二个成员变量的地址附给一个int型的指针,接着给该指针赋值,大致代码如下:
short array[10];
int * p = (int *) &array[1];*p = 1;
运行的平台是Solaris for SPARC,使用的编译器是GCC,程序执行到指针赋值的时候的出现Bus Error出错信息,程序coremp。他觉得非常奇怪,代码在X86平台运行的很好。其实这个问题完全是由于CPU硬件不同所造成的。
Bus Error通常都是因为非对齐访问造成的。CPU在设计上为了性能上的考虑,要求待访问,操作的数据地址都要对齐。如果发现没有对齐的访问,就会向当前进程发出SIGBUS信号,使程序崩溃。RISC包括SPARC都是这种类型的芯片。而X86架构就没有这种对齐要求。所以这段代码在Solaris 10 for X86下面没有问题,当然这是有性能的代价。Bus Error也有可能是因为机器物理问题或者访问无效物理地址,但这种情况非常少见。

6. 程序报出bus err 错误后什么不能用backtrace没有输出内容

×

loading..

资讯
安全
论坛
下载
读书
程序开发
数据库
系统
网络
电子书
微信学院
站长学院
QQ
手机软件
考试

软件开发|
web前端|
Web开发|
移动开发|
综合编程|

首页 > 程序开发 > 软件开发 > C语言 > 正文

善用backtrace解决大问题

2011-07-22
0 个评论

收藏

我要投稿

一.用途:

主要用于程序异常退出时寻找错误原因

二.功能:

回溯堆栈,简单的说就是可以列出当前函数调用关系

三.原理:

1. 通过对当前堆栈的分析,找到其上层函数在栈中的帧地址,再分析上层函数的堆栈,再找再上层的帧地址……一直找到最顶层为止,帧地址指的是一块:在栈上存放局部变量,上层返回地址,及寄存器值的空间。

2.
由于不同处理器堆栈方式不同,此功能的具体实现是编译器的内建函数__buildin_frame_address及
__buildin_return_address中,它涉及工具glibc和gcc,
如果编译器不支持此函数,也可自己实现此函数,举例中有arm上的实现

四.方法:

在程序中加入backtrace及相关函数调用

五.举例:

1. 一般backtrace的实现

i. 程序

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <execinfo.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <string.h>

#include <unistd.h>

#define PRINT_DEBUG

static void print_reason(int sig, siginfo_t * info, void *secret)

{

void *array[10];

size_t size;

#ifdef PRINT_DEBUG

char **strings;

size_t i;

size = backtrace(array, 10);

strings = backtrace_symbols(array, size);

printf("Obtained %zd stack frames.\n", size);

for (i = 0; i < size; i++)

printf("%s\n", strings[i]);

free(strings);

#else

int fd = open("err.log", O_CREAT | O_WRONLY);

size = backtrace(array, 10);

backtrace_symbols_fd(array, size, fd);

close(fd);

#endif

exit(0);

}

void die()

{

char *test1;

char *test2;

char *test3;

char *test4 = NULL;

strcpy(test4, "ab");

}

void test1()

{

die();

}

int main(int argc, char **argv)

{

struct sigaction myAction;

myAction.sa_sigaction = print_reason;

sigemptyset(&myAction.sa_mask);

myAction.sa_flags = SA_RESTART | SA_SIGINFO;

sigaction(SIGSEGV, &myAction, NULL);

sigaction(SIGUSR1, &myAction, NULL);

sigaction(SIGFPE, &myAction, NULL);

sigaction(SIGILL, &myAction, NULL);

sigaction(SIGBUS, &myAction, NULL);

sigaction(SIGABRT, &myAction, NULL);

sigaction(SIGSYS, &myAction, NULL);

test1();

}

ii. 编译参数

gcc main.c -o test -g -rdynamic

2. 根据不同的处理器自已实现backtrace

i. arm的backtrace函数实现

static int backtrace_xy(void **BUFFER, int SIZE)

{

volatile int n = 0;

volatile int *p;

volatile int *q;

volatile int ebp1;

volatile int eip1;

volatile int i = 0;

p = &n;

ebp1 = p[4];

eip1 = p[6];

fprintf(stderr, "======================= backtrace_xy addr: 0x%0x, param1: 0x%0x, param2: 0x%0x\n",

backtrace_xy, &BUFFER, &SIZE);

fprintf(stderr, "n addr is 0x%0x\n", &n);

fprintf(stderr, "p addr is 0x%0x\n", &p);

for (i = 0; i < SIZE; i++)

{

fprintf(stderr, "ebp1 is 0x%0x, eip1 is 0x%0x\n", ebp1, eip1);

BUFFER[i] = (void *)eip1;

p = (int*)ebp1;

q = p - 5;

eip1 = q[5];

ebp1 = q[2];

if (ebp1 == 0 || eip1 == 0)

break;

}

fprintf(stderr, "total level: %d\n", i);

return i;

}

六.举例2:

/*main.c*/

#include "sigsegv.h"

#include <string.h>

int die() {

char *err = NULL;

strcpy(err, "gonner");

return 0;

}

int main() {

return die();

}

/*sigsegv.c*/

#define _GNU_SOURCE

#include <memory.h>

#include <stdlib.h>

#include <stdio.h>

#include <signal.h>

#include <ucontext.h>

#include <dlfcn.h>

#include <execinfo.h>

#define NO_CPP_DEMANGLE

#ifndef NO_CPP_DEMANGLE

#include <cxxabi.h>

#endif

#if defined(REG_RIP)

# define SIGSEGV_STACK_IA64

# define REGFORMAT "%016lx"

#elif defined(REG_EIP)

# define SIGSEGV_STACK_X86

# define REGFORMAT "%08x"

#else

# define SIGSEGV_STACK_GENERIC

# define REGFORMAT "%x"

#endif

static void signal_segv(int signum, siginfo_t* info, void*ptr) {

static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};

size_t i;

ucontext_t *ucontext = (ucontext_t*)ptr;

#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)

int f = 0;

Dl_info dlinfo;

void **bp = 0;

void *ip = 0;

#else

void *bt[20];

char **strings;

size_t sz;

#endif

fprintf(stderr, "Segmentation Fault!\n");

fprintf(stderr, "info->si_signo = %d\n", signum);

fprintf(stderr, "info->si_errno = %d\n", info->si_errno);

// fprintf(stderr, "info->si_code = %d (%s)\n", info->si_code, info->si_codes[si_code]);

fprintf(stderr, "info->si_addr = %p\n", info->si_addr);

for(i = 0; i < NGREG; i++)

fprintf(stderr, "reg[%02d] = 0x" REGFORMAT "\n", i, ucontext->uc_mcontext.gregs[i]);

#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)

# if defined(SIGSEGV_STACK_IA64)

ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];

bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];

# elif defined(SIGSEGV_STACK_X86)

ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];

bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];

# endif

fprintf(stderr, "Stack trace:\n");

while(bp != & ip) {

if(!dladdr(ip, &dlinfo))

break;

const char *symname = dlinfo.dli_sname;

#ifndef NO_CPP_DEMANGLE

int status;

char *tmp = __cxa_demangle(symname, NULL, 0, &status);

if(status == 0 !=& tmp)

symname = tmp;

#endif

fprintf(stderr, "% 2d: %p < %s+%u> (%s)\n",

++f,

ip,

symname,

(unsigned)(ip - dlinfo.dli_saddr),

dlinfo.dli_fname);

#ifndef NO_CPP_DEMANGLE

if(tmp)

free(tmp);

#endif

if(dlinfo.dli_sname != !strcmp(dlinfo.dli_sname, "main"))

break;

ip = bp[1];

bp = (void**)bp[0];

}

#else

fprintf(stderr, "Stack trace (non-dedicated):\n");

sz = backtrace(bt, 20);

strings = backtrace_symbols(bt, sz);

for(i = 0; i < sz; ++i)

fprintf(stderr, "%s\n", strings[i]);

#endif

fprintf(stderr, "End of stack trace\n");

exit (-1);

}

int setup_sigsegv() {

struct sigaction action;

memset(&action, 0, sizeof(action));

action.sa_sigaction = signal_segv;

action.sa_flags = SA_SIGINFO;

if(sigaction(SIGSEGV, &action, NULL) < 0) {

perror("sigaction");

return 0;

}

return 1;

}

#ifndef SIGSEGV_NO_AUTO_INIT

static void __attribute((constructor)) init(void)

{

setup_sigsegv();

}

#endif

/*sigsegv.h*/

#ifndef __sigsegv_h__

#define __sigsegv_h__

#ifdef __cplusplus

extern "C" {

#endif

int setup_sigsegv();

#ifdef __cplusplus

}

#endif

#endif /* __sigsegv_h__ */

编译时需要加入-rdynamic -ldl –ggdb

void

handle_signal_error(int rec_signal,siginfo_t* signal_info,void* context)

{

NE_Info* __attribute__ ((unused)) ne_info = NULL;

struct sigaction action;

FILE* file;

void* backtr[NUMBER_OF_BACKTRACE];

cpal_uns32 __attribute__ ((unused)) i = 0;

cpal_uns32 backtr_size = 0;

ucontext_t *u_context;

time_t seconds_time;

struct tm* time_struct;

cpal_si32 ret_t;

char filename[SIZE_OF_FILENAME];

if(g_handler_running)

return;

g_handler_running = CPAL_TRUE;

ret_t = time(&seconds_time);

if(ret_t != - 1)

{

time_struct = gmtime(&seconds_time);

snprintf(filename,SIZE_OF_FILENAME,"%s%d%d%d-%d%d%d-%s",BACKTRACE_FILE_PATH,time_struct->tm_mon,time_struct->tm_mday,

(time_struct->tm_year-100)+2000,time_struct->tm_hour,time_struct->tm_min,time_struct->tm_sec,BACKTRACE_FILE);

}

else

{

snprintf(filename,SIZE_OF_FILENAME,"%s",BACKTRACE_FILE);

}

file = fopen(filename,"w");

if(file == NULL)

{

return;

}

if(signal_info == NULL)

{

return;

}

if(context == NULL)

{

return;

}

u_context = (ucontext_t*)context;

/*Restore the default action for this signal and re-raise it, so that the default action occurs. */

action.sa_sigaction = SIG_DFL;

sigemptyset(&action.sa_mask);

action.sa_flags = SA_RESTART;

sigaction(rec_signal,&action,NULL);

/* Print out the backtrace. */

backtr_size = backtrace(backtr,20);

/* The backtrace points to sigaction in libc, not to where the signal was actually raised.

This overwrites the sigaction with where the signal was sent, so we can resolve the sender. */

#if __WORDSIZE == 64

backtr[1] = (void*)u_context->uc_mcontext.gregs[REG_RIP];

#else

backtr[1] = (void*)u_context->uc_mcontext.gregs[REG_EIP];

#endif //__WORDSIZE

backtrace_symbols_fd(backtr,backtr_size,fileno(file));

fprintf(file,"Backtrace is above.\nFatal signal %d received.\n",rec_signal);

#if __WORDSIZE == 64

fprintf(file,"Signal received at address %p from 0x%08x.\n",signal_info->si_addr,

u_context->uc_mcontext.gregs[REG_RIP]);

#else

fprintf(file,"Signal received at address %p from 0x%08x.\n",signal_info->si_addr,

u_context->uc_mcontext.gregs[REG_EIP]);

#endif //__WORDSIZE

#if CPAL_LM_DEBUG

/* Print all NE_Infos */

for(; i < MAX_NO_OF_CONNS; i++)

{

ne_info = g_ne_hash_tab[i];

while(ne_info != NULL)

{

ne_info = ne_info->next_ne;

}

}

#endif

fflush(file);

fclose(file);

sleep (50); /* Sleep for 50 seconds */

g_handler_running = *_FALSE;

raise(rec_signal);

}

7. 如何解决bus error

在x86+Linux上写的程序,在PC机上运行得很好。可是使用ARM的gcc进行交叉编译,再送到DaVinci目标板上运行的时候,出现了Bus error。
出现的位置如下(其中Debug的内容是我在程序中添加的调试信息):
[email protected]:~# arm_v5t_le-gcc -g shit.c
[email protected]:~# ./a.out
Debug: malloc space for the actual data: temp_buf = 0x13118
Debug: in my_recvn()
Debug: nleft = 52
Bus error
打开调试器进行调试:
[email protected]:~# 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 ing" 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 // 运行程序
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. // 在这里出现了错误
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" // 地址起始是奇数!!!
(gdb) set ptr=0x1311a // 想改一下
(gdb) continue
Continuing.

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

其中,g_data_ptr->progtype_num是一个short类型的值。
把强制类型转换改为用memcpy()写值之后,再调试
[email protected]:~# 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 ing" 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 // 把刚刚的那句强制类型转换变成内存拷贝
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" // 还是奇数地址
(gdb) continue // 继续执行
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. // 执行通过了!!!!
(gdb)

总结:
问题总算找到了,就是我企图在一个奇数地址起始的地方强制类型转换得到一个short值。
在Intel系列处理器上,可以在任一奇数内存地址储存任何变量或数组,不会导致任何致命的错误影响,只是效率可能会降低。但在DaVinci上,这一点不行。所以必须对大于一个字节的数据类型小心谨慎,比较安全的方法是使用内存拷贝函数memcpy(),或者使用下面的代替方法:
// 先定义一个联合体
union {
short short_val ;
char short_byte[2] ;
} myshort ;
// 然后,把程序中本来应该是
// 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 ;
// 当然,最简单的方法是换成下面两句:
// memcpy(&(g_data_ptr->progtype_num), ptr, 2) ;
// ptr += 2 ;

对于这个问题的进一步探讨:
在DaVinci上应该注意内存编址模式的问题。
struct {
char struc_char ;
int struc_int ;
short struc_short ;
long struct_long ;
} struc_val ;
在宽松模式下,尽管struc_char只有1个字节,struc_short占2个字节,但编译器可能给这两个变量分别分配了4个字节,结果整个结构的大小变成了16个字节,而在编译器设为紧凑模式时,则正好是11个字节。根据计算机数据总线的位数,不同的编址模式存取数据的速度不一样。我认为在符合总线字长的情况下,效率是最高的,因为只需进行一次总线操作。
内存编址模式会影响字节对齐方式,字节对齐操作可以解决以下两个主要的问题:
1.访存效率问题;一般的编译器要对内存进行对齐,在处理变量时,编译器会根据一定的设置将长短不同的变量的数据长度进行对齐以加快内存处理速度。
2.强制类型转换问题:在x86上,字节不对齐的操作只会影响效率,但是在DaVinci上,可能就是一个Bus error, 因为它要求必须字节对齐。
字节对齐的准则
1.数据类型自身的对齐值:对于char型数据,其自身对齐值为1,对于short型为2,对于int,long,float,double类型,其自身对齐值为4字节。
2.结构体的自身对齐值:其成员中自身对齐值最大的那个值。
3.指定对齐值:#pragma pack (value)时的指定对齐值value。
4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
对于平时定义变量,尽可能先定义长度为4的倍数的变量,然后是长度是2的变量,最后是长度为1的变量。

通过测试,GCC编译器是按照4字节对齐存放于内存的。而我还没有发现更改编址模式的参数。程序如下:
#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 ;
}
测试结果:
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

所以对于一个32位的数据来讲,如果其没有在4字节整除的内存地址处存放,那么处理器就需要2个总线周期对其进行访问。
0x08 | byte8 | byte9 | byteA | byteB |
0x04 | byte4 | byte5 | byte6 | byte7 |
0x00 | byte0 | byte1 | byte2 | byte3 |
对于我刚刚的那个出现Bus error的程序,假设指针ptr刚好是指向了byte3(地址是0x0),然后想进行short强制类型转换,使用byte3,byte4来构成一个short类型的值,由于第一次总线的数据只有byte0,byte1,byte2,byte3,取不到byte4,这在DaVinci板子上,就是一个Bus error了,因为没有达到边界对齐。如果ptr指的是byte2(地址0x02),就没有问题了。因为0x02地址值是sizeof(short)的整数倍。

8. arm-linux-gcc 编译简单的helloworld 程序出现bus error,这有什么办法解决吗

是gcc的问题。
要不你下载2009q3试试.
http://crztech.iptime.org:8080/Release/Toolchain/arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2
我测试了,没问题,编译出来的程序在目标板(arm11,cortex-a8)上运行也正常。

9. 为什么程序会出现Bus Error

最近在论坛上看到一个程序员在询问Bus Error的问题。他有一个非常简单的测试程序,将一个short数组中第二个成员变量的地址附给一个int型的指针,接着给该指针赋值,大致代码如下:
short array[10];
int * p = (int *) &array[1];*p = 1;
运行的平台是Solaris for SPARC,使用的编译器是GCC,程序执行到指针赋值的时候的出现Bus Error出错信息,程序coremp。他觉得非常奇怪,代码在X86平台运行的很好。其实这个问题完全是由于CPU硬件不同所造成的。
Bus Error通常都是因为非对齐访问造成的。CPU在设计上为了性能上的考虑,要求待访问,操作的数据地址都要对齐。如果发现没有对齐的访问,就会向当前进程发出SIGBUS信号,使程序崩溃。RISC包括SPARC都是这种类型的芯片。而X86架构就没有这种对齐要求。所以这段代码在Solaris 10 for X86下面没有问题,当然这是有性能的代价。Bus Error也有可能是因为机器物理问题或者访问无效物理地址,但这种情况非常少见。
上面的代码正是这种非对齐访问造成的Bus Error。short是两个字节,其地址偏移量必是2的倍数。而对于int指针来说,需要偏移量地址是4的倍数的数据,所以直接用int指针来操作地址,就很有可能导致系统发出SIGBUS信号,程序崩溃。
这段程序如果用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;}

10. 为什么程序会出现Bus Error

最近在论坛上看到一个程序员在询问Bus Error的问题。他有一个非常简单的测试程序,将一个short数组中第二个成员变量的地址附给一个int型的指针,接着给该指针赋值,大致代码如下: short array[10]; int * p = (int *) &array[1];*p = 1; 运行的平台是Solaris for SPARC,使用的编译器是GCC,程序执行到指针赋值的时候的出现Bus Error出错信息,程序coremp。他觉得非常奇怪,代码在X86平台运行的很好。其实这个问题完全是由于CPU硬件不同所造成的。 Bus Error通常都是因为非对齐访问造成的。CPU在设计上为了性能上的考虑,要求待访问,操作的数据地址都要对齐。如果发现没有对齐的访问,就会向当前进程发出SIGBUS信号,使程序崩溃。RISC包括SPARC都是这种类型的芯片。而X86架构就没有这种对齐要求。所以这段代码在Solaris 10 for X86下面没有问题,当然这是有性能的代价。Bus Error也有可能是因为机器物理问题或者访问无效物理地址,但这种情况非常少见。 上面的代码正是这种非对齐访问造成的Bus Error。short是两个字节,其地址偏移量必是2的倍数。而对于int指针来说,需要偏移量地址是4的倍数的数据,所以直接用int指针来操作地址,就很有可能导致系统发出SIGBUS信号,程序崩溃。 这段程序如果用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;}

热点内容
分布式缓存部署步骤 发布:2025-05-14 13:24:51 浏览:609
php获取上一月 发布:2025-05-14 13:22:52 浏览:88
购买云服务器并搭建自己网站 发布:2025-05-14 13:20:31 浏览:688
sqlserver建立视图 发布:2025-05-14 13:11:56 浏览:484
搭建httpsgit服务器搭建 发布:2025-05-14 13:09:47 浏览:255
新电脑拿回来我该怎么配置 发布:2025-05-14 13:09:45 浏览:240
视频服务器新建ftp用户 发布:2025-05-14 13:03:09 浏览:225
php花生 发布:2025-05-14 12:54:30 浏览:550
java人才 发布:2025-05-14 12:29:10 浏览:649
如何打开软密码 发布:2025-05-14 12:28:55 浏览:427