青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-19  評論-21  文章-0  trackbacks-0
此文只簡單分析發送信號給用戶程序后,用戶堆棧和內核堆棧的變化。沒有分析實時信號,當然整個過程基本一致。很多參考了<情景分析>,所以有些代碼和現在的內核可能不同,比如RESTORE_ALL,但大體的機制是類似的。

1. 一個信號小例子

hex@Gentoo ~/signal $ cat sigint.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sig_int(int signo)
{
    printf("hello\n");
}

int main()
{
    if(signal(SIGINT, sig_int) == SIG_ERR){
        printf("can't catch SIGINT\n");
        exit(-1);
    }

    for(;;)
        ;

    return 0;
}

2. 用戶堆棧里發生的故事

2.1 編譯運行該程序,并設置斷點在sig_int函數開頭(0x80482e8),并設置SIGINT信號的處理方式
hex@Gentoo ~/signal $ gdb ./sigint
(gdb) b *0x80482e8
Breakpoint 1 at 0x80482e8: file sigint.c, line 6.
(gdb) handle SIGINT noprint pass
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y
Signal        Stop    Print    Pass to program    Description
SIGINT        No    No    Yes        Interrupt
(gdb) r
Starting program: /home/gj/signal/sigint

2.2 向該程序發送信號: kill -INT 此程序的pid號
hex@Gentoo ~/signal $ kill -INT 4639

2.3 該程序收到信號后停在斷點處
Breakpoint 1, sig_int (signo=2) at sigint.c:6
6    {
(gdb) i r esp
esp            0xbfffe7ec    0xbfffe7ec
(gdb) x/40a 0xbfffe7ec
0xbfffe7ec:    0xb7fff400    0x2    0x33    0x0
0xbfffe7fc:    0x7b    0x7b    0x8048930 <__libc_csu_init>    0x80488f0 <__libc_csu_fini>
0xbfffe80c:    0xbfffed58    0xbfffed40    0x0    0x0
0xbfffe81c:    0xbfffec18    0x0    0x0    0x0
0xbfffe82c:    0x8048336 <main+58>    0x73    0x213    0xbfffed40
0xbfffe83c:    0x7b    0xbfffead0    0x0    0x0
0xbfffe84c:    0x0    0x0    0x0    0x0
0xbfffe85c:    0x0    0x0    0x0    0x0
0xbfffe86c:    0x0    0x0    0x0    0x0
0xbfffe87c:    0x0    0x0    0x0    0x0
棧上的內容為信號棧sigframe:
根據此結構可以知道:
1). 返回地址0xb7fff400,它指向vdso里的sigreturn
(gdb) x/10i 0xb7fff400
   0xb7fff400 <__kernel_sigreturn>:    pop    %eax
   0xb7fff401 <__kernel_sigreturn+1>:    mov    $0x77,%eax
   0xb7fff406 <__kernel_sigreturn+6>:    int    $0x80
這個地址根據內核的不同而不同,我的內核版本是2.6.38。
2). 信號處理程序完成后,會回到 eip = 0x8048336 的地址繼續執行。


2.4 執行完sig_int函數后,進入了__kernel_sigreturn,接著回到了代碼0x8048336處,一切恢復了正常。
(gdb) x/5i $pc
=> 0x8048336 <main+58>:    jmp    0x8048336 <main+58>
(gdb) i r esp
esp            0xbfffed40    0xbfffed40

在用戶層我們能看到的只有上面這么多信息了,可能有一個地方不能理解:在上面過程c中 從0xbfffe7ec起那一塊棧上的內容從哪來的?(正常情況下堆棧esp應該一直指向在過程d中顯示的esp值0xbfffed40)

現在來看看在上面這些現象之下,內核的堆棧發生了怎樣的變化。

3. 內核堆棧里發生的故事
3.1 發信號時
在 2.2 里當執行kill -INT 4639后,pid為4639的程序(也就是我們運行的 ./sigint)會收到一個信號,但是信號實際都是在內核里實現的。每個進程(這里只講進程的情況,線程類似,線程有一個tid)都有一個pid,與此pid對應有一個結構 task_struct ,在task_struct里有一個變量 struct sigpending pending,當該進程收到信號時,并不會立即作出反應,只是讓內核把這個信號記在了此變量里(它里面是一個鏈表結構)。當然,此時與內核堆棧還沒有多大關系。

