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

隨筆 - 47, 文章 - 10, 評論 - 8, 引用 - 0
數據加載中……

簡明x86匯編語言教程(六)

原創:司徒彥南

4.0 利用子程序與中斷

已經掌握了匯編語言?沒錯,你現在已經可以去破譯別人代碼中的秘密。然而,我們還有一件重要的東西沒有提到,那就是自程序和中斷。這兩件東西是如此的重要,以至于你的程序幾乎不可能離開它們。

4.1 子程序

在高級語言中我們經常要用到子程序。高級語言中,子程序是如此的神奇,我們能夠定義和主程序,或其他子程序一樣的變量名,而訪問不同的變量,并且,還不和程序的其他部分相沖突。

然而遺憾的是,這種“優勢”在匯編語言中是不存在的。

匯編語言并不注重如何減輕程序員的負擔;相反,匯編語言依賴程序員的良好設計,以期發揮CPU的最佳性能。匯編語言不是結構化的語言,因此,它不提供直接的“局部變量”。如果需要“局部變量”,只能通過堆或棧自行實現。

從這個意義上講,匯編語言的子程序更像GWBASIC中的GOSUB調用的那些“子程序”。所有的“變量”(本質上,屬于進程的內存和寄存器)為整個程序所共享,高級語言編譯器所做的,將局部變量放到堆或棧中的操作,只能自行實現。

參數的傳遞是靠寄存器和堆棧來完成的。高級語言中,子程序(函數、過程,或類似概念的東西)依賴于堆和棧來傳遞。

讓我們來簡單地分析一下一般高級語言的子程序的執行過程。無論C、C++、BASIC、Pascal,這一部分基本都是一致的。


  • 調用者將子程序執行完成時應返回的地址、參數壓入堆棧
  • 子程序使用BP指針+偏移量對棧中的參數尋址,并取出、完成操作
  • 子程序使用RET或RETF指令返回。此時,CPU將IP置為堆棧中保存的地址,并繼續予以執行

毋庸置疑,堆棧在整個過程中發揮著非常重要的作用。不過,本質上對子程序最重要的還是返回地址。如果子程序不知道這個地址,那么系統將會崩潰。

調用子程序的指令是CALL,對應的返回指令是RET。此外,還有一組指令,即ENTER和LEAVE,它們可以幫助進行堆棧的維護。

CALL指令的參數是被調用子程序的地址。使用宏匯編的時候,這通常是一個標號。CALL和RET,以及ENTER和LEAVE配對,可以實現對于堆棧的自動操作,而不需要程序員進行PUSH/POP,以及跳轉的操作,從而提高了效率。

作為一個編譯器的實現實例,我用Visual C++編譯了一段C++程序代碼,這段匯編代碼是使用特定的編譯選項得到的結果,正常的RELEASE代碼會比它精簡得多。包含源代碼的部分反匯編結果如下(取自Visual C++調試器的運行結果,我刪除了10條int 3指令,并加上了一些注釋,除此之外,沒有做任何修改):

1: int myTransform(int nInput){
00401000 push ebp?????????????????? ; 保護現場原先的EBP指針
00401001 mov ebp,esp
2: return (nInput*2 + 3) % 7;
00401003 mov eax,dword ptr [nInput] ; 取參數
00401006 lea eax,[eax+eax+3]??????? ; LEA比ADD加法更快
0040100A cdq??????????????????????? ; DWORD->QWORD(擴展字長)
0040100B mov ecx,7????????????????? ; 除數
00401010 idiv eax,ecx?????????????? ; 除
00401012 mov eax,edx??????????????? ; 商->eax(eax中保存返回值)
3: }
00401014 pop ebp??????????????????? ; 恢復現場的ebp指針
00401015 ret??????????????????????? ; 返回
; 此處刪除10條int 3指令,它們是方便調試用的,并不影響程序行為。

