42.Linux應用調試-初步製作系統調用(用戶態->內核態)

来源:http://www.cnblogs.com/lifexy/archive/2017/12/20/8075282.html
-Advertisement-
Play Games

1首先來講講應用程式如何實現系統調用(用戶態->內核態)? 我們以應用程式的write()函數為例: 1)首先用戶態的write()函數會進入glibc庫,裡面會將write()轉換為swi(Software Interrupt)指令,從而產生軟體中斷,swi指令如下所示: 2)然後CPU會跳到異常 ...


1首先來講講應用程式如何實現系統調用(用戶態->內核態)?

我們以應用程式的write()函數為例:

1)首先用戶態的write()函數會進入glibc庫,裡面會將write()轉換為swi(Software Interrupt)指令,從而產生軟體中斷,swi指令如下所示:

swi   #val   //val: bit[23:0]立即數,該val用來判斷用戶函數需要調用哪個內核函數

2)然後CPU會跳到異常向量入口vector_swi處,根據swi指令後面的val值,在某個數組表裡找到對應的sys_write()函數

代碼如下所示(位於arch\arm\kernel\entry-common.S):

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
  ... ...

       ldr   scno, [lr, #-4]                 @ get SWI instruction  //獲取SWI值
    A710(       and  ip, scno, #0x0f000000 @ check for SWI)
    A710(       teq  ip, #0x0f000000)                               //校驗SWI的bit[27:24]是否為0xf
    A710(       bne  .Larm710bug)
     ... ...

       enable_irq                           //調用enable_irq()函數
       get_thread_info tsk
       adr  tbl, sys_call_table            @ load syscall table pointer  // tbl等於數組表基地址
       ldr   ip, [tsk, #TI_FLAGS]          @ check for syscall tracing  
     ... ...

bic  scno, scno, #0xff000000              @ mask off SWI op-code //只保留SWI的bit[23:0],也就是val值
eor  scno, scno, #__NR_SYSCALL_BASE @ check OS number    
//對於2440而講,__NR_SYSCALL_BASE基地址等於0x900000,也就是說val值為0x900000時,異或後,scno則等於0,表示數組表的基地址(第一個函數位置)
... ...

    ldrcc pc, [tbl, scno, lsl #2]             @ call sys_* routine          //pc=(tbl+scno)<<2,實現調用sys_write()
       //tbl:數組表基地址,  scno:要調用的sys_write()的索引值     lsl #2:左移2位,一個函數指針占據4個位元組

從上面代碼可以看出,2440的val基值為0x900000,也就是說要調用數組表的第一個函數時,則使用:

swi  #0x900000

 

2 接下來,我們便來自製一個系統調用

  • 1)在內核中,仿照一個sys_hello函數,然後放入數組表,供swi調用
  • 2)寫應用程式,直接通過swi指令,來調用sys_hello函數

 

3 仿照sys_hello()

3.1先來查找數組表,以sys_write為例,搜索找到位於arch/arm/kernel/calls.S,如下圖所示:

其中CALL定義如下所示:

.equ NR_syscalls,0     //將NR_syscalls=0

#define CALL(x) .equ NR_syscalls,NR_syscalls+1   //將CALL(x) 定義為:NR_syscalls=NR_syscalls+1 ,也就是每有一個CALL(),則該CALL值則+1

#include "calls.S"              //將calls.S的內容包進來,CALL(x)上面已經有了定義,就會將calls.S裡面的所有CALL(sys_xx)排列起來

#undef CALL                    //撤銷CALL定義

#define CALL(x) .long x        //然後再將排列起來的sys_xx以long(4位元組)對齊,一個函數指針占據4位元組

 

3.2 所以我們在call.S文件的CALL()列表的最後添加一段, 如下圖所示, sys_hello()的val值為352:

 

 

3.3 fs\read_write.c文件里寫一個sys_hello()函數

asmlinkage void sys_hello(const char __user * buf, size_t count)     //列印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);
    }
}

3.4  include\linux\syscalls.h文件里聲明sys_hello()

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

 

4.寫應用程式

#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 */ //%0等於buf "mov r1, %1\n" /* save the argment in r0 */ //%1等於count "swi %2\n" /* do the system call */ //%2等於0x900352 : //輸出部 : "r"(buf), "r"(count), "i" (__NR_SYSCALL_BASE + 352) //輸入部 : "r0", "r1");            //損壞部,指原有的數據會被破壞 } int main(int argc, char **argv) { printf("in app, call hello\n"); hello("www.100ask.net", 15);//這個函數會調用內核的sys_hello() return 0; }

4.1 其中asm ()是一個內嵌彙編(參考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()

 

5.重新燒寫內核,試驗應用程式

 

如上圖所示,一個簡單的系統調用便OK

 

調用成功後,就可以來修改sys_hello(),來列印應用程式的各個寄存器值,打斷點,來實現調試應用程式,需要用到:

task_pt_regs(current);          //獲取當前應用程式的各個寄存器內容,會返回一個pt_regs結構體

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 自己封裝個類庫,用於微信開發 使用的大概邏輯: Model層新建類Access_token 結合redis或其他資料庫使用 ...
  • 在開發的過程中我們總是會碰到多表操作的需求,今天我分享一個關於查詢的方法, 前言:在使用NHibernate中,需要將用戶表(Users)、部門表(Departments),鏈表查詢,在網上找了很多資料,可以在配置文件中配置相應的屬性達到關聯的效果,一對多、多對一、多對多的方式,但是使用後發現有些不 ...
  • 新建Common類庫 ...
  • 一、環境 VMware12 Pro CentOS-6.7-i386-bin-DVD1 jdk-8u151-linux-i586 二、詳細安裝步驟 前提:需要卸載自己Linux上的jdk rpm -qa | grep jdk 會顯示你所有包含jdk這個字元串的安裝包 rpm -e --nodeps 對 ...
  • 一、Linux中的文件許可權與目錄許可權 Linux中定義了3種訪問許可權,分別是r、w、x。其中r表示對象是可讀的,w表示對象是可寫的,x表示對象是可執行的,這3種許可權組成一組rwx分別對應對象的3個安全級別。這3個安全級別分別是對象的所屬者,對象的所屬組,系統其他用戶。比如圖1-1所示,文件的許可權 圖 ...
  • 今晚心血來潮,來加加班,想起還有一個博客,索性來寫寫,步驟會比較清楚,畢竟我有輕微強迫症... 聲明下,用的是centos6 的系統環境,預設root許可權,部署過程中iptables關閉,之後根據需求配置策略,selinux也是預設關閉的, 關閉iptables : /etc/init.d/ipta ...
  • 1.單詞說明 command n. 命令,指令 [kə'mɑ:nd] 單詞拼寫 名詞 單詞含義 音標(發音) command n. 命令,指令 [kə'mɑ:nd] 單詞拼寫 名詞 單詞含義 音標(發音) 提示:著重記憶單詞對應的意思,有能力的朋友最好詞性也記憶 2.詞性說明 n v vi vt c ...
  • DNS 伺服器基礎 一、DNS簡介 DNS(Domain Name System,功能變數名稱系統)是網際網路的一項服務; DNS 是將功能變數名稱和IP地址相互映射的一個分散式資料庫; DNS 是一種應用層協議,使用UDP和TCP的53埠; 1、DNS域命名空間 DNS域命名空間是一種層次結構,一般可分為根域、頂 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...