新博客地址(shankusu.me)
1.6 .c封装
glibc中许多系统调用是用.c封装的方式封装的。
.c封装都是借助嵌入式汇编,按照系统调用的封装规则进行封装的。
可以查看stat64函数的实现,来探究.c封装。
#undef stat64
int
attribute_hidden
stat64 (const char *file, struct stat64 *buf)
{
return __xstat64 (_STAT_VER, file, buf);
}
int
___xstat64 (int vers, const char *name, struct stat64 *buf)
{
int result;
result = INLINE_SYSCALL (stat64, 2, name, buf);
return result;
}
源码中使用了INLINE_SYSCALL 宏封装了stat64系统调用。
1.6.1 INLINE_SYSCALL
# define INLINE_SYSCALL(name, nr, args...) \
({ \
unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args); \
__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, )) \
? __syscall_error (-INTERNAL_SYSCALL_ERRNO (resultvar, )) \
: (int) resultvar; })
INLINE_SYSCALL宏首先执行INTERNAL_SYSCALL宏。INTERNAL_SYSCALL宏调用了系统调用,并将返回值放入resultvar中。然后判断系统调用是否执行错误。
#undef INTERNAL_SYSCALL_ERROR_P
#define INTERNAL_SYSCALL_ERROR_P(val, err) \
((unsigned int) (val) >= 0xfffff001u)
#define __glibc_unlikely(cond)(cond)
如果执行错误,则调用__syscall_error 设置errno,并返回-1。如果执行成功,则返回resultvar。
1.6.2 INTERNAL_SYSCALL
#define INTERNAL_SYSCALL(name, err, nr, args...) \
({ \
register unsigned int resultvar; \
INTERNAL_SYSCALL_MAIN_##nr (name, err, args); \
(int) resultvar; })
INTERNAL_SYSCALL宏根据系统调用参数的个数nr调用INTERNAL_SYSCALL_MAIN_0至INTERNAL_SYSCALL_MAIN_6宏。
当nr为0,调用INTERNAL_SYSCALL_MAIN_0宏。
#define INTERNAL_SYSCALL_MAIN_0(name, err, args...) \
INTERNAL_SYSCALL_MAIN_INLINE(name, err, 0, args)
# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
LOADREGS_##nr(args) \
asm volatile ( \
"call *_dl_sysinfo" \
: "=a" (resultvar) \
: "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc")
# define LOADREGS_0()
# define ASMARGS_0()
设置eax寄存器为系统调用号,执行call *_dl_sysinfo执行系统调用。
当nr为1,调用INTERNAL_SYSCALL_MAIN_1宏。
#define INTERNAL_SYSCALL_MAIN_1(name, err, args...) \
INTERNAL_SYSCALL_MAIN_INLINE(name, err, 1, args)
# define LOADREGS_1(arg1) \
LOADREGS_0 ()
# define ASMARGS_1(arg1) \
ASMARGS_0 (), "b" ((unsigned int) (arg1))
设置ebx寄存器为参数1,设置eax寄存器为系统调用号,执行call *_dl_sysinfo执行系统调用。
当nr为2,调用INTERNAL_SYSCALL_MAIN_2宏。
#define INTERNAL_SYSCALL_MAIN_2(name, err, args...) \
INTERNAL_SYSCALL_MAIN_INLINE(name, err, 2, args)
# define LOADREGS_2(arg1, arg2) \
LOADREGS_1 (arg1)
# define ASMARGS_2(arg1, arg2) \
ASMARGS_1 (arg1), "c" ((unsigned int) (arg2))
设置ecx寄存器为蚕食2,设置ebx寄存器为参数1,设置eax寄存器为系统调用号,执行call *_dl_sysinfo执行系统调用。
当nr为3,调用INTERNAL_SYSCALL_MAIN_3宏。
#define INTERNAL_SYSCALL_MAIN_3(name, err, args...) \
INTERNAL_SYSCALL_MAIN_INLINE(name, err, 3, args)
# define LOADREGS_3(arg1, arg2, arg3) \
LOADREGS_2 (arg1, arg2)
# define ASMARGS_3(arg1, arg2, arg3) \
ASMARGS_2 (arg1, arg2), "d" ((unsigned int) (arg3))
设置edx寄存器为参数3,设置ecx寄存器为参数2,设置ebx寄存器为参数1,设置eax寄存器为系统调用号,执行call *_dl_sysinfo执行系统调用。
当nr为4,调用INTERNAL_SYSCALL_MAIN_4宏。
#define INTERNAL_SYSCALL_MAIN_4(name, err, args...) \
INTERNAL_SYSCALL_MAIN_INLINE(name, err, 4, args)
# define LOADREGS_4(arg1, arg2, arg3, arg4) \
LOADREGS_3 (arg1, arg2, arg3)
# define ASMARGS_4(arg1, arg2, arg3, arg4) \
ASMARGS_3 (arg1, arg2, arg3), "S" ((unsigned int) (arg4))
设置esi为参数4,设置edx寄存器为参数3,设置ecx寄存器为参数2,设置ebx寄存器为参数1,设置eax寄存器为系统调用号,执行call *_dl_sysinfo执行系统调用。
当nr为5,调用INTERNAL_SYSCALL_MAIN_5宏。
#define INTERNAL_SYSCALL_MAIN_5(name, err, args...) \
INTERNAL_SYSCALL_MAIN_INLINE(name, err, 5, args)
# define LOADREGS_5(arg1, arg2, arg3, arg4, arg5) \
LOADREGS_4 (arg1, arg2, arg3, arg4)
# define ASMARGS_5(arg1, arg2, arg3, arg4, arg5) \
ASMARGS_4 (arg1, arg2, arg3, arg4), "D" ((unsigned int) (arg5))
设置edi为参数5,设置esi为参数4,设置edx寄存器为参数3,设置ecx寄存器为参数2,设置ebx寄存器为参数1,设置eax寄存器为系统调用号,执行call *_dl_sysinfo执行系统调用。
当nr为6,调用INTERNAL_SYSCALL_MAIN_6宏。
# define INTERNAL_SYSCALL_MAIN_6(name, err, args...) \
INTERNAL_SYSCALL_MAIN_INLINE(name, err, 6, args)
# define LOADREGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \
register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6); \
LOADREGS_5 (arg1, arg2, arg3, arg4, arg5)
# define ASMARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \
ASMARGS_5 (arg1, arg2, arg3, arg4, arg5), "r" (_a6)
设置ebp寄存器为参数6,设置edi为参数5,设置esi为参数4,设置edx寄存器为参数3,设置ecx寄存器为参数2,设置ebx寄存器为参数1,设置eax寄存器为系统调用号,执行call *_dl_sysinfo执行系统调用。
通过嵌入式汇编,.c文件完成了系统调用的封装。