首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Getrusage内嵌组件

Getrusage内嵌组件
EN

Stack Overflow用户
提问于 2017-04-14 11:41:37
回答 1查看 515关注 0票数 1

我正在尝试使用套接字将getrusage函数实现到我的客户机服务器程序中,所有这些都运行在FreeBSD上。我想打印出处理器的时间使用和内存使用情况。

我已经尝试实现以下代码,但是我得到了输出Illegal instrucion (Core dumped)

代码语言:javascript
复制
int getrusage(int who, struct rusage *usage){

    int errorcode;
    __asm__(
    "syscall"
    : "=a" (errorcode)
    : "a" (117), "D"  (who), "S" (usage)  //const Sysgetrusage : scno = 117
    : "memory"
    );

    if (errorcode<0) {
        printf("error");
    }
    return 1;  
}

更新:,我尝试过运行它,但是我得到了零值或一些随机数值或负数值。知道我错过了什么吗?

代码语言:javascript
复制
int getrusage(int who, struct rusage *usage){

    int errorcode;
    __asm__("push $0;"
                "push %2;"
                "push %1;"
                "movl $117, %%eax;"
                "int $0x80;"
                :"=r"(errorcode)
                :"D"(who),"S"(usage)
                :"%eax"
        );

    if (errorcode<0) {
        printf("error");
    }
    return 1;

}

我想更多地使用系统调用write,但是它给了我一个编译warning: passing arg 1 of 'strlen' makes pointer from integer without a cast

编辑:(这是正在运行的代码,关于注释)

代码语言:javascript
复制
struct rusage usage;
getrusage(RUSAGE_SELF,&usage);
char tmp[300];

write(i, "Memory: ", 7);
sprintf (tmp, "%ld", usage.ru_maxrss);
write(i, tmp, strlen(tmp));
write(i, "Time: ", 5);
sprintf (tmp, "%lds", usage.ru_utime.tv_sec);
write(i, tmp, strlen(tmp));
sprintf (tmp, "%ldms", usage.ru_utime.tv_usec);
write(i, tmp, strlen(tmp));

有什么不对吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-14 20:54:37

您获得illegal instruction错误的原因是,http://www.felixcloutier.com/x86/SYSCALL.html指令只在运行64位程序的64位FreeBSD上可用。这是一个严重的问题,因为您的评论之一表明您的代码正在32位FreeBSD上运行。

在正常情况下,您不需要编写自己的地学,因为它是该平台上C库(libc)的一部分。似乎您已被委托使用内联程序集来完成此任务。

64位FreeBSD和SYSCALL指令

由于SYSCALL破坏了RCX和R11的内容,所以您的64位代码中有一个小错误。您的代码可能工作,但将来可能会失败,特别是在程序扩展和启用优化时。下面的更改将这2个寄存器添加到clobber列表中:

代码语言:javascript
复制
int errorcode;
    __asm__(
        "syscall"
        : "=a" (errorcode)
        : "a" (117), "D"  (who), "S" (usage)  //const Sysgetrusage : scno = 117
        : "memory", "rcx", "r11"
);

使用memory clobber会导致产生低效的代码,所以我只在必要时使用它。当你成为一个专家的时候,对memory敲击的需求就可以被消除。如果不允许我使用C库版本的地学,我会使用如下函数

代码语言:javascript
复制
int getrusage(int who, struct rusage *usage){

    int errorcode;
    __asm__(
        "syscall"
        : "=a"(errorcode), "=m"(*usage)
        : "0"(117), "D"(who), "S"(usage)
        : "rcx", "r11"
    );

    if (errorcode<0) {
        printf("error");
    }
    return errorcode;
}

这使用内存操作数作为输出约束,并删除memory块。由于编译器知道rusage结构和is =m有多大,所以输出约束修改了我们不需要的内存,因此不需要memory clobber。

通过Int 0x80调用32位FreeBSD系统

正如注释和更新的代码中提到的那样,要在FreeBSD中使用32位代码进行系统调用,您必须使用int 0x80。这在FreeBSD系统调用公约中有描述。参数从右向左推到堆栈上,在推上最后一个参数后,必须将任意4字节的值推到堆栈上,从而在堆栈上分配4个字节。

您编辑的代码有几个bug。首先,在其余参数之前推送额外的4个字节。你得把它推下去。您需要在int 0x80之后调整堆栈,以便有效地回收传递的参数所使用的堆栈空间。您在堆栈上推了3个4字节的值,所以您需要在int 0x80之后将12添加到ESP中。

您还需要一个memory块,因为编译器根本不知道您实际上已经修改了内存。这是因为您执行约束的方式--变量usage中的数据会被修改,但是编译器不知道是什么。

int 0x80的返回值将在EAX中,但使用约束=r。它应该是=a,因为返回值将在EAX中返回。由于使用=a告诉编译器EAX失败了,您不需要再把它作为一个坏消息列出。

修改后的代码可能如下所示:

代码语言:javascript
复制
int getrusage(int who, struct rusage *usage){

    int errorcode;
    __asm__("push %2;"
            "push %1;"
            "push $0;"
            "movl $117, %%eax;"
            "int $0x80;"
            "add $12, %%esp"
            :"=a"(errorcode)
            :"D"(who),"S"(usage)
            :"memory"
            );

    if (errorcode<0) {
        printf("error");
    }
    return errorcode;
}

另一种用更先进的技术编写这篇文章的方法是:

代码语言:javascript
复制
int getrusage(int who, struct rusage *usage){

    int errorcode;
    __asm__("push %[usage]\n\t"
            "push %[who]\n\t"
            "push %%eax\n\t"
            "int $0x80\n\t"
            "add $12, %%esp"
            :"=a"(errorcode), "=m"(*usage)
            :"0"(117), [who]"ri"(who), [usage]"r"(usage)
            :"cc" /* Don't need this with x86 inline asm but use for clarity */
        );

    if (errorcode<0) {
        printf("error");
    }
    return errorcode;
}

这使用一个标签(usagewho)来标识每个参数,而不是使用%3%4等数字位置。这使得内联程序集更容易理解。由于任何4字节的值都可以在int 0x80之前推到堆栈上,所以我们可以通过简单地推送任何寄存器的内容来保存几个字节。在这种情况下,我使用了%%eax。这使用=m约束,就像我在64位示例中所做的那样。

有关扩展内联汇编程序的更多信息可以在GCC文献中找到。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43410821

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档