glibc源码分析(二)系统调用

新博客地址(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文件完成了系统调用的封装。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值