编辑
2025-01-22
工作知识
0
请注意,本文编写于 135 天前,最后修改于 135 天前,其中某些信息可能已经过时。

目录

一、vDSO的符号
二、实现vDSO的调用
三、生成vdso.so
四、测试vDSO调用

根据vDSO--内核原理我们可以对一个syscall来进行vDSO的优化,再根据vDSO--示例之实现系统调用我们实现了一个自己的系统调用__do_sys_kylin,这里我们将__do_sys_kylin加入到vDSO中

一、vDSO的符号

我们从lds可以发现需要导出符号,所以我们添加一个__kernel_kylin的符号给应用,代码如下:

# git diff vdso/vdso.lds.S diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S index b840ab1b705c..c766afed0ec8 100644 --- a/arch/arm64/kernel/vdso/vdso.lds.S +++ b/arch/arm64/kernel/vdso/vdso.lds.S @@ -84,6 +84,7 @@ VERSION global: __kernel_rt_sigreturn; __kernel_gettimeofday; + __kernel_kylin; __kernel_clock_gettime; __kernel_clock_getres; local: *;

二、实现vDSO的调用

为了完成vDSO的实验,我没有去故意设置vvar的值来获取,而是在vDSO中嵌套了一个syscall,这样方便大家理解,如下:

# git diff vdso/vgettimeofday.c diff --git a/arch/arm64/kernel/vdso/vgettimeofday.c b/arch/arm64/kernel/vdso/vgettimeofday.c index 4236cf34d7d9..0005f42565d9 100644 --- a/arch/arm64/kernel/vdso/vgettimeofday.c +++ b/arch/arm64/kernel/vdso/vgettimeofday.c @@ -18,6 +18,22 @@ int __kernel_gettimeofday(struct __kernel_old_timeval *tv, return __cvdso_gettimeofday(tv, tz); } +int __kernel_kylin(char* words) +{ + register char *word asm("x0") = words; + register long ret asm("x0"); +#define __NR_sys_kylin 449 + register long nr asm("x8") = __NR_sys_kylin; + + asm volatile( + " svc #0\n" + : "=r" (ret) + : "r" (word), "r" (nr) + : "memory"); + + return ret; +} +

三、生成vdso.so

至此vDSO的函数实现已经完成了,我们编译vdso.so即可。编译后文件如下:

arch/arm64/kernel/vdso/vdso.so

此时我们看看符号是否增加,如下:

# readelf -s arch/arm64/kernel/vdso/vdso.so Symbol table '.dynsym' contains 7 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 OBJECT GLOBAL DEFAULT ABS LINUX_2.6.39 2: 0000000000000780 108 FUNC GLOBAL DEFAULT 7 __kernel_clock_getres@@LINUX_2.6.39 3: 00000000000007f0 8 NOTYPE GLOBAL DEFAULT 7 __kernel_rt_sigreturn@@LINUX_2.6.39 4: 00000000000005c0 424 FUNC GLOBAL DEFAULT 7 __kernel_gettimeofday@@LINUX_2.6.39 5: 0000000000000770 12 FUNC GLOBAL DEFAULT 7 __kernel_kylin@@LINUX_2.6.39 6: 0000000000000320 664 FUNC GLOBAL DEFAULT 7 __kernel_clock_gettime@@LINUX_2.6.39

我们看一下符号的代码段内容

# objdump --disassemble=__kernel_kylin arch/arm64/kernel/vdso/vdso.so arch/arm64/kernel/vdso/vdso.so: 文件格式 elf64-littleaarch64 Disassembly of section .text: 0000000000000770 <__kernel_kylin@@LINUX_2.6.39>: 770: d2803828 mov x8, #0x1c1 // #449 774: d4000001 svc #0x0 778: d65f03c0 ret

以上完全正确

四、测试vDSO调用

我们将arch/arm64/kernel/vdso/vdso.so作为标准动态库看待,直接复制到机器中,编写测试代码如下:

#include <sys/syscall.h> #include <stdio.h> extern int __kernel_kylin(char* words); int main(int argc, char *argv[]) { int ret = 0; char* words = "Userspace say:hello kylin!"; ret = __kernel_kylin(words); printf("vdso ret=%d \n", ret); return 0; }

此时我们构建的时候应该把vdso当作标准动态库,如下编译

gcc test_kylin_vdso.c -o test_kylin_vdso -L. -lvdso

此时我们运行:

# ./test_kylin_vdso vdso ret=0

然后查看日志

# dmesg [ 5586.379813] kylin: Get sys_kylin call:[Userspace say:hello kylin!]. ret=0

可以发现能够正常的syscall到我的系统调用,我们ltrace看看

# ltrace ./test_kylin_vdso __libc_start_main(0x5569b3083c, 1, 0x7fdfd074f8, 0x5569b30880 <unfinished ...> __kernel_kylin(0x5569b30920, 0x7fdfd074f8, 0x7fdfd07508, 0x5569b3083c) = 0 printf("vdso ret=%d \n", 0vdso ret=0 ) = 12 exit(0 <unfinished ...> __cxa_finalize(0x5569b41008, 0x5569b307f0, 0x10d68, 1) = 0x7fba4bec70 +++ exited (status 0) +++

正常调用__kernel_kylin,至此我们可以正常通过vdso来调用syscall的内容。