4:
5:
int main(int argc, char* argv[])
6: {
00401020 push ebp?????????????????? ; 保護現場原先的EBP指針
00401021 mov ebp,esp
00401023 sub esp,10h??????????????? ; 為取argc, argv修正堆棧指針。
7:int a[3];
8:for(register int i=0; i<3; i++){
00401026 mov dword ptr [i],0??????? ; 0->i
0040102D jmp main+18h (00401038)??? ; 判斷循環條件
0040102F mov eax,dword ptr [i]????? ; i->eax
00401032 add eax,1????????????????? ; eax ++
00401035 mov dword ptr [i],eax????? ; eax->i
00401038 cmp dword ptr [i],3??????? ; 循環條件: i與3比較
0040103C jge main+33h (00401053)??? ; 如果不符合條件,則應結束循環
9: a[i] = myTransform(i);
0040103E mov ecx,dword ptr [i]????? ; i->ecx
00401041 push ecx?????????????????? ; ecx (i) -> 堆棧
00401042 call myTransform (00401000); 調用myTransform
00401047 add esp,4????????????????? ; esp+=4: 在堆中的新單元
??????????????????????????????????? ; 準備存放返回結果
0040104A mov edx,dword ptr [i]????? ; i->edx
0040104D mov dword ptr a[edx*4],eax ; 將eax(myTransform返回值)
??????????????????????????????????? ; 放回a[i]
10: }
00401051 jmp main+0Fh (0040102f)??? ; 計算i++,并繼續循環
11:return 0;
00401053 xor eax,eax??????????????? ; 返回值應該是0
12: }
00401055 mov esp,ebp??????????????? ; 恢復堆棧指針
00401057 pop ebp??????????????????? ; 恢復BP
00401058 ret??????????????????????? ; 返回調用者(C++運行環境)

上述代碼確實做了一些無用功,當然,這是因為編譯器沒有對這段代碼進行優化。讓我們來關注一下這段代碼中,是如何調用子程序的。不考慮myTransform這個函數實際進行的數值運算,最讓我感興趣的是這一行代碼:

00401003 mov eax,dword ptr [nInput] ; 取參數

這里nInput是一個簡簡單單的變量符號嗎?Visual C++的調試器顯然不能告訴我們答案——它的設計目標是為了方便程序調試,而不是向你揭示編譯器生成的代碼的實際構造。我用另外一個反匯編器得到的結果是:

00401003 mov eax,dword ptr [ebp+8] ? ; 取參數

這和我們在main()中看到的壓棧順序是完全吻合的(注意,程序運行到這個地方的時候,EBP=ESP)。main()最終將i的通過堆棧傳遞給了myTransform()。

剖析上面的程序只是說明了我前面所提到的子程序的一部分用法。對于匯編語言來說,完全沒有必要拘泥于結構化程序設計的框架(在今天,使用匯編的主要目的在于提高執行效率,而不是方便程序的維護和調試,因為匯編不可能在這一點上做得比C++更好)。考慮下面的程序:

void myTransform1(int nCount, char* sBytes){
? for(register int i=1; i<nCount; i++)
??? sBytes[i] += sBytes[i-1];
? for(i=0; i<nCount; i++)
??? sBytes[i] <<= 1;
}

void myTransform2(int nCount, char* sBytes){
? for(register int i=0; i<nCount; i++)
??? sBytes[i] <<= 1;
}

很容易看出,這兩個函數包含了公共部分,即

? for(i=0; i<nCount; i++)
??? sBytes[i] <<= 1;

目前,還沒有編譯器能夠做到將這兩部分合并。依然沿用剛才的編譯選項,得到的反匯編結果是(同樣地刪除了int 3):

