使用vsyscall系统调用

vsyscall相较于普通的通过INT 80中断完成的系统调用要更快,因此在对于精度要求很高或者时延要求极低的系统调用适合用vsyscall来实现,但是有一个缺点是vsyscall的系统调用不一定有libc的包裹函数,因此使用上比较复杂,但是内核已经为我们映射好了这些vsyscall到线程的地址空间中。废话少说,看代码:

/*
 *Copyright (c) 2013 GuZheng
 * Author: GuZheng <cengku@gmail.com>
 * Demo of how to use vsyscall func
 *
 * */
/* vsyscall.h header info
#ifndef _ASM_X86_VSYSCALL_H
#define _ASM_X86_VSYSCALL_H

enum vsyscall_num {
        __NR_vgettimeofday,
        __NR_vtime,
        __NR_vgetcpu,
};

#define VSYSCALL_START (-10UL << 20)
#define VSYSCALL_SIZE 1024
#define VSYSCALL_END (-2UL << 20)
#define VSYSCALL_MAPPED_PAGES 1
#define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr))


#endif
*/

#include <asm/vsyscall.h> /*the vsyscall header*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>

struct getcpu_cache {
        unsigned long blob[128 / sizeof(long)];
};

int main(int argc, char **argv)
{
        /*这个内核版本有三个vsyscall实现的系统调用
        *gettimeofday,time和getcpu
        *因此先定义三个函数原型的指针,用来接受后面找到的函数的映射地址
        * */
        int (*my_getcpu)(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
        int (*my_gettimeofday)(struct timeval *tv, struct timezone *tz);
        time_t (*my_time)(time_t *calptr);

        int node, cpu;
        time_t tm;
        struct tm *gm;
        struct timeval tv;
        struct timezone tz;
        struct getcpu_cache cache;

        /*根据VSYSCALL_ADDR宏,以及三个函数的偏移就可以找到映射的地址了*/
        char *addr1 = (char *)VSYSCALL_ADDR(__NR_vgettimeofday);
        printf("vgettimeofday addr is%p \n", addr1);
        char *addr2 = (char *)VSYSCALL_ADDR(__NR_vtime);
        printf("vtime addr is %p \n", addr2);
        char *addr3 = (char *)VSYSCALL_ADDR(__NR_vgetcpu);
        printf("vgetcpu addr is %p \n", addr3);

        my_gettimeofday = (int (*)(struct timeval *, struct timezone *))addr1;
        my_gettimeofday(&tv, &tz);
        printf("tv_sec:%d\n", tv.tv_sec);
        printf("tv_usec:%d\n", tv.tv_usec);
        printf("tz_minuteswest:%d\n", tz.tz_minuteswest);
        printf("tz_dsttime:%d\n", tz.tz_dsttime);

        my_time = (time_t (*)(time_t *))addr2;
        time(&tm);
        gm = gmtime(&tm);
        printf("Now is %d-%d-%d %d:%d:%d\n",
                        gm->tm_year + 1900,
                        gm->tm_mon,
                        gm->tm_mday,
                        gm->tm_hour,
                        gm->tm_min,
                        gm->tm_sec);

        my_getcpu = (int (*)(unsigned *, unsigned *, struct getcpu_cache *))addr3;
        my_getcpu(&cpu, &node, &cache);
        printf("numa node:%d, run on cpu:%d\n", node, cpu);


        return 0;
}

方法有点hack,后面补上用内联汇编的正规版本

补上gcc inline asm版本的(你妹的内联asm真心不好写啊!):

/*
 *Copyright (c) 2013 GuZheng
 * Author: GuZheng <cengku@gmail.com>
 * Demo of how to use vsyscall func
 *
 * */
/* vsyscall.h header info
#ifndef _ASM_X86_VSYSCALL_H
#define _ASM_X86_VSYSCALL_H

enum vsyscall_num {
        __NR_vgettimeofday,
        __NR_vtime,
        __NR_vgetcpu,
};

#define VSYSCALL_START (-10UL << 20)
#define VSYSCALL_SIZE 1024
#define VSYSCALL_END (-2UL << 20)
#define VSYSCALL_MAPPED_PAGES 1
#define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr))


#endif
*/

#include <asm/vsyscall.h> /*the vsyscall header*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>

struct getcpu_cache {
        unsigned long blob[128 / sizeof(long)];
};

int main(int argc, char **argv)
{
        /*这个内核版本有三个vsyscall实现的系统调用
        *gettimeofday,time和getcpu
        *因此先定义三个函数原型的指针,用来接受后面找到的函数的映射地址
        * */
        int (*my_getcpu)(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
        int (*my_gettimeofday)(struct timeval *tv, struct timezone *tz);
        time_t (*my_time)(time_t *calptr);

        int node, cpu;
        time_t tm;
        struct tm *gm;
        struct timeval tv;
        struct timezone tz;
        struct getcpu_cache cache;

        /*根据VSYSCALL_ADDR宏,以及三个函数的偏移就可以找到映射的地址了*/
        char *addr1 = (char *)VSYSCALL_ADDR(__NR_vgettimeofday);
        printf("vgettimeofday addr is%p \n", addr1);
        char *addr2 = (char *)VSYSCALL_ADDR(__NR_vtime);
        printf("vtime addr is %p \n", addr2);
        char *addr3 = (char *)VSYSCALL_ADDR(__NR_vgetcpu);
        printf("vgetcpu addr is %p \n", addr3);

        my_gettimeofday = (int (*)(struct timeval *, struct timezone *))addr1;
        //my_gettimeofday(&tv, &tz);
        __asm__(
                "movq %1, %%rdx;"
                "movq %0, %%rax;"
                "movq %2, %%rcx;"
                "movq %%rdx, %%rsi;"
                "movq %%rax, %%rdi;"
                "call *%%rcx;"
                :
                : "r"(&tv), "r"(&tz), "r"(addr1)
                : "rdx", "rax", "rcx", "rsi", "rdi"
        );
        printf("tv_sec:%d\n", tv.tv_sec);
        printf("tv_usec:%d\n", tv.tv_usec);
        printf("tz_minuteswest:%d\n", tz.tz_minuteswest);
        printf("tz_dsttime:%d\n", tz.tz_dsttime);

        my_time = (time_t (*)(time_t *))addr2;
        //time(&tm);
        __asm__(
                "movq %0, %%rax;"
                "movq %1, %%rcx;"
                "movq %%rax, %%rdi;"
                "call *%%rcx"
                :
                : "r"(&tm), "r"(addr2)
                : "rax", "rcx", "rdi"
        );
        gm = gmtime(&tm);
        printf("Now is %d-%d-%d %d:%d:%d\n",
                        gm->tm_year + 1900,
                        gm->tm_mon,
                        gm->tm_mday,
                        gm->tm_hour,
                        gm->tm_min,
                        gm->tm_sec);

        my_getcpu = (int (*)(unsigned *, unsigned *, struct getcpu_cache *))addr3;
        //my_getcpu(&cpu, &node, &cache);

        __asm__(
                "movq %2, %%rdx;"
                "movq %0, %%rcx;"
                "movq %1, %%rax;"
                "movq %3, %%r8;"
                "movq %%rcx, %%rsi;"
                "movq %%rax, %%rdi;"
                "call *%%r8;"
                :
                : "r"(&cpu), "r"(&node),"r"(NULL),"r"(addr3)
                );
        printf("numa node:%d, run on cpu:%d\n", node, cpu);


        return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值