微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux系统调用的原理

ARM Linux系统调用的原理

时间:11-09 来源:互联网 点击:

g O_LARGEFILE, mode);

}

libc_hidden_def(__libc_open64)

最终__libc_open64又调用了__libc_open函数,这个函数在文件libc/sysdeps/linux/common/open.c中定义:

libc_hidden_proto(__libc_open)

int __libc_open(const char *file, intoflag, ...)

{

mode_tmode = 0;

if(oflag & O_CREAT) {

va_listarg;

va_start(arg, oflag);

mode= va_arg (arg, mode_t);

va_end (arg);

}

return__syscall_open(file, oflag, mode);

}

libc_hidden_def(__libc_open)

这个函数,也是仅仅根据打开标志oflag的值,来判断是否有第三个参数,若由,则获得其值。之后,便用获得的参数来调用__syscall_open(file,oflag, mode)。

__syscall_open在同一个文件中定义:

static __inline__ _syscall3(int,__syscall_open, const char *, file,

int,flags, __kernel_mode_t, mode)

在文件libc/sysdeps/linux/arm/bits/syscalls.h文件中可以看到:

#undef _syscall3

#define_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \

type name(type1 arg1,type2 arg2,type3arg3) \

{ \

return (type) (INLINE_SYSCALL(name, 3,arg1, arg2, arg3)); \

}

这个宏实际上完成定义一个函数的工作,宏的第一个参数是函数的返回值类型,第二个参数是函数名,之后的参数就如同它们的参数名所表明的那样,分别是函数的参数类型及参数名。__syscall_open实际上为:

int __syscall_open (const char * file,intflags, __kernel_mode_t mode)

{

return (int) (INLINE_SYSCALL(__syscall_open,3, file, flags, mode));

}

INLINE_SYSCALL为同一个文件中定义的宏:

#undef INLINE_SYSCALL

#define INLINE_SYSCALL(name, nr,args...) \

({ unsigned int _inline_sys_result = INTERNAL_SYSCALL (name, , nr,args); \

if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_inline_sys_result, ),0)) \

{ \

__set_errno (INTERNAL_SYSCALL_ERRNO(_inline_sys_result, )); \

_inline_sys_result = (unsigned int) -1; \

} \

(int) _inline_sys_result; })

INLINE_SYSCALL宏中最值得注意的是INTERNAL_SYSCALL,其定义如下:

#undef INTERNAL_SYSCALL

#if !defined(__thumb__)

#if defined(__ARM_EABI__)

#define INTERNAL_SYSCALL(name, err, nr,args...) \

({unsigned int __sys_result; \

{ \

register int _a1 __asm__ ("r0"), _nr __asm__ ("r7"); \

LOAD_ARGS_##nr (args) \

_nr = SYS_ify(name); \

__asm__ __volatile__ ("swi 0x0 @ syscall " #name \

: "=r" (_a1) \

: "r" (_nr) ASM_ARGS_##nr \

: "memory"); \

__sys_result = _a1; \

} \

(int) __sys_result; })

#else /* defined(__ARM_EABI__) */

#define INTERNAL_SYSCALL(name, err, nr,args...) \

({ unsigned int __sys_result; \

{ \

register int _a1 __asm__ ("a1"); \

LOAD_ARGS_##nr (args) \

__asm__ __volatile__ ("swi %1 @ syscall " #name \

: "=r" (_a1) \

: "i" (SYS_ify(name))ASM_ARGS_##nr \

: "memory"); \

__sys_result = _a1; \

} \

(int) __sys_result; })

#endif

这里也将同文件中的LOAD_ARGS宏的定义贴出来:

#define LOAD_ARGS_0()

#define ASM_ARGS_0

#define LOAD_ARGS_1(a1) \

_a1 = (int) (a1); \

LOAD_ARGS_0 ()

#define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1)

#define LOAD_ARGS_2(a1, a2) \

register int _a2 __asm__ ("a2") = (int) (a2); \

LOAD_ARGS_1 (a1)

#define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2)

#define LOAD_ARGS_3(a1, a2, a3) \

register int _a3 __asm__ ("a3") = (int) (a3); \

LOAD_ARGS_2 (a1, a2)

这几个宏用来在寄存器中加载相应的参数,参数传递的方式和普通的C函数也没有什么太大的区别,同样都是将参数列表中的参数依次放入寄存器r0、r1、r2、r3…中。

上面的SYS_ify(name)宏,是用来获得系统调用号的。

#define SYS_ify(syscall_name) (__NR_##syscall_name)

也就是__NR___syscall_open,在libc/sysdeps/linux/common/open.c中可以看到这个宏的定义:

#define __NR___syscall_open __NR_open

__NR_open在内核代码的头文件中有定义。

在这里我们忽略定义__thumb__的情况,而假设我们编译出来的库函数使用的都是ARM指令集。在上面的代码中,我们看到,根据是否定义宏__ARM_EABI__,INTERNAL_SYSCALL会被展开为两种不同的版本。关于这一点,与应用二进制接口ABI有关,不同的ABI,则会有不同的传递系统调用号的方法。对于比较新的EABI,则在r7寄存器保存系统调用号,通过

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top