1:void myTransform1(int nCount, char* sBytes){
00401000 push ebp
00401001 mov ebp,esp
00401003 push ecx
2:for(register int i=1; i<nCount; i++)
00401004 mov dword ptr [i],1
0040100B jmp myTransform1+16h (00401016)
0040100D mov eax,dword ptr [i]
00401010 add eax,1
00401013 mov dword ptr [i],eax
00401016 mov ecx,dword ptr [i]
00401019 cmp ecx,dword ptr [nCount]
0040101C jge myTransform1+3Dh (0040103d)
3: sBytes[i] += sBytes[i-1];
0040101E mov edx,dword ptr [sBytes]
00401021 add edx,dword ptr [i]
00401024 movsx eax,byte ptr [edx-1]
00401028 mov ecx,dword ptr [sBytes]
0040102B add ecx,dword ptr [i]
0040102E movsx edx,byte ptr [ecx]
00401031 add edx,eax
00401033 mov eax,dword ptr [sBytes]
00401036 add eax,dword ptr [i]
00401039 mov byte ptr [eax],dl
0040103B jmp myTransform1+0Dh (0040100d)
4:for(i=0; i<nCount; i++)
0040103D mov dword ptr [i],0
00401044 jmp myTransform1+4Fh (0040104f)
00401046 mov ecx,dword ptr [i]
00401049 add ecx,1
0040104C mov dword ptr [i],ecx
0040104F mov edx,dword ptr [i]
00401052 cmp edx,dword ptr [nCount]
00401055 jge myTransform1+6Bh (0040106b)
5: sBytes[i] <<= 1;
00401057 mov eax,dword ptr [sBytes]
0040105A add eax,dword ptr [i]
0040105D mov cl,byte ptr [eax]
0040105F shl cl,1
00401061 mov edx,dword ptr [sBytes]
00401064 add edx,dword ptr [i]
00401067 mov byte ptr [edx],cl
00401069 jmp myTransform1+46h (00401046)
6: }
0040106B mov esp,ebp
0040106D pop ebp
0040106E ret
7:
8:void myTransform2(int nCount, char* sBytes){
00401070 push ebp
00401071 mov ebp,esp
00401073 push ecx
9:for(register int i=0; i<nCount; i++)
00401074 mov dword ptr [i],0
0040107B jmp myTransform2+16h (00401086)
0040107D mov eax,dword ptr [i]
00401080 add eax,1
00401083 mov dword ptr [i],eax
00401086 mov ecx,dword ptr [i]
00401089 cmp ecx,dword ptr [nCount]
0040108C jge myTransform2+32h (004010a2)
10: sBytes[i] <<= 1;
0040108E mov edx,dword ptr [sBytes]
00401091 add edx,dword ptr [i]
00401094 mov al,byte ptr [edx]
00401096 shl al,1
00401098 mov ecx,dword ptr [sBytes]
0040109B add ecx,dword ptr [i]
0040109E mov byte ptr [ecx],al
004010A0 jmp myTransform2+0Dh (0040107d)
11: }
004010A2 mov esp,ebp
004010A4 pop ebp
004010A5 ret
12:
13:
int main(int argc, char* argv[])
14: {
004010B0 push ebp
004010B1 mov ebp,esp
004010B3 sub esp,0CCh
15:char a[200];
16:for(register int i=0; i<200; i++)a[i]=i;
004010B9 mov dword ptr [i],0
004010C3 jmp main+24h (004010d4)
004010C5 mov eax,dword ptr [i]
004010CB add eax,1
004010CE mov dword ptr [i],eax
004010D4 cmp dword ptr [i],0C8h
004010DE jge main+45h (004010f5)
004010E0 mov ecx,dword ptr [i]
004010E6 mov dl,byte ptr [i]
004010EC mov byte ptr a[ecx],dl
004010F3 jmp main+15h (004010c5)
17: myTransform1(200, a);
004010F5 lea eax,[a]
004010FB push eax
004010FC push 0C8h
00401101 call myTransform1 (00401000)
00401106 add esp,8
18: myTransform2(200, a);
00401109 lea ecx,[a]
0040110F push ecx
00401110 push 0C8h
00401115 call myTransform2 (00401070)
0040111A add esp,8
19:return 0;
0040111D xor eax,eax
20: }
0040111F mov esp,ebp
00401121 pop ebp
00401122 ret

非常明顯地,0040103d-0040106e和00401074-004010a5這兩段代碼存在少量的差別,但很顯然只是對寄存器的偏好不同(編譯器在優化時,這可能會減少堆棧操作,從而提高性能,但在這里只是使用了不同的寄存器而已)

對代碼進行合并的好處是非常明顯的。新的操作系統往往使用頁式內存管理。當內存不足時,程序往往會頻繁引發頁面失效(Page faults),從而引發操作系統從磁盤中讀取一些東西。磁盤的速度趕不上內存的速度,因此,這一行為將導致性能的下降。通過合并一部分代碼,可以減少程序的大小,這意味著減少頁面失效的可能性,從而軟件的性能會有所提高?/p>

當然,這樣做的代價也不算低——你的程序將變得難懂,并且難于維護。因此,再進行這樣的優化之前,一定要注意:


  • 優化前的程序必須是正確的。如果你不能確保這一點,那么這種優化必將給你的調試帶來極大的麻煩。
  • 優化前的程序實現最好是最優的。仔細檢查你的設計,看看是否已經使用了最合適(即,對于此程序而言最優)的算法,并且已經在高級語言許可的范圍內進行了最好的實現。
  • 優化最好能夠非常有效地減少程序大小(例如,如果只是減少十幾個字節,恐怕就沒什么必要了),或非常有效地提高程序的運行速度(如果代碼只是運行一次,并且只是節省幾個時鐘周期,那么在多數場合都沒有意義)。否則,這種優化將得不償失。

4.2 中斷

