参考这篇文章:

http://blog.chinaunix.net/uid-24599332-id-2122898.html

SIGBUS和SIGSEGV也许是我们在平时遇到的次数最多的两个内存错误信号。内存问题一直是最令我们头疼的事情,弄清楚两个信号的发生缘由对我们很好的理解程序的运行是大有裨益的。

我们来看两段程序:
//testsigsegv.c
int main() {
        char *pc = (char*)0x00001111;
        *pc = 17;
}

//testsigbus.c
int main() {
        int *pi = (int*)0x00001111;
        *pi = 17;
}

上面的代码那么的相似,我们也同样用gcc编译(加上-g选项,便于gdb调试;平台Solaris Sparc),执行结果也都是dump core。但通过GDB对core进行观察,你会发现细微的不同。

第一个例子出的core原因是:Program terminated with signal 11, Segmentation fault.

而第二个例子的core则提示:Program terminated with signal 10, Bus error. 两者有什么不同呢?这两段代码的共同点都是将一个非法地址赋值给指针变量,然后试图写数据到这个地址。

如果要说清楚这个问题,我们就要结合汇编码和一些计算机的体系结构的知识来共同分析了。

先来看testsigsegv.c的汇编码:
... ...
main:
        !#PROLOGUE# 0
        save    %sp, -120, %sp
        !#PROLOGUE# 1
        sethi   %hi(4096), %i0
        or      %i0, 273, %i0
        st      %i0, [%fp-20]
        ld      [%fp-20], %i1
        mov     17, %i0
        stb     %i0, [%i1]
        nop
        ret
        restore
... ...

我们关注的是这句:stb     %i0, [%i1]
从计算机底层的执行角度来说,过程是如何的呢?%i0寄存器里存储的是立即数17,我们要将之存储到寄存器%i1的值指向的内存地址。这一过程对于CPU来说其指挥执行的正常过程是:将寄存器%i0中的值送上数据总线,将寄存器%i1的值送到地址总线,然后使能控制总线上的写信号完成这一向内存写1 byte数据的过程。

我们再看testsigbus.c的汇编码:
... ...
main:
        !#PROLOGUE# 0
        save    %sp, -120, %sp
        !#PROLOGUE# 1
        sethi   %hi(4096), %i0
        or      %i0, 273, %i0
        st      %i0, [%fp-20]
        ld      [%fp-20], %i1
        mov     17, %i0
        st      %i0, [%i1]
        nop
        ret
        restore
... ...

同样最后一句:st      %i0, [%i1],CPU执行的过程与testsigsegv.c中的一致(只是要存储数据长度是4字节),那为什么产生错误的原因不同呢?一个是SIGSEGV,而另一个是SIGBUS。这里涉及到的就是对内存地址的校验的问题了,包括对内存地址是否对齐的校验以及该内存地址是否合法的校验。

注:gdb看汇编代码,

这可以通过disassemble命令或x命令或类似的命令:

http://blog.csdn.net/mergerly/article/details/8538272

[root@localhost test]# gdb ./a.out -q
(gdb) list
#include<stdio.h>
#include<malloc.h> int callee(int a, int b, int c, int d, int e)
{
return ;
} int main(){
callee(,,,,);
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400463 <main+>: push %rbp
0x0000000000400464 <main+>: mov %rsp,%rbp
0x0000000000400467 <main+>: mov $0x5,%r8d
0x000000000040046d <main+>: mov $0x4,%ecx
0x0000000000400472 <main+>: mov $0x3,%edx
0x0000000000400477 <main+>: mov $0x2,%esi
0x000000000040047c <main+>: mov $0x1,%edi
0x0000000000400481 <main+>: callq 0x400448 <callee>
0x0000000000400486 <main+>: mov $0x2,%eax
0x000000000040048b <main+>: leaveq
0x000000000040048c <main+>: retq
End of assembler dump.
(gdb) x/10i main
0x400463 <main>: push %rbp
0x400464 <main+>: mov %rsp,%rbp
0x400467 <main+>: mov $0x5,%r8d
0x40046d <main+>: mov $0x4,%ecx
0x400472 <main+>: mov $0x3,%edx
0x400477 <main+>: mov $0x2,%esi
0x40047c <main+>: mov $0x1,%edi
0x400481 <main+>: callq 0x400448 <callee>
0x400486 <main+>: mov $0x2,%eax
0x40048b <main+>: leaveq
(gdb)

回到SIGSEGV和SIGBUS

我们假设如果首先进行的内存地址是否合法的校验(是否归属于用户进程的地址空间),那么我们回顾一下,这两个程序中的地址0x00001111显然都不合法,按照这种流程,两个程序都应该是SIGSEGV导致的core才对,但是事实并非如此。那难道是先校验内存地址的对齐?我们再看这种思路是否合理?

testsigsegv.c中,0x00001111这个地址值被赋给了char *pc;也就是告诉CPU通过这个地址我们要存取一个字节的值,对于一个字节长度的数据,无所谓对齐,所以该地址通过对齐校验;

并被放到地址总线上了。而在testsigbus.c里,0x00001111这个地址值被赋给了int *pi;也就是告诉CPU通过这个地址我们要存取一个起码4个字节的值,那么对于长度4个字节的对象,其存放地址起码要被4整除才可以,而0x00001111这个值显然不能满足要求,也就不能通过内存对齐的校验(也就是说地址也要被4整除,否则不对齐)。也就是说SIGBUS这个信号在地址被放到地址总线之后被检查出来的不符合对齐的错误;而SIGSEGV则是在地址已经放到地址总线上后,由后续流程中的某个设施检查出来的内存违法访问错误。

一般我们平时遇到SIGBUS时总是因为地址未对齐导致的,而SIGSEGV则是由于内存地址不合法造成的。

1) SIGBUS(Bus error)意味着指针所对应的地址是有效地址,但总线不能正常使用该指针。通常是未对齐的数据访问所致。
2) SIGSEGV(Segment fault)意味着指针所对应的地址是无效地址,没有物理内存对应该地址。