3.2 檢測信號
  如果只記錄了信號,但沒有相應反應,那有什么用啊。一個進程在什么 情況下會檢測信號的存在呢?在<情景分析>里說到了:“在中斷機制中,處理器的硬件在每條指令結束時都要檢測是否有中斷請求的存在。信號機制是純軟件的,當然不能依靠硬件來檢測信號的到來。同時,要在每條指令結束時都來檢測顯然是不現實的,甚至是不可能的。所以對信號的檢測機制是:每當從系統調用,中斷處理或異常處理返回到用戶空間的前夕;還有就是當進程被從睡眠中喚醒(必定是在系統調用中)的時候,此時若發現有信號在等待就要提前從系統調用返回。總而言之,不管是正常返回還是提前返回,在返回到用戶空間的前夕總是要檢測信號的存在并作出反應。”

  因此,對收到的信號做出反應的時間是 從內核返回用戶空間的前夕,那么有那些情況會讓程序進入內核呢?答案是中斷,異常和系統調用。簡單了解一下它們發生時內核堆棧的變化。
  //-----中斷,異常,系統調用 : 開始
   1)在用戶空間發生中斷時,CPU會自動在內核空間保存用戶堆棧的SS, 用戶堆棧的ESP, EFLAGS, 用戶空間的CS, EIP, 中斷號 - 256
   | 用戶堆棧的SS | 用戶堆棧的ESP | EFLAGS | 用戶空間的CS | EIP | 中斷號 - 256
   進入內核后,會進行一個SAVE_ALL,這樣內核棧上的內容為:
   | 用戶堆棧的SS | 用戶堆棧的ESP | EFLAGS | 用戶空間的CS | EIP | 中斷號 - 256 | ES | DS | EAX | EBP | EDI | ESI | EDX | ECX | EBX

   好了,一切都處理完時,內核jmp到RESTORE_ALL(它是一個宏,例:在x86_32體系結構下,/usr/src/kernel/arch/286/kernel/entry_32.S文件里包含該宏的定義)

   RESTORE做的工作,從它的代碼里就可以看出來了:   
   首先把棧上的 ES | DS | EAX | EBP | EDI | ESI | EDX | ECX | EBX pop到對應的寄存器里
   然后將esp + 4 把 “中斷號 - 256” pop掉
   此時內核棧上的內容為:
   | 用戶堆棧的SS | 用戶堆棧的ESP | EFLAGS | 用戶空間的CS | EIP
   最后執行iret指令,此時CPU會從內核棧上取出SS, ESP, ELFGAS, CS, EIP,然后接著運行。

   2) 在用戶空間發生異常時,CPU自動保存在內核棧的內容為:
   | 用戶堆棧的SS | 用戶堆棧的ESP | EFLAGS | 用戶空間的CS | EIP | 出錯代碼 error_code
   (注:CPU只是在進入異常時才知道是否應該把出錯代碼壓入堆棧(為什么?),而從異常處理通過iret指令返回時已經時過境遷,CPU已經無從知當初發生異常的原因,因此不會自動跳過這一項,而要靠相應的異常處程序對堆棧加以調整,使得在CPU開始執行iret指令時堆棧頂部是返回地址)

   進入內核后,沒有進行SAVE_ALL,而是進入相應的異常處理函數(這個函數是包裝后的,真正的處理函數在后面)(在此函數里會把真正的處理函數的地址push到棧上),然后jmp到各種異常處理所共用的程序入口error_code,它會像SAVE_ALL那樣保存相應的寄存器(沒有保存ES),此時內核空間上的內容為:
   | 用戶堆棧的SS | 用戶堆棧的ESP | EFLAGS | 用戶空間的CS | EIP | 出錯代碼 error_code | 相應異常處理函數入口 | DS | EAX | EBP | EDI | ESI | EDX | ECX | EBX
   (注:如果沒有出錯代碼,則此值為0)

   最后結束時與中斷類似(RESTORE_ALL)。

   3) 發生系統調用時,CPU自動保存在內核棧的內容為:
   | 用戶堆棧的SS | 用戶堆棧的ESP | EFLAGS | 用戶空間的CS | EIP
   為了與中斷和異常的棧一致,在進入系統調用入口(ENTRY(system_call))后會首先push %eax,然后進行SAVE_ALL,此時內核棧上的內容為
   | 用戶堆棧的SS | 用戶堆棧的ESP | EFLAGS | 用戶空間的CS | EIP | EAX | ES | DS | EAX | EBP | EDI | ESI | EDX | ECX | EBX
 
   最后結束時與中斷類似(RESTORE_ALL)。
   //-----中斷,異常,系統調用 : 結束

   中斷,異常,系統調用這部分有一點遺漏的地方:檢測信號的時機就是緊挨著RESTORE_ALL之前發生的。