中斷應該說是一個陳舊的話題。在新的系統中,它的作用正在逐漸被削弱,而變成操作系統專用的東西。并不是所有的計算機系統都提供中斷,然而在x86系統中,它的作用是不可替代的。

中斷實際上是一類特殊的子程序。它通常由系統調用,以響應突發事件。

例如,進行磁盤操作時,為了提高性能,可能會使用DMA方式進行操作。CPU向DMA控制器發出指令,要求外設和內存直接交換數據,而不通過CPU。然后,CPU轉去進行起他的操作;當數據交換結束時,CPU可能需要進行一些后續操作,但此時它如何才能知道DMA已經完成了操作呢?

很顯然不是依靠CPU去查詢狀態——這樣DMA的優勢就不明顯了。為了盡可能地利用DMA的優勢,在完成DMA操作的時候,DMA會告訴CPU“這事兒我辦完了”,然后CPU會根據需要進行處理。

這種處理可能很復雜,需要若干條指令來完成。子程序是一個不錯的主意,不過,CALL指令需要指定地址,讓外設強迫CPU執行一條CALL指令也違背了CPU作為核心控制單元的設計初衷??紤]到這些,在x86系統中引入了中斷向量的概念。

中斷向量表是保存在系統數據區(實模式下,是0:0開始的一段區域)的一組指針。這組指針指向每一個中斷服務程序的地址。整個中斷向量表的結構是一個線性表。

每一個中斷服務有自己的唯一的編號,我們通常稱之為中斷號。每一個中斷號對應中斷向量表中的一項,也就是一個中斷向量。外設向CPU發出中斷請求,而CPU自己將根據當前的程序狀態決定是否中斷當前程序并調用相應的中斷服務。

不難根據造成中斷的原因將中斷分為兩類:硬件中斷和軟件中斷。硬件中斷有很多分類方法,如根據是否可以屏蔽分類、根據優先級高低分類,等等??紤]到這些分類并不一定科學,并且對于我們介紹中斷的使用沒有太大的幫助,因此我并不打算太詳細地介紹它(在本教程的高級篇中,關于加密解密的部分會提到某些硬件中斷的利用,但那是后話)。

在設計操作系統時,中斷向量的概念曾經帶來過很大的便利。操作系統隨時可能升級,這樣,通過CALL來調用操作系統的服務(如果說每個程序都包含對于文件系統、進程表這些應該由操作系統管理的數據的直接操作的話,不僅會造成程序的臃腫,而且不利于系統的安全)就顯得不太合適了——沒人能知道,以后的操作系統的服務程序入口點會不會是那兒。軟件中斷的存在為解決這個問題提供了方便。

對于一臺包含了BIOS的計算機來說,啟動的時候系統已經提供了一部分服務,例如顯示服務。無論你的BIOS、顯示卡有多么的“個性”,只要他們和IBM PC兼容,那么此時你肯定可以通過調用16(10h)號中斷來使用顯示服務。調用中斷的指令是


int 中斷號
??

這將引發CPU去調用一個中斷。CPU將保存當前的程序狀態字,清除Trap和Interrupt兩個標志,將即將執行的指令地址壓入堆棧,并調用中斷服務(根據中斷向量表)。

編寫中斷服務程序不是一件容易的事情。很多時候,中斷服務程序必須寫成可重入代碼(或純代碼,pure code)。所謂可重入代碼是指,程序的運行過程中可以被打斷,并由開始處再次執行,并且在合理的范圍內(多次重入,而不造成堆棧溢出等其他問題),程序可以在被打斷處繼續執行,并且執行結果不受影響。

由于在多線程環境中等其他一些地方進行程序設計時也需要考慮這個因素,因此這里著重講一下可重入代碼的編寫。

可重入代碼最主要的要求就是,程序不應使用某個指定的內存地址的內存(對于高級語言來說,這通常是全局變量,或對象的成員)。如果可能的話,應使用寄存器,或其他方式來解決。如果不能做到這一點,則必須在開始、結束的時候分別禁止和啟用中斷,并且,運行時間不能太長。

下面用C語言分別舉一個可重入函數,和兩個非可重入函數的例子(注. 這些例子應該是在某本多線程或操作系統的書上看到的,遺憾的是我想不起來是哪本書了,在這里先感謝那位作者提供的范例):

可重入函數:

void strcpy(char* lpszDest, char* lpszSrc){
? while(*dest++=*src++);
? *dest=0;
}

非可重入函數