Linux的mmap(2)手册页
使用映射可能涉及到如下信号
SIGSEGV    试图对只读映射区域进行写操作
SIGBUS     试图访问一块无文件内容对应的内存区域,比如超过文件尾的内存区域,或者以前有文件内容对应,现在为另一进程截断过的内存区域。
 
调试方法:
gcc -g 编译 
ulimit -c 20000 
之后运行程序,等core dump 
最后gdb -c core <exec file> 
 
 

SIGSEGV 和 SIGBUS & gdb看汇编的更多相关文章

  1. GDB调试汇编分析

    GDB调试汇编分析 代码 本次实践我参照了许多先做了的同学的博客,有卢肖明,高其,张梓靖同学.代码借用的是卢肖明同学的代码进行调试运行. GCC编译 使用gcc -g gdbtest.c -o gdb ...

  2. 20145233 GDB调试汇编分析

    GDB调试汇编分析 代码 #include<stdio.h> short addend1 = 1; static int addend2 = 2; const static long ad ...

  3. 20145318 GDB调试汇编堆栈分析

    20145318 GDB调试汇编堆栈分析 代码 #include<stdio.h> short addend1 = 1; static int addend2 = 2; const sta ...

  4. 20145311利用gdb调试汇编代码

    利用GDB调试汇编代码 首先编写c语言原代码,我使用的是同学分析过的代码 #include<stdio.h>short addend1 = 1;static int addend2 = 2 ...

  5. 20145219 gdb调试汇编堆栈分析

    20145219 gdb调试汇编堆栈分析 代码gdbdemo.c int g(int x) { return x+19; } int f(int x) { return g(x); } int mai ...

  6. 20145310 GDB调试汇编堆栈分析

    GDB调试汇编堆栈分析 由于老师说要逐条分析汇编代码,所以我学习卢肖明同学的方法,重新写了一篇博客. 代码: #include<stdio.h> short addend1 = 1; st ...

  7. GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析 分析过程 这是我的C源文件:click here 使用gcc - g example.c -o example -m32指令在64位的机器上产生32位汇编,然后使用gdb ...

  8. 20145212——GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析 测试代码 #include <stdio.h> short val = 1; int vv = 2; int g(int xxx) { return xxx + ...

  9. gdb调试汇编堆栈过程的学习

    gdb调试汇编堆栈过程的学习 以下为C源文件 使用gcc - g code.c -o code -m32指令在64位的机器上产生32位汇编,然后使用gdb example指令进入gdb调试器: 进入之 ...

随机推荐

  1. java https客户端请求

    String pathname = Test3.class.getResource("/client.jks").getFile(); System.out.println(pat ...

  2. opencv边缘滤波

    2018-03-0422:16:11 import cv2 as cv import numpy as np def bi_demo (image): print ("ceshi" ...

  3. git 删除分支如何恢复

    强制删除了一个分支而后又想重新使用这个分支,该怎么找回该分支上的代码呢? 一:问题描述: 今天师父说上线几个功能,让我把开发的分支推送到远程.当打开git就傻眼了,之前开发好的分支被我删除了,就连推送 ...

  4. JavaScript设计模式 (1) 原型模式

    原型模式(Prototype):用原型实例指向创建类对象,使用于创建新对象的类共享原型对象的属性以及方法. //图片轮播类 var LoopImages = function (imgArr, con ...

  5. (转)Hibernate框架基础——多对多关联关系映射

    http://blog.csdn.net/yerenyuan_pku/article/details/52756536 多对多关联关系映射 多对多的实体关系模型也是很常见的,比如学生和课程的关系.一个 ...

  6. wpf 界面加载 Command

    导入 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" <i:Interaction. ...

  7. java面试题链接

    http://blog.csdn.net/jackfrued/article/details/17339393

  8. xmpp使用经验

    IM 标准协议有XMPP\IMPP\PRIM\SIP(SIMPLE)等,其中XMPP基于XML的协议,具备了很好的扩展性(依靠XML的域名空间)并且可以建立在TLS上使用SASL认证. 1.文件比如图 ...

  9. Loj #6000.「 网络流 24 题 」搭配飞行员

    解题思路 考虑如何建模. 既然是网络流,那么肯定要有源点和汇点.而这个题目并没有什么明显的源点和汇点. 想一想,如果一个飞机能够起飞的话,那么必定有一对可以配对的正副驾驶员.也就是说一条曾广路能够上必 ...

  10. <MyBatis>入门一 HelloWorld

    1.HelloWorld 导入依赖 <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependen ...