最近在看《深入理解程序设计》,看到说,如不执行系统调用int的后果,汇编,链接后,执行出现段错误。
一 般来说,段错误无非是访问的内存超出了系统所给这个程序的内存空间。 通常这个值是由gdtr来保存的,他是一个48位的寄存器,其中的32位是保存由它指 向的gdt表,后13位保存相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向的gdt是由以64位为一个单位的表,在这张表中就保存着程序运行的代码段以及数据段的起始地址以及与此相应的段限和页面交换还有程序运行级别还有内存粒度等等的信息。一旦一个程序发生了 越界访问,cpu就会产生相应的异常保护,于是segmentation fault就出现了. 在编程中以下几类做法容易导致段错误: 1)访问系统数据区,尤其是往系统保护的内存地址写数据 2)内存越界(数组越界,变量类型不一致等) 3)访问到不属于你的内存区域
1. int指令称为软中断指令,可以用这条指令故意产生一个异常,异常的处理和中断类似,CPU从用户模式切换到特权模式,然后跳转到内核代码中执行异常处理程序。
2. int指令中的立即数0x80是一个参数,在异常处理程序中要根据这个参数决定如何处理,在Linux内核中int $0x80这种异常称为系统调用(System Call)。内核提供了很多系统服务供用户程序使用,但这些系统服务不能像库函数(比如printf)那样调用,因为在执行用户程序时CPU处于用户模式,不能直接调用内核函数,所以需要通过系统调用切换CPU模式,经由异常处理程序进入内核,用户程序只能通过寄存器传几个参数,之后就要按内核设计好的代码路线走,而不能由用户程序随心所欲,想调哪个内核函数就调哪个内核函数,这样可以保证系统服务被安全地调用。在调用结束之后,CPU再切换回用户模式,继续执行int $0x80的下一条指令,在用户程序看来就像函数调用和返回一样。
3. eax和ebx的值是传递给系统调用的两个参数。eax的值是系统调用号,Linux的各种系统调用都是由int $0x80指令引发的,内核需要通过eax判断用户要调哪个系统调用,_exit的系统调用号是1。ebx的值是传给_exit的参数,表示退出状态。大多数系统调用完成之后会返回用户空间继续执行后面的指令,而_exit系统调用比较特殊,它会终止掉当前进程,而不是返回用户空间继续执行。
# goal: exit and return a status flag
#input:
#output: return a status flag
.section .date
.section .text
.globl _start
_start:
movl $1, %eax #用于退出程序的命令LINUX内核命令号(os call)
movl $0, %ebx #返回给 os 的 status flag
// int $0x80 #唤醒内核,exit
我的理解是计算机执行完movl $0, %ebx之后,开始执行下一句,但是,我又没告诉它,执行什么,所以它就执行上一句执行程序所存储的地址的后面的地址的内容,这显然是未知的,所以出现段错误。