3.3 對檢測到的信號做出反應
  如果檢測到有要處理的信號時,就要開始做一些準備工作了,此時內核里的內容為(進入內核現場時的內容)
  | 用戶堆棧的SS1 | 用戶堆棧的ESP1 | EFLAGS1 | 用戶空間的CS1 | EIP1 | ? | ES1 | DS1 | EAX1 | EBP1 | EDI1 | ESI1 | EDX1 | ECX1 | EBX1
  (注:?的值有三個選擇:中斷號 - 256/出錯代碼 error_code/出錯代碼 error_code)
  假設將要處理的信號對應的信號處理程序是用戶自己設置的,即本文中SIGINT對應的信號處理程序sig_int。
  現在要做的事情是讓cpu去執行信號處理程序sig_int,但是執行前需要做好準備工作:
  3.3.1  setup_frame
  在用戶空間設置好信號棧(struct sigframe)(假設設置好棧后esp的值為sigframe_esp,在本文中其值為0xbfffe7ec),即在2.3里看到的棧內容。
  注:struct sigframe里至少包含以下內容:
  用戶堆棧的SS1, 用戶堆棧的ESP1, EFLAGS1, 用戶空間的CS1, EIP1, ES1, DS1, EAX1, EBP1, EDI1, ESI1, EDX1, ECX1, EBX1

  3.3.2 設置即將運行的eip的值為信號處理函數sig_int的地址(為0x80482e8),并設置用戶ESP的值為sigframe_esp(為0xbfffe7ec),這是通過修改內核棧里的EIP和ESP的值實現的,因為在從系統調用里iret時,會從內核棧里取EIP,ESP。
  這時內核棧的內核為:
  | 用戶堆棧的SS1 | 0xbfffe7ec | EFLAGS1 | 用戶空間的CS1 | 0x80482e8 | ? | ES1 | DS1 | EAX1 | EBP1 | EDI1 | ESI1 | EDX1 | ECX1 | EBX1
 
  最后,進行RESTORE_ALL,內核棧上的內容為:
  | 用戶堆棧的SS1 | 0xbfffe7ec | EFLAGS1 | 用戶空間的CS1 | 0x80482e8
 
  RESTORE_ALL里執行完iret后,寄存器內容為: EIP為0x80482e8(即sig_int),esp為0xbfffe7ec 。 于是用戶空間到了步驟 2.3

3.4 信號處理程序完成以后
  2.3 -> 2.4,進入了sig_return系統調用,在sig_return里,內核棧的內容為(每個名字后面加一個2以便與前面的1區分)
  | 用戶堆棧的SS2 | 用戶堆棧的ESP2 | EFLAGS2 | 用戶空間的CS2 | EIP2 | ? | ES2 | DS2 | EAX2 | EBP2 | EDI2 | ESI2 | EDX2 | ECX2 | EBX2
  sig_return要做的主要工作就是根據用戶棧里sigframe的值修改內核棧里的內容,使內核棧變為:
  | 用戶堆棧的SS1 | 用戶堆棧的ESP1 | EFLAGS1 | 用戶空間的CS1 | EIP1 | ? | ES1 | DS1 | EAX1 | EBP1 | EDI1 | ESI1 | EDX1 | ECX1 | EBX1
                                                  
  至此內核棧里的內容和進行信號處理前一樣了。經過RESTORE_ALL后,用戶堆棧里的內容也和以前一樣(主要指ESP的值一樣)。

  "kill -INT 4639" 只是一段小插曲。程序從原處開始運行。
