应用调试(四)系统调用SWI
目錄
- 應(yīng)用調(diào)試(四)系統(tǒng)調(diào)用SWI
- 系統(tǒng)調(diào)用
- SWI代碼片段分析
- 分析sys_write
- 構(gòu)造sys_hello
- 應(yīng)用程序調(diào)用SWI
- 嵌入?yún)R編語(yǔ)法
- 測(cè)試APP
- 參考
title: 應(yīng)用調(diào)試(四)系統(tǒng)調(diào)用SWI
date: 2019/01/19 18:05:39
toc: true
---
應(yīng)用調(diào)試(四)系統(tǒng)調(diào)用SWI
系統(tǒng)調(diào)用
我們App中的open,read等實(shí)際上會(huì)觸發(fā)swi異常,觸發(fā)系統(tǒng)調(diào)用sys_open,sys_read等,內(nèi)核根據(jù)swi的值來(lái)執(zhí)行具體的操作
SWI代碼片段分析
搜索下vector_swi,找到入口函數(shù)arch\arm\kernel\entry-common.S
.align 5 ENTRY(vector_swi)@ 保存現(xiàn)場(chǎng)sub sp, sp, #S_FRAME_SIZEstmia sp, {r0 - r12} @ Calling r0 - r12add r8, sp, #S_PCstmdb r8, {sp, lr}^ @ Calling sp, lrmrs r8, spsr @ called from non-FIQ mode, so ok.str lr, [sp, #S_PC] @ Save calling PCstr r8, [sp, #S_PSR] @ Save CPSRstr r0, [sp, #S_OLD_R0] @ Save OLD_R0zero_fp@ 獲得swi的指令地址,確保是swi指令ldr scno, [lr, #-4] @ get SWI instructionA710( and ip, scno, #0x0f000000 @ check for SWI )A710( teq ip, #0x0f000000 )A710( bne .Larm710bug )@ tbl等于數(shù)組表基地址get_thread_info tskadr tbl, sys_call_table @ load syscall table pointerldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing@清除高8位bic scno, scno, #0xff000000 @ mask off SWI op-code@ #define __NR_SYSCALL_BASE 0x900000 這里swi的值實(shí)際上是0x900000 0x900001 ...所以要清除這個(gè)高位的9eor scno, scno, #__NR_SYSCALL_BASE @ check OS number@根據(jù)索引號(hào),去tbl 這個(gè)數(shù)組中調(diào)用函數(shù)@ tbl:數(shù)組表基地址, scno:要調(diào)用的sys_write()的索引值 lsl #2:左移2位,一個(gè)函數(shù)指針占據(jù)4個(gè)字節(jié)cmp scno, #NR_syscalls @ check upper syscall limitadr lr, ret_fast_syscall @ return addressldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine這里首先獲得swi這條指令的內(nèi)容,swi指令位于lr-4,原因如下圖
然后分析確保是swi指令,也就是and ip, scno, #0x0f000000
通過(guò)swi的值去找到這個(gè)數(shù)組的索引,執(zhí)行函數(shù)
分析sys_write
理論上,應(yīng)該有sys_write存入這個(gè)指針數(shù)組,搜索下發(fā)現(xiàn)如下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) ......同時(shí)有如下在arch\arm\kernel\entry-common.S,也就是先定義這個(gè)CALL,再將上面的定義全部包含進(jìn)來(lái)
.equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S" #undef CALL #define CALL(x) .long x也就是說(shuō),我們可以自己定義一個(gè)swi val 在arch\arm\kernel\calls.S 放在最后面
/* 350 */ CALL(sys_timerfd)CALL(sys_eventfd)CALL(sys_hello) /* 添加一個(gè)自己的系統(tǒng)調(diào)用 */構(gòu)造sys_hello
仿照sys_write聲明定義在include\linux\syscalls.h和fs\read_write.c
asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)實(shí)現(xiàn)函數(shù)如下
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);} }應(yīng)用程序調(diào)用SWI
參考glibc-2.3.6/,這里沒(méi)去仔細(xì)看了,這里有個(gè)__brk函數(shù),仿照著寫,具體看下注釋
#include <errno.h> #include <unistd.h> #define __NR_SYSCALL_BASE 0x900000void 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 表示第一個(gè)*//* %0 %1 i表示立即數(shù),也是就是Immediate 這里就是 swi的具體的值 */: "r"(buf), "r"(count), "i" (__NR_SYSCALL_BASE + 352)/* 損壞部,指令執(zhí)行過(guò)程中可能引起的哪些寄存器發(fā)生變化*/: "r0", "r1"); }int main(int argc, char **argv) {printf("in app, call hello\n");hello("hello", 6);return 0; }嵌入?yún)R編語(yǔ)法
參考文件cnblog,這里不去仔細(xì)分析了,簡(jiǎn)單的分析在韋老師視頻31課4.1節(jié)25分左右
參考linux內(nèi)核源代碼情景分析1.5.2節(jié))
格式如下所示:
- asm( 指令部 : 輸出部 : 輸入部 : 損壞部 );
- 如果沒(méi)有的部分,冒號(hào)也不能省略
指令部
在指令部中,若出現(xiàn)%0、%1、%2等,則表示指令部后面的第幾個(gè)變量.
比如上面代碼的mov r0, %0\n
其中%0便會(huì)對(duì)應(yīng)buf值,而r是一個(gè)約束條件字母,r表示任意一個(gè)寄存器,在預(yù)處理時(shí),便會(huì)自動(dòng)分配一個(gè)寄存器,將buf值放入該寄存器里,然后運(yùn)行mov r0 (buf對(duì)應(yīng)的寄存器)
輸出部
每個(gè)輸出部的約束條件字母都要加上"=",比如:
int num=5,val;asm("mov %0,%1\n":"=r"(val) //指定val是一個(gè)輸出部,執(zhí)行mov后,val便等于5:"i"(num) // "i"約束條件字母,表示num是一個(gè)立即數(shù): );輸入部
和輸出部唯一不同的就是,在約束條件字母前不能加上=
常用的約束條件字母,如下圖所示:
損壞部
和輸入輸出類似,一般用來(lái)處理操作的中間過(guò)程,因?yàn)檫@些原有的內(nèi)容都會(huì)被損壞,比如上面的hello()里的r0, r1,只是用來(lái)當(dāng)做參數(shù),傳遞給內(nèi)核的sys_hello()
測(cè)試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 # 這個(gè)“hello” 是系統(tǒng)調(diào)用打印的參考
https://www.cnblogs.com/lifexy/p/8075282.html 嵌入式匯編簡(jiǎn)單介紹
轉(zhuǎn)載于:https://www.cnblogs.com/zongzi10010/p/10292717.html
總結(jié)
以上是生活随笔為你收集整理的应用调试(四)系统调用SWI的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 浙江文成“红领巾”向交警敬礼:上下学感谢
- 下一篇: Java 虚拟机经典六问