前言
用户进程有用户态和内核态两种执行状态,用户进程可以通过系统调用陷入内核态,陷入内核态就意味着可以访问内核的资源。
那么如何陷入内核态呢?一般通过同步异常操作来实现。ARM64专门定义了svc指令,用于进入同步异常,也就是说,一旦执行了svc指令,cpu立即跳转到同步异常入口地址处,从这个地址进入内核态。
从glibc说起
要了解系统调用的完整机制,我们可以从glibc入手,因为glibc有很多的系统调用实例。
我们随便找一个库函数,比如tcsetattr,该函数用于设置终端的属性,它会调用__ioctl函数,__ioctl函数在ARM64中的定义如下:
ENTRY(__ioctl)
mov x8, #__NR_ioctl
sxtw x0, w0
svc #0x0
cmn x0, #4095
b.cs .Lsyscall_error
ret
PSEUDO_END (__ioctl)
- 将系统调用号存放在x8寄存器中
- 执行svc指令,陷入异常,并且从el0切换到el1。
异常入口
我们首先来看下ARM64的异常向量表:
ENTRY(vectors)
ventry el1_sync_invalid // Synchronous EL1t
ventry el1_irq_invalid // IRQ EL1t
ventry el1_fiq_invalid // FIQ EL1t
ventry el1_error_invalid // Error EL1t
ventry el1_syn