大佬教程收集整理的这篇文章主要介绍了Linux系统调用,libc,VDSO和实现解析,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我在最后一个libc中剖析了syscall调用:
git clone git://sourceware.org/git/glibc.git
我在sysdeps / unix / sysv / linux / i386 / sysdep.h中有这个代码:
# definE intERNAL_SYSCall_R_309_11845@AIN_INLINE(name,err,nr,args...) \
LOADREGS_##nr(args) \
asm volatile ( \
"call *%%gs:%P2" \
: "=a" (resultvar) \
: "a" (__NR_##Name),"i" (offsetof (tcbhead_t,sysinfo)) \
AsmaRGS_##nr(args) : "memory","cc")
如果我理解这段代码,那么LOADREGS _ ## nr(args)宏会将参数加载到寄存器ebx,ecx,edx,esi,edx和ebp中.
sysdeps / UNIX / SYSV / LINUX / I386 / sysdep.h中
# define LOADREGS_0()
# define AsmaRGS_0()
# define LOADREGS_1(arg1) \
LOADREGS_0 ()
# define AsmaRGS_1(arg1) \
AsmaRGS_0 (),"b" ((unsigned int) (arg1))
# define LOADREGS_2(arg1,arg2) \
LOADREGS_1 (arg1)
# define AsmaRGS_2(arg1,arg2) \
AsmaRGS_1 (arg1),"c" ((unsigned int) (arg2))
# define LOADREGS_3(arg1,arg2,arg3) \
LOADREGS_2 (arg1,arg2)
# define AsmaRGS_3(arg1,arg3) \
AsmaRGS_2 (arg1,arg2),"d" ((unsigned int) (arg3))
# define LOADREGS_4(arg1,arg3,arg4) \
LOADREGS_3 (arg1,arg3)
# define AsmaRGS_4(arg1,arg4) \
AsmaRGS_3 (arg1,arg3),"S" ((unsigned int) (arg4))
# define LOADREGS_5(arg1,arg4,arg5) \
LOADREGS_4 (arg1,arg4)
# define AsmaRGS_5(arg1,arg5) \
AsmaRGS_4 (arg1,arg4),"D" ((unsigned int) (arg5))
# define LOADREGS_6(arg1,arg5,arg6) \
register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6); \
LOADREGS_5 (arg1,arg5)
# define AsmaRGS_6(arg1,arg6) \
AsmaRGS_5 (arg1,arg5),"r" (_a6)
#endif /* GCC 5 */
enter code here
在ebx,edx和ebp寄存器中加载参数的代码在哪里?这是上面的代码吗?我不明白实施.
以下代码加载ebx寄存器中的第6个参数?
register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6);
这段代码是什么:
AsmaRGS_0 (),"b" ((unsigned int) (arg1))
它加载ebx寄存器中的第一个参数?
然后“call * %% gs:%P2”跳转到VDSO代码?这段代码对应“call * gs:0x10”?
那么,这个写系统调用的下图,它很好吗?:
write(1,"A",1) -----> LIBC -----> VDSO -----> KERNEL
load reg ?
jump to vdso
|---------------------------------------------------|--------------|
user land kernel land
我不懂VDSO实用程序! vdso选择syscall方法(sysenter或int 0x80).
提前谢谢你的帮助.抱歉,我的英语非常糟糕.
LOADREGS_1(args)
asm volatile (
"call *%%gs:%P2"
: "=a" (resultvar)
: "a" (__NR_exit),sysinfo))
AsmaRGS_1(args) : "memory","cc")
LOADREGS_1(args)将扩展为LOADREGS_0(),它将扩展为空 – LOADREGS _ *(…)只需要在提供更多参数时调整寄存器.
AsmaRGS_1(args)将扩展为AsmaRGS_0(),“b”((unsigned int)(arg1)),它将扩展为“b”((unsigned int)(arg1).
x86上__NR_exit为1.
因此,代码将扩展为:
asm volatile (
"call *%%gs:%P2"
: "=a" (resultvar)
: "a" (1),sysinfo)),"b" ((unsigned int) (arg1) : "memory","cc")
AsmaRGS_ *实际上并不执行代码本身 – 它们是gcc的指令,以确保某些值(例如(unsigned int)(arg1))在某些寄存器中(例如b,aka ebX).因此,asm volatile的参数组合(当然,这不是一个函数,只是一个gcc内置函数)只是简单地指定gcc应该如何为系统调用做准备以及在系统调用完成后它应该如何继续.
现在,生成的程序集将如下所示:
; set up other registers...
movl $1,%eax
call *%gs:0x10
; tear down
%gs是一个引用线程本地存储的段寄存器 – 具体来说,glibc引用一个指向VDSO的保存值,当它首次解析说明VDSO所在位置的ELF头时,它存储在那里.
一旦代码进入VDSO,我们就不确切知道发生了什么 – 它取决于内核版本 – 但我们知道它使用最有效的可用机制来运行系统调用,例如sysenter指令或int 0x80指令.
所以,是的,你的图表是准确的:
write(1,1) -----> LIBC -----> VDSO -----> KERNEL
load reg ?
jump to vdso
|---------------------------------------------------|--------------|
user land kernel land
这是一个更简单的代码调用VDSO,特别是对于单参数系统调用,来自我维护的名为libsyscall的库:
_lsc_syscall1:
xchgl 8(%esp),%ebx
movl 4(%esp),%eax
call *_lsc_vdso_ptr(,1)
movl 8(%esp),%ebx
# pass %eax out
ret
这只是将参数从堆栈移到寄存器中,通过从内存加载的指针调用VDSO,将其他寄存器恢复到先前的状态,并返回系统调用的结果.
以上是大佬教程为你收集整理的Linux系统调用,libc,VDSO和实现解析全部内容,希望文章能够帮你解决Linux系统调用,libc,VDSO和实现解析所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。