posted on 2011-07-26 18:27 hex108 閱讀(4079) 評論(0)  編輯 收藏 引用 所屬分類: Kernel
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            免费看黄裸体一级大秀欧美| 亚洲三级观看| 狠狠色伊人亚洲综合网站色| 国产精品国产馆在线真实露脸| 久热re这里精品视频在线6| 久久精品一区中文字幕| 久久久噜噜噜久久中文字幕色伊伊| 久久免费精品视频| 欧美激情一区二区| 欧美午夜电影在线| 国产精品theporn88| 国产欧美日韩综合精品二区| 国内精品美女在线观看| 91久久精品美女高潮| 亚洲欧美激情四射在线日| 欧美一区二区精品| 欧美风情在线观看| 亚洲影院污污.| 欧美国产第一页| 国产精品系列在线| 亚洲日本电影在线| 欧美影院午夜播放| 最新国产成人在线观看| 午夜视频一区二区| 欧美日韩在线三级| 在线观看国产日韩| 亚洲欧美不卡| 亚洲第一天堂无码专区| 亚洲在线网站| 欧美激情在线有限公司| 国产亚洲激情在线| 一区二区三区精品国产| 欧美96在线丨欧| 亚洲午夜国产成人av电影男同| 欧美一区二区大片| 欧美成人精精品一区二区频| 国产精品免费看片| 一本在线高清不卡dvd| 久久一区视频| 亚洲伊人观看| 国产精品大片wwwwww| 亚洲国产经典视频| 欧美一二区视频| 日韩视频在线观看一区二区| 久久先锋影音| 国外成人免费视频| 久久久久久亚洲精品杨幂换脸 | 一本色道久久88综合亚洲精品ⅰ | 欧美日韩国内| 亚洲级视频在线观看免费1级| 久久久国产精品亚洲一区| 亚洲视频播放| 国产精品国产三级国产aⅴ9色| 亚洲毛片在线观看.| 欧美成黄导航| 老鸭窝91久久精品色噜噜导演| 国产自产v一区二区三区c| 狠狠色丁香久久综合频道| 亚洲欧美一区二区视频| 亚洲视频导航| 国产免费成人在线视频| 久久久久国产精品一区三寸| 午夜视频在线观看一区二区| 国产乱码精品一区二区三区五月婷 | 亚洲视频图片小说| 欧美午夜电影一区| 亚洲欧美久久久| 亚洲先锋成人| 国产欧美日韩亚州综合| 久久av二区| 久久免费视频一区| 亚洲人成免费| 国产精品大片| 午夜视频一区在线观看| 亚洲一区二区三区中文字幕| 久久爱另类一区二区小说| 国产精品亚洲精品| 久久精品噜噜噜成人av农村| 亚洲一区二区精品视频| 国产精品一区视频| 久热成人在线视频| 久久综合伊人| 一本色道**综合亚洲精品蜜桃冫| 日韩一级精品视频在线观看| 国产精品卡一卡二卡三| 久久综合九色综合欧美就去吻| 欧美a级大片| 国产精品theporn| 久久九九电影| 国产欧美91| 久久一区国产| 你懂的视频一区二区| 日韩午夜av| 亚洲尤物在线视频观看| 伊人伊人伊人久久| 欧美国产综合| 欧美天堂亚洲电影院在线播放| 午夜日韩av| 欧美88av| 久久国产精品72免费观看| 乱中年女人伦av一区二区| 正在播放欧美一区| 久久九九精品| 亚洲精品一区中文| 99伊人成综合| 亚洲影视在线播放| 精品福利电影| 一本色道久久综合精品竹菊 | 亚洲一区二区三区精品动漫| 欧美一区激情| 一区二区三区高清视频在线观看| 欧美一级理论片| 中国亚洲黄色| 欧美激情91| 久久婷婷国产综合精品青草| 欧美日韩免费一区二区三区| 欧美国产成人精品| 国内外成人在线| 亚洲一区二区动漫| 一区二区三区.www| 免费亚洲视频| 欧美日韩精品免费| 免费观看国产成人| 国产欧美 在线欧美| 夜夜夜久久久| 日韩午夜在线| 欧美 日韩 国产 一区| 在线看片一区| 99热在这里有精品免费| 欧美高清在线观看| 伊人久久亚洲美女图片| 欧美高清自拍一区| 欧美日韩成人网| 午夜视频在线观看一区二区三区 | 国内久久精品视频| 亚洲精品在线免费| 国内精品久久久久久久影视麻豆| 亚洲麻豆一区| 在线视频你懂得一区| 国产欧美一区二区精品婷婷| 美日韩精品免费观看视频| 欧美18av| 亚洲三级影片| 国产精品久久久久久久午夜片| 亚洲一区二区免费看| 午夜精品久久久久久久男人的天堂 | 免费欧美日韩国产三级电影| 香蕉乱码成人久久天堂爱免费| 久久综合电影一区| 亚洲国产精品成人va在线观看| 精品成人在线观看| 欧美日韩高清区| 免费观看成人www动漫视频| 亚洲视频第一页| 欧美午夜精彩| 鲁大师成人一区二区三区| 国产精品每日更新| 亚洲欧美激情一区| 日韩视频不卡中文| 久久精品99国产精品| 亚洲一二三区视频在线观看| 国产精品日日摸夜夜摸av| 欧美成va人片在线观看| 久久狠狠久久综合桃花| 久久精品国产91精品亚洲| 9久re热视频在线精品| 美女在线一区二区| 亚洲国产精品毛片| 国产偷自视频区视频一区二区| 另类春色校园亚洲| 久久精品国产清自在天天线| 亚洲自拍高清| 亚洲国产成人av| 欧美1区2区3区| 欧美顶级艳妇交换群宴| 欧美在线免费观看| 亚洲欧美中文字幕| 亚洲一区二区三区久久| 一区二区三区高清在线观看| 性欧美xxxx视频在线观看| 亚洲国产高清aⅴ视频| 亚洲欧美综合v| 欧美aa国产视频| 国产亚洲欧美一级| 欧美亚洲在线播放| 日韩视频在线免费| 国产精品午夜在线观看| 卡一卡二国产精品| 欧美激情在线播放| 亚洲宅男天堂在线观看无病毒| 亚洲精品小视频在线观看| 亚洲巨乳在线| 欧美成人一区在线| 国产麻豆视频精品| 国产精品99久久久久久久久| 亚洲高清一区二| 欧美视频中文字幕| 欧美成人一区二区三区片免费| 国产精品手机在线| 国产日本欧洲亚洲|