android基于Socket的系统调用实现
声明:该文件为本人原创,如转载修改及使用其中图片,请注明出处及原作者。
Author:lanbo(高兆成)
E-mail:lanbo_g@126.com
如有任何疑问可留言或E-mail
系统调用就是用户空间应用程序和内核提供的服务之间的接口。服务是由linux内核提供的,无法直接调用。因此必须使用一个进程来跨越用户空间和内核之间的界限。
今天我们就将从用户层通过socket来分析linux下的系统调用的实现过程。
通过该文章读者可熟悉系统调用的实现
以wpa_supplicant中driver_wext中的socket为例来分析:
要想通过wext与kernel沟通wpa_supplicant中是在wpa_driver_wext_init函数中通过创建socket来实现
Socket定义在bionic/libc/arch-arm/syscalls/socket.S中如下:
#include <sys/linux-syscalls.h>
.text
.type socket, #function
.globl socket
.align 4
.fnstart
socket:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_socket//此处将__NR_socket放入到ARM R7中
swi #0//调用系统中断
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend
__NR_socket 在几个文件中都有定义,我就不确认是调用的kernel/arch/arm/include/asm/Unistd.h还是
ndk/build/platforms/android-8/arch-arm/usr/include/sys/Linux-syscalls.h
#if !defined__ASM_ARM_UNISTD_H && !defined __ASM_I386_UNISTD_H
#if defined__arm__ && !defined __ARM_EABI__ && !defined __thumb__
# define __NR_SYSCALL_BASE 0x900000
#else
# define __NR_SYSCALL_BASE 0
#endif
………………………省略号……………….
#define __NR_socket (__NR_SYSCALL_BASE +281)
如上调用了swi(软中断) ,接下来我们看看中断向量实现。
在ARM V4及V4T以后的大部分处理器中,中断向量表的位置可以有两个位置:一个是0,另一个是0xffff0000。可以通过CP15协处理器c1寄存器中V位(bit[13])控制。V和中断向量表的对应关系如下:
V=0:0x00000000~0x0000001C
V=1:0xffff0000~0xffff001C
arch/arm/mm/proc-arm920.S中
.section".text.init", #alloc, #execinstr
__arm920_setup:
……orr r0, r0,#0x2100 @ ..1. ...1 ..11 ...1
//bit13=1 中断向量表基址为0xFFFF0000。R0的值将被付给CP15的C1.
中断向量在early_trap_init中定义,调用顺序如下:
start_kernel(kernel/init/main.c)==> setup_arch(kernel/arch/arm/kernel/Setup.c)==>early_trap_init(kernel/arch/arm/kernel/Traps.c)
early_trap_init部分代码如下:
unsigned longvectors = CONFIG_VECTORS_BASE;//定义中断向量起始地址
//#defineCONFIG_VECTORS_BASE 0xffff0000定义在kernel/include/linux/Autoconf.h
extern char__stubs_start[], __stubs_end[];
extern char__vectors_start[], __vectors_end[];
//如下做中断向量的搬移动作,为保护模式准备,如上调用swi后PC指针会指向vectors +address 0x00000008。
memcpy((void*)vectors, __vectors_start, __vectors_end -__vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
memcpy((void *)vectors + 0x1000 - kuser_sz,__kuser_helper_start, kuser_sz);
其中__stubs_start[], __stubs_end[],__vectors_start[], __vectors_end[]在kernel/arch/arm/kernel/dntry-armv.S中定义,我们来分析看看如何实现。
.macro vector_stub,name, mode, correction=0//此处定义了一个vector_stub宏定义
.align 5
vector_\name:
.if \correction
sub lr,lr, #\correction
.endif
@
@ Save r0, lr_<exception> (parentPC) and spsr_<exception>
@ (parent CPSR)
@
stmia sp,{r0, lr} @ save r0, lr
mrs lr,spsr
str lr,[sp, #8] @ save spsr
@
@ Prepare for SVC32 mode. IRQs remain disabled.
@
mrs r0,cpsr
eor r0,r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
msr spsr_