我正在尝试使用套接字将getrusage函数实现到我的客户机服务器程序中,所有这些都运行在FreeBSD上。我想打印出处理器的时间使用和内存使用情况。
我已经尝试实现以下代码,但是我得到了输出Illegal instrucion (Core dumped)
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;
}更新:,我尝试过运行它,但是我得到了零值或一些随机数值或负数值。知道我错过了什么吗?
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
编辑:(这是正在运行的代码,关于注释)
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));有什么不对吗?
发布于 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列表中:
int errorcode;
__asm__(
"syscall"
: "=a" (errorcode)
: "a" (117), "D" (who), "S" (usage) //const Sysgetrusage : scno = 117
: "memory", "rcx", "r11"
);使用memory clobber会导致产生低效的代码,所以我只在必要时使用它。当你成为一个专家的时候,对memory敲击的需求就可以被消除。如果不允许我使用C库版本的地学,我会使用如下函数
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失败了,您不需要再把它作为一个坏消息列出。
修改后的代码可能如下所示:
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;
}另一种用更先进的技术编写这篇文章的方法是:
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;
}这使用一个标签(usage和who)来标识每个参数,而不是使用%3、%4等数字位置。这使得内联程序集更容易理解。由于任何4字节的值都可以在int 0x80之前推到堆栈上,所以我们可以通过简单地推送任何寄存器的内容来保存几个字节。在这种情况下,我使用了%%eax。这使用=m约束,就像我在64位示例中所做的那样。
有关扩展内联汇编程序的更多信息可以在GCC文献中找到。
https://stackoverflow.com/questions/43410821
复制相似问题