char cTemp;???????????????? ????????????????? // 全局變量

void SwapChar(char* lpcX, char* lpcY){
? cTemp = *lpcX; *lpcX = *lpcY; lpcY = cTemp; // 引用了全局變量,在分享內存的多個線程中可能造成問題
}

非可重入函數

void SwapChar2(char* lpcX, char* lpcY){
? static char cTemp;???????????????? ???????? // 靜態變量
? cTemp = *lpcX; *lpcX = *lpcY; lpcY = cTemp; // 引用了靜態變量,在分享內存的多個線程中可能造成問題
}

中斷利用的是系統的棧。棧操作是可重入的(因為??梢员WC“先進后出”),因此,我們并不需要考慮棧操作的重入問題。使用宏匯編器寫出可重入的匯編代碼需要注意一些問題。簡單地說,干脆不要用標號作為變量是一個不錯的主意。

使用高級語言編寫可重入程序相對來講輕松一些。把持住不訪問那些全局(或當前對象的)變量,不使用靜態局部變量,堅持只適用局部變量,寫出的程序就將是可重入的。

書歸正傳,調用軟件中斷時,通常都是通過寄存器傳進、傳出參數。這意味著你的int指令周圍也許會存在一些“幫手”,比如下面的代碼:

mov ax, 4c00h
int 21h

就是通過調用DOS中斷服務返回父進程,并帶回錯誤反饋碼0。其中,ax中的數據4c00h就是傳遞給DOS中斷服務的參數。

到這里,x86匯編語言的基礎部分就基本上講完了,《簡明x86匯編語言教程》的初級篇——匯編語言基礎也就到此告一段落。當然,目前為止,我只是蜻蜓點水一般提到了一些學習x86匯編語言中我認為需要注意的重要概念。許多東西,包括全部匯編語句的時序特性(指令執行周期數,以及指令周期中各個階段的節拍數等)、功能、參數等等,限于個人水平和篇幅我都沒有作詳細介紹。如果您對這些內容感興趣,請參考Intel和AMD兩大CPU供應商網站上提供的開發人員參考。

在以后的簡明x86匯編語言教程中級篇和高級篇中,我將著重介紹匯編語言的調試技術、優化,以及一些具體的應用技巧,包括反跟蹤、反反跟蹤、加密解密、病毒與反病毒等等。

