title: 应用调试(四)系统调用SWI

date: 2019/01/19 18:05:39

toc: true

应用调试(四)系统调用SWI

系统调用

我们App中的open,read等实际上会触发swi异常,触发系统调用sys_open,sys_read等,内核根据swi的值来执行具体的操作

SWI代码片段分析

搜索下vector_swi,找到入口函数arch\arm\kernel\entry-common.S

	.align	5
ENTRY(vector_swi)
@ 保存现场 sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0 - r12
add r8, sp, #S_PC
stmdb r8, {sp, lr}^ @ Calling sp, lr
mrs r8, spsr @ called from non-FIQ mode, so ok.
str lr, [sp, #S_PC] @ Save calling PC
str r8, [sp, #S_PSR] @ Save CPSR
str r0, [sp, #S_OLD_R0] @ Save OLD_R0
zero_fp @ 获得swi的指令地址,确保是swi指令
ldr scno, [lr, #-4] @ get SWI instruction
A710( and ip, scno, #0x0f000000 @ check for SWI )
A710( teq ip, #0x0f000000 )
A710( bne .Larm710bug ) @ tbl等于数组表基地址
get_thread_info tsk
adr tbl, sys_call_table @ load syscall table pointer
ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing @清除高8位
bic scno, scno, #0xff000000 @ mask off SWI op-code
@ #define __NR_SYSCALL_BASE 0x900000 这里swi的值实际上是0x900000 0x900001 ...所以要清除这个高位的9
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number @根据索引号,去tbl 这个数组中调用函数
@ tbl:数组表基地址, scno:要调用的sys_write()的索引值 lsl #2:左移2位,一个函数指针占据4个字节
cmp scno, #NR_syscalls @ check upper syscall limit
adr lr, ret_fast_syscall @ return address
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
  1. 这里首先获得swi这条指令的内容,swi指令位于lr-4,原因如下图

  2. 然后分析确保是swi指令,也就是and ip, scno, #0x0f000000

  3. 获得全局的一个存有系统调用函数的数组的地址

  4. 通过swi的值去找到这个数组的索引,执行函数

分析sys_write

理论上,应该有sys_write存入这个指针数组,搜索下发现如下arch\arm\kernel\calls.S

/* 0 */		CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
CALL(sys_write)
/* 5 */ CALL(sys_open)
......

同时有如下在arch\arm\kernel\entry-common.S,也就是先定义这个CALL,再将上面的定义全部包含进来

	.equ NR_syscalls,0
#define CALL(x) .equ NR_syscalls,NR_syscalls+1
#include "calls.S"
#undef CALL
#define CALL(x) .long x

也就是说,我们可以自己定义一个swi val 在arch\arm\kernel\calls.S 放在最后面

/* 350 */	CALL(sys_timerfd)
CALL(sys_eventfd)
CALL(sys_hello) /* 添加一个自己的系统调用 */

构造sys_hello

仿照sys_write声明定义在include\linux\syscalls.hfs\read_write.c

asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)

实现函数如下

asmlinkage void sys_hello(const char __user * buf, size_t count);

asmlinkage void sys_hello(const char __user * buf, size_t count)
{
char ker_buf[100]; if(buf)
{ copy_from_user(ker_buf, buf, (count<100)? count : 100);
ker_buf[99]='\0';
printk("sys_hello:%s\n",ker_buf);
}
}

应用程序调用SWI

参考glibc-2.3.6/,这里没去仔细看了,这里有个__brk函数,仿照着写,具体看下注释

#include <errno.h>
#include <unistd.h>
#define __NR_SYSCALL_BASE 0x900000 void hello(char *buf, int count)
{
/* swi */
asm ("mov r0, %0\n" /* save the argment in r0 */
"mov r1, %1\n" /* save the argment in r0 */
"swi %2\n" /* do the system call */ /* 输出部分,这里不需要输出,但是需要 : 占位*/
:
/* 输入部分, r表示寄存器 ,使用 %0 表示第一个*/
/* %0 %1 i表示立即数,也是就是Immediate 这里就是 swi的具体的值 */
: "r"(buf), "r"(count), "i" (__NR_SYSCALL_BASE + 352)
/* 损坏部,指令执行过程中可能引起的哪些寄存器发生变化*/
: "r0", "r1");
} int main(int argc, char **argv)
{
printf("in app, call hello\n");
hello("hello", 6);
return 0;
}

嵌入汇编语法

参考文件cnblog,这里不去仔细分析了,简单的分析在韦老师视频31课4.1节25分左右

参考linux内核源代码情景分析1.5.2节)

格式如下所示:

  • asm( 指令部 : 输出部 : 输入部 : 损坏部 );
  • 如果没有的部分,冒号也不能省略

指令部

在指令部中,若出现%0、%1、%2等,则表示指令部后面的第几个变量.

比如上面代码的mov r0, %0\n

其中%0便会对应buf值,而r是一个约束条件字母,r表示任意一个寄存器,在预处理时,便会自动分配一个寄存器,将buf值放入该寄存器里,然后运行mov r0 (buf对应的寄存器)

输出部

每个输出部的约束条件字母都要加上"=",比如:

int num=5,val;

asm("mov %0,%1\n"
:"=r"(val) //指定val是一个输出部,执行mov后,val便等于5
:"i"(num) // "i"约束条件字母,表示num是一个立即数
: );

输入部

和输出部唯一不同的就是,在约束条件字母前不能加上=

常用的约束条件字母,如下图所示:

损坏部

和输入输出类似,一般用来处理操作的中间过程,因为这些原有的内容都会被损坏,比如上面的hello()里的r0, r1,只是用来当做参数,传递给内核的sys_hello()

测试APP

# mount -t nfs -o nolock,vers=2 192.168.95.222:/home/book/stu /mnt
# cd /mnt/code
# ./test_system_call
in app, call hello
sys_hello:hello # 这个“hello” 是系统调用打印的

参考

https://www.cnblogs.com/lifexy/p/8075282.html 嵌入式汇编简单介绍

应用调试(四)系统调用SWI的更多相关文章

  1. 驱动调试(四)oops确定调用树

    目录 驱动调试(四)oops确定调用树 内核开启调用树 栈指针分析 原理 寄存器别名 基础解释 例子分析 找到PC地址的位置 栈分析 附录:原文的excel title: 驱动调试(四)oops确定调 ...

  2. 42.Linux应用调试-初步制作系统调用(用户态->内核态)

    1首先来讲讲应用程序如何实现系统调用(用户态->内核态)? 我们以应用程序的write()函数为例: 1)首先用户态的write()函数会进入glibc库,里面会将write()转换为swi(S ...

  3. Linux内核分析 笔记四 系统调用的三个层次 ——by王玥

    一.知识点总结 (一)用户态.内核态和中断 1.内核态:在高的执行级别下,代码可以执行特权指令,访问任意的物理地址,这时的CPU就对应内核态 2.用户态:在低级别的指令状态下,代码 只能在级别允许的特 ...

  4. Socket与系统调用深层分析

    实验背景: Socket API编程接口之上可以编写基于不同网络协议的应用程序: Socket接口在用户态通过系统调用机制进入内核: 内核中将系统调用作为一个特殊的中断来处理,以socket相关系统调 ...

  5. GDB调试系列之了解GDB

    想要熟练利用GDB进行程序调试,首先要了解什么是GDB. 1. 什么是GDB GDB (the GNU Project Debugger) 是一个可以运行在大多数常见的UNIX架构.Windows.M ...

  6. [转]Android逆向之动态调试总结

    一.在SO中关键函数上下断点 刚学逆向调试时.大多都满足于在SO中某关键函数上下断点.然后通过操作应用程序,去触发这个断点,然后进行调试 详细的步骤可以参见非虫大大的<Android软件安全与逆 ...

  7. 使用IntelliJ IDEA(PHPStorm)和xdebug在firefox、chrome中远程调试PHP

    很多PHP程序员都习惯于使用echo.var_dump和exit来中断和调试web应用程序,本文主要介绍结合xdebug.IntelliJ IDEA.Firefox/chrome/IE来远程调试PHP ...

  8. vscode 学习笔记 —— 调试 (以 node 为例)

    一.建立配置文件 1.选择你的项目 2.选择你项目的语言 3.当前项目路径下生成 .vscode/launch.json { // Use IntelliSense to learn about po ...

  9. 如何调试触发器-MSSQL (转帖)

    调试触发器 //------------------------------------- 作者:四海为圈(原创) //------------------------------------- 1. ...

随机推荐

  1. [20190402]对比_mutex_wait_scheme不同模式cpu消耗.txt

    [20190402]对比_mutex_wait_scheme不同模式cpu消耗.txt --//前几天做了sql语句在mutexes上的探究.今天对比不同_mutex_wait_scheme模式cpu ...

  2. Integer a= 127 与 Integer b = 128相关

    Integer a = 127; Integer b = 127; Integer c = 128; Integer d = 128; a == b 与 c == d 的比较结果是什么? a == b ...

  3. windows下安装MongoDB扩展和配置

    windows下安装MongoDB扩展和配置 1.下载mongoDB扩展,根据当前php版本进行下载 地址如下:http://pecl.php.net/package/mongo 我本地php版本是 ...

  4. Docker之常用命令(二)

    这篇博客就不扯皮了,简单粗暴地贴上自己整理的一份Docker常用命令. docker search ** // 查找镜像 docker pull nginx // 载入镜像 # -a 拉取所有tagg ...

  5. 3星|《HBO的内容战略》:HBO与美国电视业大事记

    HBO的内容战略 基本是HBO与美国电视业的大事记.从电视的诞生讲起.HBO在1972年首播,1975年做出一个当时惊世骇俗的决定:勇卫星实时向全美发送信号,随即成为覆盖全国的电视台:80年代受到录像 ...

  6. JavaScript对象类型之简单介绍

    引言 对象是JavaScript的基本数据类型. 对象是一种复合值:将很多值(原始值或者其他对象)聚合在一起,通过名字访问这些值. 对象可以看做属性的无序集合,每个属性都是一个名/值对.属性名是字符串 ...

  7. 完成一个java项目需要的一些基础

    包括  1.eclipse关键字      2.文档注      3. jar包的导出与导入 一.elipse关键字 ctry+t       查看父类 ctry+鼠标光标     查看源代码 二.文 ...

  8. 监控zookeeper

    [4ajr@db1 scripts]$ cat zookeeper_mode.sh #!/bin/bash mode=`echo srvr|nc 127.0.0.1 2181|awk '/Mode/{ ...

  9. vs2015第二次装安装不能选择路径问题解决方法

    vs2015卸载后注册表还会存在vs2015的信息,下次安装的时候会读注册表里面记录的路径,不能自己选择路径. 解决方法: 1.在vs安装文件的路径打开命令,shift+鼠标右键 2.输入命令:cn_ ...

  10. 乡下人重拾MVC——创建视图

    1. 创建视图都不勾选:代表不使用任何模版,页面的代码即为运行后显示的内容 2.  创建分部视图 代表统会自动把View文件夹下名为“_ViewStart.cshtml”的内容添加到新建的html最上 ...