OK6410A 开发板 (八) 62 linux-5.11 OK6410A linux应用空间常见的异常情景及分析

应用程序运行的时候,是感觉不到其他进程的
应用程序运行的时候,有三种情况
	1. 用户空间执行指令
	2. 发生异常陷入内核
		6种异常 // 不包括reset异常 , reset 异常发生后就回不来了
	3. 退出
		正常退出
			1.在main函数中使用了return返回 	// return之后把控制权交给调用函数
			2.调用exit()或者_exit  			// exit()之后把控制权交给系统
		
		异常退出
			1.调用abort函数
				会产生 SIGABRT 信号
			2.进程收到某个信号,而该信号是程序中止
				SIGINT
				SIGFPE 
				SIGSEGV
				SIGPIPE
				SIGALAM
实例1 除0 ,打印 Floating point exception
  • 进程的执行
// 进程A
#include <stdio.h>
int main(void){
        int a = 0;
        int b = 5;
        int c = 0;

        printf("press ENTER to divide\n");
        getchar();

        c = b/a; //执行到这一句发生 data abort 异常


        return 0;
}
// divide-by-zero
// divide by zero
// https://blog.csdn.net/horacen/article/details/107366457
// bl  0 <__aeabi_idiv>
// libgcc.a 中提供了 __aeabi_idiv
// gcc-4.1.2 中 提供了 /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/libgcc.a
  • 代码有没有使用vfp 取决于编译过程
-mfloat-abi=aaa 来指定浮点运算处理方式
-mfpu=bbb来指定浮点协处理的类型
aaa 可取 soft softfp hard
bbb 可取 vfp neon vfpv3 vfpv4 vfpv3-d16 vfpv4-d16

-mfloat-abi=soft	// -msoft-float 与 -mfloat-abi 功能类似
	// 用cpu寄存器(不用vfp寄存器),将除0 在用户空间用 浮点软件库 实现
	// 有没有fpu都不会陷入异常
	// gcc 用的 软件浮点库实现 为 mpfr // The MPFR library is a C library for multiple-precision floating-point computations with correct rounding. 
-mfloat-abi=softfp
	// 用cpu寄存器(不用vfp寄存器),用vfp指令
	// 有fpu,直接执行指令 没有fpu,陷入未定义指令异常,可在异常中模拟该指令
-mfloat-abi=hard
	// 用vfp寄存器,用vfp指令
	// 有fpu,直接执行指令 没有fpu,陷入未定义指令异常,可在异常中模拟该指令
  • vfp有没有 开启
从ARMv5开始,就有可选的 Vector Floating Point
启用的话,要按照以下步骤

1.如果在 Normal World 下需要访问 VFP ,那么必须
	在 Non-Secure Access Control Register (CP15.NSACR) (即在 CP15 register 1 中的 Coprocessor access register) 中必须启用对 CP10 和 CP11 的访问,这通常是在安全引导加载程序中完成的。
	bit[21:20] 0b11
	bit[23:22] 0b11
2.置位(不是清0) VFP专用系统寄存器 FPEXC 寄存器中的 bit[30](EN)
  • next step

下一步可能是 
	1.fpu指令的执行
	2.浮点软件库的执行
	3.未定义指令异常

在这里,根据实际情况来看, 会是 浮点软件库的执行, 浮点软件库由 gcc 提供(不是glibc)
在这里,0 不是 arm异常 检测到的,而是 gcc提供的浮点软件库 检测到的.

	float32 float32_div( float32 a, float32 b )
		bExp = extractFloat32Exp( b );
		if ( bExp == 0 )
			float_raise( float_flag_divbyzero );


--- 其他可能情况下的解释

// 浮点软件库的执行 引起的异常
A coprocessor can partially execute an instruction and then cause an exception. 
This is useful for handling run-time-generated exceptions, like divide-by-zero or overflow. 
However, the partial execution is internal to the coprocessor and is not visible to the ARM processor. 
As far as the ARM processor is concerned, the instruction is held at the start of its execution and completes without exception if allowed to begin execution.
Any decision on whether to execute the instruction or cause an exception is taken within the coprocessor before the ARM processor is allowed to start executing the instruction.

// arm1176 手册上的意思,像是 vfp 异常
The VFP supports all five floating point exceptions defined by the IEEE 754 standard:
• invalid operation
• divide by zero
• overflow
• underflow
• inexact.

You can individually enable or disable these exception traps. 
If disabled, the default results defined by IEEE 754 are returned. 
All rounding modes are supported, and basic single and basic double formats are used.

For full compliance, the VFP requires support code to handle arithmetic where operands or results are de-norms. 
This support code is normally installed on the Undefined instruction exception handler.

  • 信号的发送
SYSCALL_DEFINE0(gettid)
	获取进程的pid
SYSCALL_DEFINE3(tgkill,...,pid_t, pid
SyS_tgkill
	do_tkill
		do_send_specific
			do_send_sig_info
				send_signal (sig=8, info=0xee1fdee4, t=0xeeb317c0, group=0)

  • 信号的接收
sig_kernel_coredump
	do_coredump



  • 用户空间
glibc-2.18/sysdeps/generic/siglist.h
34   init_sig (SIGFPE, "FPE", N_("Floating point exception"))


stdio-common/siglist.c

 23 const char *const _sys_siglist[NSIG] =                                           
 24 {                                                                                
 25 #define init_sig(sig, abbrev, desc)   [sig] = desc,                              
 26 #include <siglist.h>                                                             
 27 #undef init_sig                                                                  
 28 };                                                                               
 29 strong_alias (_sys_siglist, _sys_siglist_internal)                               
 30                                                                                  
 31                                                                                  
 32 const char *const _sys_sigabbrev[NSIG] =                                         
 33 {                                                                                
 34 #define init_sig(sig, abbrev, desc)   [sig] = abbrev,                            
 35 #include <siglist.h>                                                             
 36 #undef init_sig                                                                  
 37 };

sysdeps/gnu/siglist.c

 25 const char *const __new_sys_siglist[NSIG] =                                      
 26 {                                                                                
 27 #define init_sig(sig, abbrev, desc)   [sig] = desc,                              
 28 #include <siglist.h>                                                             
 29 #undef init_sig                                                                  
 30 };                                                                               
 31 libc_hidden_ver (__new_sys_siglist, _sys_siglist)                                
 32                                                                                  
 33 const char *const __new_sys_sigabbrev[NSIG] =                                    
 34 {                                                                                
 35 #define init_sig(sig, abbrev, desc)   [sig] = abbrev,                            
 36 #include <siglist.h>                                                             
 37 #undef init_sig                                                                  
 38 }; 


实例2 空指针的访问 进入 data abort 异常 , 异常退出,打印 Segmentation fault
#include <stdio.h>
int main(void){

        int *p = 0;
        int a = 0;

        printf("press ENTER to devide\n");
        getchar();

        a = *p;
        return 0;
}
  • 异常进入
data abort 异常
  • 信号的发送
__dabt_usr
	...
	do_page_fault
		sig = SIGSEGV;
		code = SEGV_MAPERR;
		__do_user_fault
			force_sig_info
				specific_send_sig_info
					send_signal
						__send_signal

  • 信号的接收
同上
实例3 0地址运行 Segmentation fault
#include <stdio.h>


typedef void(*p_t)(void);

int main(void){

        p_t p = 0;
        p();

        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值