posted on 2006-11-06 10:36 編程之道 閱讀(409) 評論(0)  編輯 收藏 引用 所屬分類: 開發相關 、ASM

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲欧美日韩在线播放| 国产精品自在线| 亚洲精品麻豆| 欧美国产一区视频在线观看| 久久免费精品日本久久中文字幕| 久久久久www| 久热成人在线视频| 亚洲国产成人精品视频| 日韩一区二区精品| 亚洲欧美在线高清| 久久婷婷久久一区二区三区| 免费日韩成人| 国产精品久久国产精品99gif| 国产欧美一区二区精品仙草咪| 国内揄拍国内精品少妇国语| 亚洲激情视频在线| 亚洲欧美日韩在线观看a三区| 亚洲欧美清纯在线制服| 久久综合狠狠综合久久激情| 亚洲国产精品第一区二区三区| 亚洲精品美女久久久久| 亚洲图片你懂的| 久久精品国产精品| 欧美日韩一区二区三区在线| 黑丝一区二区三区| 亚洲视频在线观看一区| 久久久中精品2020中文| 亚洲精品自在久久| 久久精品99国产精品| 欧美精品高清视频| 国产专区综合网| 一本一本久久| 久热精品视频在线免费观看 | 亚洲另类自拍| 亚洲影院免费观看| 欧美wwwwww| 狠狠狠色丁香婷婷综合久久五月| 一区二区三区成人 | 亚洲精品久久视频| 篠田优中文在线播放第一区| 欧美精品午夜视频| 在线成人小视频| 久久不射电影网| 中文在线一区| 欧美精品三级日韩久久| 狠狠噜噜久久| 欧美伊人久久久久久久久影院| 亚洲国产美女| 蜜臀久久99精品久久久画质超高清| 国产欧美日韩不卡免费| 亚洲女女女同性video| 亚洲精品久久久蜜桃| 欧美aⅴ一区二区三区视频| 激情av一区二区| 久久精品中文字幕一区| 亚洲欧美日本另类| 一区二区三区偷拍| 欧美日韩综合视频网址| 亚洲毛片av| 欧美黄网免费在线观看| 久久综合一区二区三区| 一色屋精品视频免费看| 久久久久久久久岛国免费| 亚洲一区二三| 国产九九精品视频| 亚洲一区在线免费观看| 一区二区三区蜜桃网| 欧美无砖砖区免费| 亚洲自拍偷拍一区| 亚洲一区国产一区| 国产欧美一区二区精品性色| 久久er精品视频| 欧美资源在线观看| 在线看日韩欧美| 欧美黄色大片网站| 欧美日韩免费视频| 亚洲视频电影在线| 亚洲午夜精品一区二区| 国产精品嫩草久久久久| 久久aⅴ国产欧美74aaa| 欧美一区二区三区男人的天堂| 国产日韩欧美高清| 老司机精品久久| 亚洲欧美网站| 狠狠色噜噜狠狠狠狠色吗综合| 久久夜色精品国产亚洲aⅴ| 狂野欧美一区| 亚洲一区二区三区久久| 久久电影一区| 99综合电影在线视频| 亚洲欧美激情四射在线日 | 久久狠狠婷婷| 亚洲高清一区二区三区| 9久草视频在线视频精品| 国产亚洲精品资源在线26u| 亚洲国产精品一区二区第一页 | 亚洲国产精品999| 日韩亚洲国产欧美| 韩国福利一区| 亚洲精品一区二区网址| 国产一区亚洲一区| 一本色道久久88综合日韩精品| 国产女人aaa级久久久级| 欧美高清视频在线| 国产视频一区在线| 日韩午夜一区| 亚洲激情亚洲| 欧美亚洲自偷自偷| 亚洲五月六月| 亚洲国产精品va| 国产视频欧美视频| 亚洲精品社区| 亚洲韩国日本中文字幕| 亚洲与欧洲av电影| 在线一区二区三区做爰视频网站 | 亚洲看片免费| 亚洲第一区在线观看| 亚洲欧美日本视频在线观看| 亚洲精品乱码久久久久久久久| 亚洲欧美日韩精品| 亚洲一区二区在| 欧美激情 亚洲a∨综合| 老牛嫩草一区二区三区日本| 国产视频久久久久久久| 亚洲一区二区三区久久| 亚洲视频一区在线| 欧美日韩国产精品| 亚洲日本中文字幕| 日韩视频不卡中文| 美女亚洲精品| 欧美国产91| 亚洲国产导航| 久久综合综合久久综合| 美女精品网站| 在线欧美影院| 麻豆成人小视频| 欧美激情一区在线观看| 亚洲福利一区| 欧美高清视频免费观看| 欧美韩日亚洲| 99精品久久久| 欧美色视频一区| 亚洲性视频h| 欧美在线999| 国产亚洲成av人在线观看导航| 亚洲欧美日韩精品久久奇米色影视| 亚洲欧美日韩高清| 国产精品制服诱惑| 香蕉久久国产| 欧美高清视频一区二区| 亚洲伦理在线观看| 欧美日韩综合另类| 性xx色xx综合久久久xx| 久久精品视频在线看| 狠狠色丁香婷婷综合| 久久综合九色综合欧美狠狠| 亚洲福利视频专区| 亚洲午夜电影网| 国产在线拍揄自揄视频不卡99| 久久久久在线| 日韩午夜精品| 久久国产精品久久久久久| 狠狠色综合网站久久久久久久| 美女露胸一区二区三区| 9久草视频在线视频精品| 久久久久高清| 亚洲视频综合在线| 在线精品高清中文字幕| 欧美人与性动交cc0o| 亚洲欧美日韩精品久久奇米色影视| 亚洲免费一区二区| 国产精品成人va在线观看| 欧美一区在线直播| 91久久精品一区二区别| 欧美亚洲一区在线| 亚洲国产精品一区二区久| 欧美午夜精品久久久| 国产精品久久久久久久久免费樱桃 | 136国产福利精品导航| 免费在线视频一区| 亚洲一区二区在| 亚洲电影av在线| 久久国产精品久久久| 99re6热在线精品视频播放速度| 国产精品网站在线播放| 欧美成人亚洲成人| 欧美在线观看网站| 亚洲视频精品| 亚洲三级色网| 欧美顶级少妇做爰| 欧美一区二区三区另类| 一区二区三区回区在观看免费视频| 国内外成人在线| 国产精品麻豆成人av电影艾秋| 久久一二三区| 久久久久国产一区二区| 翔田千里一区二区| 亚洲午夜在线观看| 国产精品99久久久久久宅男 | 韩国精品久久久999|