嵌入式汇编实现系统调用-time

平台为x86-64

系统调用是用户层调用linux服务的最常用的方式,但是大家通常使用封装好的库函数,比如libc提供的API进行使用,本篇文章使用嵌入式汇编实现time的系统调用。

首先使用libc编写一段程序做为对比:

#include<stdio.h>
#include<time.h>

int main(void)
{
   time_t timer = 0;
   struct tm *tblock;

   timer = time(NULL);  //获取当前时间

   tblock = localtime(&timer);
   char *str=asctime(tblock);  //将tm结构体转换成字符串
   printf("Local time is: %s", str); 
   return 0;
 
}

编译:

root@henry-002:/usr/test_code# gcc  time_libc.c -o time_libc --static

执行:

root@henry-002:/usr/test_code# ./time_libc 
Local time is: Tue Mar 16 16:48:38 2021

执行结果正常,说明使用libc调用time正常,然后反汇编elf文件:

root@henry-002:/usr/test_code# objdump -dlt time_libc > time_libc.dis

我们找到主要的执行部分:

000000000040105e <main>:
main():
  40105e:	55                   	push   %rbp
  40105f:	48 89 e5             	mov    %rsp,%rbp
  401062:	48 83 ec 20          	sub    $0x20,%rsp
  401066:	48 c7 45 e8 00 00 00 	movq   $0x0,-0x18(%rbp)
  40106d:	00 
  40106e:	bf 00 00 00 00       	mov    $0x0,%edi
  401073:	e8 e8 26 03 00       	callq  433760 <time>
  401078:	48 89 45 e8          	mov    %rax,-0x18(%rbp)
  40107c:	48 8d 45 e8          	lea    -0x18(%rbp),%rax
  401080:	48 89 c7             	mov    %rax,%rdi
  401083:	e8 c8 26 03 00       	callq  433750 <localtime>
  401088:	48 89 45 f0          	mov    %rax,-0x10(%rbp)
  40108c:	48 8b 45 f0          	mov    -0x10(%rbp),%rax
  401090:	48 89 c7             	mov    %rax,%rdi
  401093:	e8 c8 25 03 00       	callq  433660 <asctime>
  401098:	48 89 45 f8          	mov    %rax,-0x8(%rbp)
  40109c:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  4010a0:	48 89 c6             	mov    %rax,%rsi
  4010a3:	bf 64 3b 49 00       	mov    $0x493b64,%edi
  4010a8:	b8 00 00 00 00       	mov    $0x0,%eax
  4010ad:	e8 0e 6e 00 00       	callq  407ec0 <_IO_printf>
  4010b2:	b8 00 00 00 00       	mov    $0x0,%eax
  4010b7:	c9                   	leaveq 
  4010b8:	c3                   	retq   
  4010b9:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)


.............

0000000000433760 <time>:
time():
  433760:	b8 c9 00 00 00       	mov    $0xc9,%eax
  433765:	0f 05                	syscall 
  433767:	c3                   	retq   
  433768:	0f 1f 84 00 00 00 00 	nopl   0x0(%rax,%rax,1)
  43376f:	00 

 

 

根据以上分析,我们了解到了time的系统调用号是0xc9,嵌入式汇编如下:

#include<stdio.h>
#include<time.h>

int main(void)
{
   time_t timer = 0;
   struct tm *tblock;

   //获取当前时间
   asm volatile(
       "mov $0,%%edi\n\t" //edi存储入参,入参为NULL,既0
       "mov $0xc9,%%eax\n\t" //系统调用号为0xc9
       "syscall\n\t"        //执行系统调用
       "mov %%eax,%0\n\t"   //eax存储的是返回值,将返回值赋值给输出参数timer
       :"=m"(timer)     //输出为内存只写变量timer
   );
   tblock = localtime(&timer);
   char *str=asctime(tblock);  //将tm结构体转换成字符串
   printf("Local time is: %s", str); 
   return 0;
}

 

编译:

root@henry-002:/usr/test_code# gcc  time_syscall.c -o time_syscall --static

执行结果正常:

root@henry-002:/usr/test_code# ./time_syscall 
Local time is: Tue Mar 16 16:41:18 2021

反汇编:

root@henry-002:/usr/test_code# objdump -dlt time_syscall > time_syscall.dis

找到主要的部分:

000000000040105e <main>:
main():
  40105e:	55                   	push   %rbp
  40105f:	48 89 e5             	mov    %rsp,%rbp
  401062:	48 83 ec 20          	sub    $0x20,%rsp
  401066:	48 c7 45 e8 00 00 00 	movq   $0x0,-0x18(%rbp)
  40106d:	00 
  40106e:	bf 00 00 00 00       	mov    $0x0,%edi
  401073:	b8 c9 00 00 00       	mov    $0xc9,%eax
  401078:	0f 05                	syscall 
  40107a:	89 45 e8             	mov    %eax,-0x18(%rbp)
  40107d:	48 8d 45 e8          	lea    -0x18(%rbp),%rax
  401081:	48 89 c7             	mov    %rax,%rdi
  401084:	e8 c7 26 03 00       	callq  433750 <localtime>
  401089:	48 89 45 f0          	mov    %rax,-0x10(%rbp)
  40108d:	48 8b 45 f0          	mov    -0x10(%rbp),%rax
  401091:	48 89 c7             	mov    %rax,%rdi
  401094:	e8 c7 25 03 00       	callq  433660 <asctime>
  401099:	48 89 45 f8          	mov    %rax,-0x8(%rbp)
  40109d:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  4010a1:	48 89 c6             	mov    %rax,%rsi
  4010a4:	bf 64 3b 49 00       	mov    $0x493b64,%edi
  4010a9:	b8 00 00 00 00       	mov    $0x0,%eax
  4010ae:	e8 0d 6e 00 00       	callq  407ec0 <_IO_printf>
  4010b3:	b8 00 00 00 00       	mov    $0x0,%eax
  4010b8:	c9                   	leaveq 
  4010b9:	c3                   	retq   
  4010ba:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)

 

需要注意的地方是:

1.给系统调用传递参数,很多书籍和材料上写是用ebx,编译的时候需要使用32bit模式编译,既增加-m32编译参数,我用的是64bit平台,可能这部分有区别。

2.另外就是系统调用号,可能有区别,但是系统调用号会随着linux的版本升级而增加,libc到底是如何确定系统调用号的,需要再研究一下,后续有结果再更新。

3.使用edi传递入参必须是0,否则会执行错误。

4.syscall不能用int 80代替。

上一篇:考研机试 48.吃糖果


下一篇:pyinstaller 图标问题(ico)