平台为兆芯x86-64平台,原创文章,转载请标注出处~
在前一篇文章中,使用嵌入式汇编实现了time系统调用,这个系统调用没有入参,今天使用嵌入式汇编实现sysinfo,此系统调用有一个指针入参。
首先使用libc实现sysinfo的调用:
#include <sys/sysinfo.h>
#include <stdio.h>
#include <string.h>
int main()
{
int errno = -1;
long uptime = 0;
struct sysinfo s_info;
memset(&s_info,0,sizeof(struct sysinfo));
errno = sysinfo(&s_info);
uptime = s_info.uptime;
printf("this is libc call sysinfo errno = %d, uptime = %ld\n",errno, uptime);
return 0;
}
编译:
root@henry-002:/usr/test_code# gcc sysinfo_libc.c -o sysinfo_libc --static
执行结果:
root@henry-002:/usr/test_code# ./sysinfo_libc
this is libc call sysinfo errno = 0, uptime = 6073
执行结果正常,说明libc是可以正常执行的,进行反汇编:
root@henry-002:/usr/test_code# objdump -dlt sysinfo_libc > sysinfo_libc.dis
找到主要执行的代码:
000000000040105e <main>:
main():
40105e: 55 push %rbp
40105f: 48 89 e5 mov %rsp,%rbp
401062: 48 83 c4 80 add $0xffffffffffffff80,%rsp
401066: c7 45 84 ff ff ff ff movl $0xffffffff,-0x7c(%rbp)
40106d: 48 c7 45 88 00 00 00 movq $0x0,-0x78(%rbp)
401074: 00
401075: 48 8d 45 90 lea -0x70(%rbp),%rax
401079: ba 70 00 00 00 mov $0x70,%edx
40107e: be 00 00 00 00 mov $0x0,%esi
401083: 48 89 c7 mov %rax,%rdi
401086: e8 b5 b0 01 00 callq 41c140 <memset>
40108b: 48 8d 45 90 lea -0x70(%rbp),%rax
40108f: 48 89 c7 mov %rax,%rdi
401092: e8 89 5d 03 00 callq 436e20 <sysinfo>
401097: 89 45 84 mov %eax,-0x7c(%rbp)
40109a: 48 8b 45 90 mov -0x70(%rbp),%rax
40109e: 48 89 45 88 mov %rax,-0x78(%rbp)
4010a2: 48 8b 55 88 mov -0x78(%rbp),%rdx
4010a6: 8b 45 84 mov -0x7c(%rbp),%eax
4010a9: 89 c6 mov %eax,%esi
4010ab: bf 28 38 49 00 mov $0x493828,%edi
4010b0: b8 00 00 00 00 mov $0x0,%eax
4010b5: e8 16 6e 00 00 callq 407ed0 <_IO_printf>
4010ba: b8 00 00 00 00 mov $0x0,%eax
4010bf: c9 leaveq
4010c0: c3 retq
4010c1: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
4010c8: 00 00 00
4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
.......................
0000000000436e20 <sysinfo>:
sysinfo():
436e20: b8 63 00 00 00 mov $0x63,%eax
436e25: 0f 05 syscall
436e27: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax
436e2d: 0f 83 bd 17 00 00 jae 4385f0 <__syscall_error>
436e33: c3 retq
436e34: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
436e3b: 00 00 00
436e3e: 66 90 xchg %ax,%ax
可以看到sysinfo的系统调用号是0x63,使用嵌入式 汇编实现代码如下:
#include <sys/sysinfo.h>
#include <stdio.h>
#include <string.h>
int main()
{
int errno = -1;
long uptime = 0;
struct sysinfo s_info;
memset(&s_info,0,sizeof(struct sysinfo));
asm volatile(
"lea %1,%%rdi\n\t" //将输入参数s_info的地址赋值给rdi
"mov $0x63,%%eax\n\t" //系统调用号为0x63
"syscall\n\t" //执行系统调用,此处不能用int 0x80代替
"mov %%eax,%0\n\t" //返回值放在eax中,将返回值赋值给errno
:"=m"(errno)
:"m"(s_info)
);
uptime = s_info.uptime;
printf("this is syscall call sysinfo errno = %d, uptime = %ld\n",errno, uptime);
return 0;
}
编译 :
root@henry-002:/usr/test_code# gcc sysinfo_syscall.c -o sysinfo_syscall --static
执行结果达到预期:
root@henry-002:/usr/test_code# ./sysinfo_syscall
this is syscall call sysinfo errno = 0, uptime = 6277
反汇编:
root@henry-002:/usr/test_code# objdump -dlt sysinfo_syscall > sysinfo_syscall.dis
找到主要执行的代码段:
000000000040105e <main>:
main():
40105e: 55 push %rbp
40105f: 48 89 e5 mov %rsp,%rbp
401062: 48 83 c4 80 add $0xffffffffffffff80,%rsp
401066: c7 45 84 ff ff ff ff movl $0xffffffff,-0x7c(%rbp)
40106d: 48 c7 45 88 00 00 00 movq $0x0,-0x78(%rbp)
401074: 00
401075: 48 8d 45 90 lea -0x70(%rbp),%rax
401079: ba 70 00 00 00 mov $0x70,%edx
40107e: be 00 00 00 00 mov $0x0,%esi
401083: 48 89 c7 mov %rax,%rdi
401086: e8 a5 b0 01 00 callq 41c130 <memset>
40108b: 48 8d 7d 90 lea -0x70(%rbp),%rdi
40108f: b8 63 00 00 00 mov $0x63,%eax
401094: 0f 05 syscall
401096: 89 45 84 mov %eax,-0x7c(%rbp)
401099: 48 8b 45 90 mov -0x70(%rbp),%rax
40109d: 48 89 45 88 mov %rax,-0x78(%rbp)
4010a1: 8b 45 84 mov -0x7c(%rbp),%eax
4010a4: 48 8b 55 88 mov -0x78(%rbp),%rdx
4010a8: 89 c6 mov %eax,%esi
4010aa: bf e8 37 49 00 mov $0x4937e8,%edi
4010af: b8 00 00 00 00 mov $0x0,%eax
4010b4: e8 07 6e 00 00 callq 407ec0 <_IO_printf>
4010b9: b8 00 00 00 00 mov $0x0,%eax
4010be: c9 leaveq
4010bf: c3 retq
需要注意的地方:
1.给sysinfo传递参数的时候,使用的是rdi寄存器,而不是用rax寄存器。
2.编译器给edi赋值的时候,会先用lea指令将变量地址赋值给rax,然后再通过mov指令将rax的值赋值给rdi,我这里直接使用lea指令将变量地址赋值给rdi,比编译器节省一条指令。
3.lea指令不能用mov指令代替,因为lea指令为load effective address 的缩写,是取源操作数的偏移地址,并将其传送到目的操作数单元。类似于C语言的取地址符&。而mov是将变量值赋值给操作数。
4.libc还有其他的指令,如异常处理,这里没有考虑,nopw和xchg不确定具体的作用,后续可能再更新。