c - Getrusage inline assembly -
i trying implement getrusage
function client server program using sockets , of running on freebsd. want print out processor time usage , memory usage.
i have tried implement following code getting output 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; }
update: have tried run 0 values or random number value or negative number values. ideas missing?
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; }
i use system call write
more likely, giving me compilation warning: passing arg 1 of 'strlen' makes pointer integer without cast
edit: (this working code now, regarding comment)
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));
any ideas wrong?
the reason getting illegal instruction
error because syscall instruction available on 64-bit freebsd running 64-bit program. serious issue since 1 of comments suggests code running on 32-bit freebsd.
under normal circumstances don't need write own getrusage since part of c library (libc) on platform. appears have been tasked inline assembly.
64-bit freebsd , syscall instruction
there bit of bug in 64-bit code since syscall destroys contents of rcx , r11. code may work may fail in future program expands , enable optimizations. following change adds 2 registers clobber list:
int errorcode; __asm__( "syscall" : "=a" (errorcode) : "a" (117), "d" (who), "s" (usage) //const sysgetrusage : scno = 117 : "memory", "rcx", "r11" );
using memory
clobber can lead generation of inefficient code use if necessary. become more of expert need memory
clobber can eliminated. have used function following if wasn't allowed use c library version of getrusage:
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; }
this uses memory operand output constraint , drops memory
clobber. since compiler knows how large rusage
structure , =m
says output constraint modifies memory don't need need memory
clobber.
32-bit freebsd system calls via int 0x80
as mention in comments , updated code, make system call in 32-bit code in freebsd have use int 0x80
. described in freebsd system calls convention. parameters pushed on stack right left , must allocate 4 bytes on stack pushing 4 byte value onto stack after push last parameter.
your edited code has few bugs. first push 4 bytes before rest of arguments. need push after. need adjust stack after int 0x80
reclaim stack space used arguments passed. pushed 3 4-byte values on stack, need add 12 esp after int 0x80
.
you need memory
clobber because compiler doesn't know have modified memory @ all. because way have done constraints data in variable usage
gets modified compiler doesn't know what.
the return value of int 0x80
in eax use constraint =r
. should have been =a
since return value returned in eax. since using =a
tells compiler eax clobbered don't need list clobber anymore.
the modified code have looked like:
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; }
another way 1 have written more advanced techniques is:
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 x86 inline asm use clarity */ ); if (errorcode<0) { printf("error"); } return errorcode; }
this uses label (usage
, who
) identify each parameter rather using numerical positions %3
, %4
etc. makes inline assembly easier follow. since 4-byte value can pushed onto stack before int 0x80
can save few bytes pushing contents of register. in case used %%eax
. uses =m
constraint did in 64-bit example.
more information on extended inline assembler can found in gcc documentation.
Comments
Post a Comment