日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

C指针原理(23)-win32汇编及.NET调试

發布時間:2025/3/12 asp.net 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C指针原理(23)-win32汇编及.NET调试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2018-12-28 20:36:07
在WINDOWS系統能用到匯編的機會不多,基本都可以用C或C++代勞,更何況現在MICROSOFT的Visual Studio 系列工具非常強大,WINDOWS下的開發已經在向.NET方面發展,實際調用WINDOWS SDK的機會也不多。 WIN32匯編編寫窗口程序需要調用大量的WINDOWS 的API,而且提供了高級語言才有的條件語句和循環語句,難度相對于LINUX下的AT&T匯編要小很多。

匯編可以開發WINDOWS程序?答案是肯定的,用WIN32匯編語言開發出來的WINDOWS程序具有執行效率高、占用空間小等特點。

一、開發工具下載與安裝

在眾多WIN32匯編開發工具中,MASM32筆者比較偏愛,它具有很多代碼示例和豐富的開發資源,在下列下載地址中選擇一個地址下載MASM32。

http://website.assemblercode.com/masm32/m32v9r.zip

http://masm32.masmcode.com/masm32/m32v9r.zip

http://webhost.ccp.com/~win32/hutch/m32v9r.zip

二、知識預備

1、寄存器

為了提高運算速度和數據的存取速度,在計算機的CPU內,有一組硬件裝置,第一個裝置內存放CPU運算需要的數,這些數值可供CPU直接存取,這組裝置叫寄存器。寄存器分為通用寄存器、段寄存器、程序指針寄存器、標志寄存器。

編程最常用就是通用寄存器,常用的通用寄存器有eax,ebx,ecx,edx,esi,edi等等,現代計算機的CPU一般是以32位為單位進行運算,因此一個寄存器最大能存放32位的二進制數。每個寄存器通常都有它默認的用法,所謂默認只是一種編程的習慣,你可以不遵守這些用法,但是有些情況下必須遵守,因為我們開發的是WINDOWS程序,要遵守WINDOWS操作系統的規定和匯編語法本身的約束,比如調用一個WINDOWSAPI函數,返回值放在EAX,堆棧的棧頂地址在esp,在匯編語言的循環中,ECX內存放循環的次數。具體寄存器的使用會在以后介紹。

2、堆棧

堆棧是個非常古老的概念,在DOS時代就有了,也是個非常重要的東西,程序沒了它就活不了,堆棧就是在內存里分配一個區域,使用這個區域必須遵守一個規定:后進先出,后進來的先出去,可以把它想像成一個空木箱,首先往里面放棉衣,然后往里面放書,最后放上運動服。如果要取出書,必須得把最后放上的運動服取出,放的順序是棉衣->書->運動服,取的順序是運動服->書->棉衣,堆棧也是如此。

先解釋一下什么是地址,內存價格的便宜和內存容量的擴大,WINDOWS虛擬內存早已出現,內存中放著眾多的數據,必須要有方法表示內存某個地點,這個地點就用地址來表示。把內存以字節為單位劃分,某個地址表示某個字節的地址,如左下圖是一個內有4個成員的堆棧,堆棧里的成員以一個字節為單位(數的右邊標明了以十六進制表示的地址,如1001)

±-+

|AF| 地址:AF21

±-+

|03| 地址:AF20

±-+

|30| 地址:AF19

±-+

|F1| 地址:AF18

±-+

堆棧是向下增長的,每增加一個成員,棧頂(堆棧頂部的地址)的地址減1,對于這個堆棧,棧頂地址是AF18,如果再往這個堆棧里增加一個成員的話,它的地址是:AF18-1=AF17。如果往這個堆棧里增加一個32位的數,棧頂的地址是多少呢,32位的數占4個成員的位置,棧頂的地址為:AF18-4=AF14。

在這個堆棧中增加一個32位數DAB0CD90,新的堆棧如下:

±-+

|AF| 地址:AF21

±-+

|03| 地址:AF20

±-+

|30| 地址:AF19

±-+

|F1| 地址:AF18

±-+

|DA| 地址:AF17

±-+

|B0| 地址:AF16

±-+

|CD| 地址:AF15

±-+

|90| 地址:AF14

±-+

如果從堆棧里拿走一個32位數,則棧頂的地址為:AF14+4=AF18

三、WIN32匯編語言的語法

為了方便大家理解和入門,下面盡量使用宏匯編和偽指令地方進行描述,也正因為有了宏匯編和偽指令的幫助,WIN32匯編才具有很多高級語言的特性,很多語法和C差不多。

1、WIN32匯編程序基本結構

.386

.MODEL Flat,STDCALL

.DATA

初始化值的全局變量定義

.DATA?

未初始化值的全局變量定義

.CONST

常量定義

.CODE

.............................

程序入口LABEL

........................end程序入口LABEL

2、變量定義

(1)定義全局變量

全局變量定義在.data和.data?內,

初始化變量的定義方式如下:

.data

變量名 類型 初始值1,初始值2,…

變量名 類型 重復次數dup(初始值1,初始值2,…)

注意:如果用?表示初始值的話,則表示0

未初始化變量的定義方式是

.data?

變量名 類型 ?

(2)條件測試語句

(A)基本結構

.IF條件程序代碼[.ELSEIF]條件比較程序代碼.......

[.ELSE]

程序代碼.ENDIF

(3)操作符

(A)比較操作符

== 相等

!= 不等于

大于

>= 大于或等于

< 小于

<= 小于或等于

& 位測試

! 邏輯非

&& 邏輯與

|| 邏輯或

(B)位操作符

AND按位與

OR 按位或

XOR 異或

SHL邏輯左移SHR邏輯右移

?標志寄存器操作符

CARRY?是否進位

OVERFLOW? 是否溢出

PARITY? 奇偶位是否置位

SIGN? 符號位標志位是否被置位

ZERO? 零位標志位是否置位

(4)循環語句

(A)while語句

while 條件

....................

[.break[.if 退出條件]]

[.contine[.if 退出條件]]]

.end

(B)repeat語句

.repeat

[.break[.if 退出條件]]

[.contine[.if 退出條件]]]

.until 條件(或.untilcxz [條件])

(5)子程序定義

1、定義

子程序名 proc [距離][語言類型][可視區域][USERS 寄存器列表][,參數:類型]…[VARARG]local 局部變量列表

子程序名 endp

2、如果在未定義前使用,要聲明、

函數名 proto [距離][語言][參數1]:數據類型,[參數2]:數據類型,…

(6)數據結構

(A)聲明

wndclass struct

wndclass ends

(B)定義

mystruct wndclass<1,1,…,1>

mystruct wndclass <>

?使用

mov eax,mystruct.lpfnwndproc

mov esi,offset mystruct

assume esi: ptr WNDCLASS

mov eax,[esi].lpfnwndproc

assume esi:nothing

四、在WIN32匯編中的使用WINDOWS API

WIN32匯編如果沒有API的幫助無法實現很多功能,筆者沒見過在WIN32匯編程序不調用API的。

調用API實際上是靠堆棧來完成參數傳遞的,既然是堆棧,那就要遵守后進先出的原則,這意味API的第一個參數是最后一個放入堆棧的,最后一個參數是第一個放入堆棧的。

調用方式如下:

push 參數n

push 參數2

push 參數1

call API函數名

為了簡化代碼,也可以使用以下這種方式調用API

invoke API函數名,參數1,參數2,…,參數n

我們用WIN32匯編構建第一個WINODWS程序,這個程序完成顯示一個帶問號的對話框,對話框的內容是現在系統時間。

首先,打開MASM32Editor(在桌面上可以找到圖標),在里面輸入以下代碼:

.386.model flat, stdcalloption casemap :none

;#################################################################

include windows.incinclude user32.incinclude kernel32.incinclude gdi32.incinclude masm32.incincludelib user32.libincludelib kernel32.libincludelib gdi32.libincludelib masm32.lib

;#################################################################
.data?
szbuffer db 100 dup(?)
.data
szcaptionName db “我的HELLO,WORLD!”,0
szbegin db “現在時間:”
sztext db 100 dup(?)
;################################################################# .code

start:
;程序的入口
call _callgetnow
invoke MessageBox,NULL,offset szbegin,offsetszcaptionName,MB_ICONQUESTION or MB_OK
invoke ExitProcess,eax
;#################################################################
_callgetnow proc
pushad
invokeGetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,NULL,NULL,addrsztext,100
invokeGetTimeFormat,LOCALE_USER_DEFAULT,LOCALE_NOUSEROVERRIDE,NULL,NULL,addrszbuffer,100

invokeszCatStr,addr sztext,addr szbuffer popad ret

_callgetnow endp
;#################################################################

end start

將上述代碼保存為HELLOWORLD.ASM后,對程序進行編譯。

在編譯前參照下圖設置好系統的環境變量,path變量加上x:\masm32\bin,lib變量加上x:\masm32\lib,include變量加上x:\masm32\include。

確環境變量設置好后,進入DOS窗口開始編譯。

首先運行ml,編譯成coff文件格式

然后運行LINK,進行鏈接,生成EXE文件,

大功造成,運行一下試試效果吧!

下面我們接著來做一個有些難度的helloworld,這個程序將系統時間直接顯示在桌面上。程序源代碼如下:

.386.model flat, stdcalloption casemap :none ;#########################################################################include windows.incinclude user32.incinclude kernel32.incinclude gdi32.incinclude masm32.incincludelib user32.libincludelib kernel32.libincludelib gdi32.libincludelib masm32.lib;#########################################################################.data?szbuffer db 100 dup(?).dataszmssucesscap db "HELLO,WORLD!深入",0szmssucesstext db "在桌面的(300,300)處顯示了當前時間",0szmscap db "錯誤",0szmstext1 db "無法在桌面上顯示!",0szmstext2 db "無法得到全屏DC!",0szbegin db "現在時間:"sztext db 100 dup(?) ;#########################################################################.codestart: ;程序的入口_showtext proto :DWORDcall _callgetnowinvoke _showtext,offset szbegininvoke ExitProcess,eax ;######################################################################### _callgetnow procpushadinvokeGetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,NULL,NULL,addrsztext,100invokeGetTimeFormat,LOCALE_USER_DEFAULT,LOCALE_NOUSEROVERRIDE,NULL,NULL,addrszbuffer,100invokeszCatStr,addr sztext,addr szbufferpopadret _callgetnow endp ;######################################################################### _showtext proc lpsztext:DWORDLOCAL@Desktopdc:HDCLOCAL@dwcolor:DWORDpushadmov@dwcolor,00FF0000hinvokeGetWindowDC,NULLcmpeax,0jne @finvokeMessageBox,NULL,offset szmstext2,offset szmscap,MB_ICONERROR@@:mov@Desktopdc,eaxinvokelstrlen,lpsztextmovebx,eaxinvokeSetBkMode,@Desktopdc,TRANSPARENTinvokeSetTextColor,@Desktopdc,@dwcolorinvokeTextOut,@Desktopdc,300,300,lpsztext,ebxinvokeMessageBox,NULL,offset szmssucesstext,offsetszmssucesscap,MB_ICONINFORMATIONcmpeax,0jne @finvokeMessageBox,NULL,offset szmstext1,offset szmscap,MB_ICONERROR@@:popadret _showtext endp ;#########################################################################end start

以上程序中有幾個重要的GDI相關的API,下面簡要介紹一下

(1)

invoke SetBkMode,@Desktopdc,TRANSPARENT

設置背景方式為透明

(2)

invoke SetTextColor,@Desktopdc,@dwcolor

設置字體顏色為藍色

(3)

invoke TextOut,@Desktopdc,300,300,lpsztext,ebx

在300,300處顯示文本

(4)

invoke GetWindowDC,NULL

取得桌面DC

(5)

mov @dwcolor,00FF0000h

設置顏色為藍色。@dwcolor是一個DWORD型的變量,

可以在相關頭文件中找到這樣的定義:

typedef DWORD COLORREF;
因此COLORREF類型的變量就是DWORD型變量。

COLORREF變量如何表示顏色呢,只有一個雙字大小,它的表示格式是(16進制):

0x00bbggrr

bb表示藍色,gg表示綠色,rr表示紅色

00FF0000h:藍

0000ff00h:綠

000000FFh:紅

程序運行效果如下:

因此,在此只簡單介紹一下,首先來看一段簡單的窗口程序。注意";"表示注釋

;加上注釋和個人理解

.386
.model flat,stdcall
option casemap:none

;以下定義INCLUDE文件
include winows.inc
include gdi32.inc
includelib gdi32.lib
include user32.inc
includelib user32.lib
include kernel32.inc
include kernel32.lib
;以下定義數據段
.data ? ;定義變量
hinstance dd ?
hwinmain dd ?
.const ;定義常量,字符串全部要以0結尾,因為在內存中0是字符串的結束符
szclassname db ‘billclass’,0
szcaptionmain db ‘bill’s firt program’,0
sztext db ‘WIN32匯編,BILL!!!!’,0
;以下是代碼段
.code
;定義窗口過程
_procwinmain proc uses ebx edi esi,hwnd,umsg,wparam,lparam
;定義局部變量用關鍵字local
local @stps:PAINTSTRUCT
local @strect:PAINTSTRUCT
local @hdc
mov eax,umsg ;取得傳入過程的消息變量值
;-----------下面開始根據消息類型的不同作出不同的處理
.if eax == WM_PAINT ;如果消息是窗口繪制
invoke BeginPaint,hwnd,addr@stRect;WIN32匯編調用API程序后,API程序將返回值放在EAX中,
;客戶區準備
mov @hdc,eax;取得設備句柄

invoke GetclientRect,hwnd,addr @stRect;addr是取變量的地址但只能用在INVOKE語句中且
;不能同時使用
;EAX寄存器傳參數,因為ADDR會用到EAX。
;此API的含義是取得描述客戶區的結構放在@stRect
invoke drawText,@hdc,addr sztext,-1,addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER ;語句換行符是\,顯示’WIN32匯編,BIL
;L!!!!’,并設置其為單行DT_SINGLE
;等等LINE
invoke EndPaint,hwnd,addr @stPs
.elseifmeax==WM_CLOSE
invoke DestroyWindow,hwinmain ;銷毀窗口
invoke PostQuitMessage,Null ;向消息循環中發出退出消息
.else
invoke DefWindowProc,hwnd,uMsg,wPara,lParam;如果不是上述消息,則執行WINDOWS標準的默認消息處
;理,如鍵盤等消息
ret;返回
.endif

xor eax,eax ;eax清0
ret
_ProcWinMain endp
;以上這個子程序處理窗口消息的,是窗口的回調函數,該項函數不是我們調用,是由WINDOWS調用用來處理
;窗口消息的,我們調用的是DispatchMessage,DispatchMessage再回過頭來調用窗口過程。
_WinMain Proc ;主程序
local @stWndClass:WNDCLASSEX
local @stmsg:MSG

invoke GetModuleHandle,Null ;得到應用程序句柄
mov hInstance,eax ;將應用程序的句柄放入hInstance變量
invoke RtlZeroMemory,addr @stWndClass,sizeof WndClassEX ;msdn的解釋TheRtlZeroMemory routine
;fills a block of memory with zeros,即
;0填充stWndClass結構變量所占的內存,也就是初始化
;-----下面注冊窗口類
invoke loadcursor,0,IDC_ARROW ;加載箭頭形指針句柄
mov @stWndClass.hCursor,eax ;鼠標指針賦值
push hInstance
pop @stWndClass.hInstance ;窗口句柄賦值
mov @stWndClass.cbsize,sizeof WNDCLASSEX ;結構大小
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW ;設置窗口樣式
mov @stWndClass.lpfnwndproc,offset _procwinmain;設置回調函數,也就是窗口消息處理過程
mov @stwndclass.hbrbackground,COLOR_WINDOW+1
mov @stwndclass.lpszclassname,offset szclassname ;設置窗口類的名稱
invoke RegisterClassEx,addr @stwndclass ;傳上述設置好的結構以注冊窗口類
;建立顯示窗口
invoke CreateWindowEx,WS_EX_CLIENTEDGE,\
offset szclassname,offsetszcaptionmain,\
WS_OVERLAPPEDWINDOW,100,100,600,400,NULL,\
NULL,hinstance,NULL ;建立窗口并返回句柄在EAX中
mov hwinMain,eax ;剛創建的窗口句柄賦值
invoke showwindow,hwinmain,SW_SHOWNORMAL ;顯示窗口
invoke updatewindow,hwinmain ;刷新窗口客戶區,導致客戶區窗口paint
;消息循環,win32匯編得自行建立WINDOWS消息循環,不過這樣更自由,可以徹底地控制程序
.while true
 invoke GetMessage,addr @stMsg,null,0,0 ;WINDOWS在系統內部有個系統消息隊列,
            ;并為每個應用程序還維護了一個消息隊列,將這些屬于這些程序窗口范圍內的
            ;系統消息發到該應用程序消息隊伍中,這個API的作用就是從自己的應用程序
            ;消息隊伍中接收消息。
  .break .if eax==0 ;If the function retrieves the WM_QUIT message, the return value is zero.
            ;invoke Translate(msdn),也就是說,當程序退出里,消息隊伍里會有WM_QUIT消息,            ;就退出循環,意味著退出程序。
  invoke translatemessage,addr @stmsg;由應用程序對消息進行預處理,如把基于鍵盤掃描碼的按鍵消息黑心                   ;換成ASCII碼的鍵盤消息等
  invoke dispatchmessage,addr@stmsg ;將預處理好的消息發給WINDOWS,WINDOWS將其分派給該程序的相應窗;口處理過程處理,那么WINDOWS怎么知道窗口處理過程在哪呢,剛才不是已經注冊過窗口類了,這就是為什么窗口;類要注冊的原因了,那么為什么不能由程序自己處理消息,非得發給WINDOWS呢,其一、一個應有程序的窗口很多,如果自己處理的話,得建立一個窗口列表,上面記錄每個窗口的窗口處理過程。其二、WINDOWS對于一些實時性很;強的信息采用直接調用窗口處理過程的方法。
.endw
ret
_winmain endp
;沒有下面的代碼程序無法執行,因為START語句指定程序啟動的入口點
start:
call _winmain
invoke ExitProcess,NULL;退出
end start
可以看到上面代碼和用C編寫的WIN SDK程序很相似。我們接著繼續看2個例子:

例1:用WIN32匯編構建第一個WINODWS程序,這個程序完成顯示一個帶問號的對話框,對話框的內容是現在系統時間。

首先,打開MASM32Editor(在桌面上可以找到圖標),在里面輸入以下代碼:

.386 .model flat, stdcall option casemap :none ;################################################################# include windows.inc include user32.inc include kernel32.inc include gdi32.inc include masm32.inc includelib user32.lib includelib kernel32.lib includelib gdi32.lib includelib masm32.lib ;################################################################# .data? szbuffer db 100 dup(?) .data szcaptionName db "我的HELLO,WORLD!",0 szbegin db "現在時間:" sztext db 100 dup(?) ;################################################################# .code start: ;程序的入口 call _callgetnow invoke MessageBox,NULL,offset szbegin,offsetszcaptionName,MB_ICONQUESTION or MB_OK invoke ExitProcess,eax ;################################################################# _callgetnow proc pushad invokeGetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,NULL,NULL,addrsztext,100 invokeGetTimeFormat,LOCALE_USER_DEFAULT,LOCALE_NOUSEROVERRIDE,NULL,NULL,addrszbuffer,100 invokeszCatStr,addr sztext,addr szbuffer popad ret _callgetnow endp ;################################################################# end start

將上述代碼保存為HELLOWORLD.ASM后,對程序進行編譯。

在編譯前參照下圖設置好系統的環境變量,path變量加上x:\masm32\bin,lib變量加上x:\masm32\lib,include變量加上x:\masm32\include。

確環境變量設置好后,進入DOS窗口開始編譯。

首先運行ml,編譯成coff文件格式

然后運行LINK,進行鏈接,生成EXE文件,

大功造成,運行一下試試效果吧!

例2:系統時間直接顯示在桌面上。程序源代碼如下:

Asm代碼

.386
.model flat, stdcall
option casemap :none
;#########################################################################
include windows.inc
include user32.inc
include kernel32.inc
include gdi32.inc
include masm32.inc

includelib user32.lib includelib kernel32.lib includelib gdi32.lib includelib masm32.lib

;#########################################################################
.data?
szbuffer db 100 dup(?)
.data
szmssucesscap db “HELLO,WORLD!深入”,0
szmssucesstext db “在桌面的(300,300)處顯示了當前時間”,0
szmscap db “錯誤”,0
szmstext1 db “無法在桌面上顯示!”,0
szmstext2 db “無法得到全屏DC!”,0
szbegin db “現在時間:”
sztext db 100 dup(?)
;#########################################################################
.code
start:
;程序的入口
_showtext proto :DWORD
call _callgetnow
invoke _showtext,offset szbegin
invoke ExitProcess,eax
;#########################################################################
_callgetnow proc
pushad
invokeGetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,NULL,NULL,addrsztext,100
invokeGetTimeFormat,LOCALE_USER_DEFAULT,LOCALE_NOUSEROVERRIDE,NULL,NULL,addrszbuffer,100

invokeszCatStr,addr sztext,addr szbuffer popad ret

_callgetnow endp
;#########################################################################
_showtext proc lpsztext:DWORD
LOCAL@Desktopdc:HDC
LOCAL@dwcolor:DWORD

pushad mov@dwcolor,00FF0000h invokeGetWindowDC,NULL cmpeax,0 jne @f invokeMessageBox,NULL,offset szmstext2,offset szmscap,MB_ICONERROR @@: mov@Desktopdc,eax invokelstrlen,lpsztext movebx,eax invokeSetBkMode,@Desktopdc,TRANSPARENT invokeSetTextColor,@Desktopdc,@dwcolor invokeTextOut,@Desktopdc,300,300,lpsztext,ebx invokeMessageBox,NULL,offset szmssucesstext,offsetszmssucesscap,MB_ICONINFORMATION cmpeax,0 jne @f invokeMessageBox,NULL,offset szmstext1,offset szmscap,MB_ICONERROR @@: popad ret

_showtext endp
;#########################################################################
end start

以上程序中有幾個重要的GDI相關的API,下面簡要介紹一下

(1)

invoke SetBkMode,@Desktopdc,TRANSPARENT

設置背景方式為透明

(2)

invoke SetTextColor,@Desktopdc,@dwcolor

設置字體顏色為藍色

(3)

invoke TextOut,@Desktopdc,300,300,lpsztext,ebx

在300,300處顯示文本

(4)

invoke GetWindowDC,NULL

取得桌面DC

(5)

mov @dwcolor,00FF0000h

設置顏色為藍色。@dwcolor是一個DWORD型的變量,

可以在相關頭文件中找到這樣的定義:

typedef DWORD COLORREF;
因此COLORREF類型的變量就是DWORD型變量。

COLORREF變量如何表示顏色呢,只有一個雙字大小,它的表示格式是(16進制):

0x00bbggrr

bb表示藍色,gg表示綠色,rr表示紅色

00FF0000h:藍

0000ff00h:綠

000000FFh:紅

.NET堆棧原理

1、用調試器調試線程

1)棧調用

以下面代碼為例

Imports System.Threading

Public Class Form1

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click Dim main_x As Integer main_x = 5 Call sub1(main_x) End Sub Private Sub sub1(sub1_x As Integer) Dim jg As Integer jg = sub1_x sub1_x Call sub2(jg) End Sub Private Sub sub2(sub2_x As Integer) Dim jg As Integer jg = sub2_x 2 '在下一句設置斷點 jg = jg * jg End Sub

End Class

我們首先來看調用堆棧,在調試菜單中選擇調用堆棧,可看到過程的調用順序:

然后查看線程

最后查看局部變量

此外,我們還可以研究一下這個線程的調用時堆棧情況,通過反匯編代碼,在調用堆棧窗口中選擇“轉到反匯編”

Private Sub sub2(sub2_x As Integer)
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,14h
00000006 mov dword ptr [ebp-10h],ecx
00000009 mov dword ptr [ebp-4],edx
0000000c cmp dword ptr ds:[0256B1B8h],0
00000013 je 0000001A
00000015 call 62A16743
0000001a xor edx,edx
0000001c mov dword ptr [ebp-8],edx
0000001f mov eax,dword ptr [ebp-10h]
00000022 mov dword ptr [ebp-14h],eax
00000025 mov ecx,dword ptr [ebp-10h]
00000028 call 628F5C25
0000002d mov dword ptr [ebp-0Ch],eax
00000030 push 32h
00000032 mov edx,dword ptr [ebp-0Ch]
00000035 mov ecx,dword ptr [ebp-14h]
00000038 call FFDF30D0
0000003d mov ecx,dword ptr [ebp-4]
00000040 call FFFFFF70
00000045 mov ecx,63h
0000004a call FFDF2940
0000004f nop
Dim jg As Integer
jg = sub2_x 2
00000050 mov eax,dword ptr [ebp-4]
00000053 mov edx,2
00000058 imul eax,eax,2
0000005b jno 00000062
0000005d call 62A19A30
00000062 mov dword ptr [ebp-8],eax
'在下一句設置斷點
jg = jg jg
00000065 mov eax,dword ptr [ebp-8]
00000068 imul eax,dword ptr [ebp-8]
0000006c jno 00000073
0000006e call 62A19A30
00000073 mov dword ptr [ebp-8],eax

End Sub

00000076 nop
00000077 nop
00000078 mov ecx,63h
0000007d call FFDF2A60
00000082 nop
00000083 mov esp,ebp
00000085 pop ebp
00000086 ret

ESP是棧頂指針

ebp是基址指針

±----+

+基址 +

±----+

+棧內容+

+棧內容+

+棧內容+

+棧內容+

+棧內容+

+棧頂 +

如上圖所示,基地的地址比棧頂的地址大,就是向下增長。

寄存器ebp和esp保存著當前的基址和棧頂地址

首先,進入函數時

00000000 push ebp
備份基址指針

00000001 mov ebp,esp

然后設置基址指針指向棧頂,相當于為當前棧清空了內容,做好在棧中分配局部變量的準備
00000003 sub esp,14h

完成棧(可以理解為本函數可訪問的棧)的空間分配,將棧頂指針向下增長14h(向下增長的意思是棧的空間增長規律是地址遞減)。相當于棧中已經容納了14h的空間

Dim jg As Integerjg = sub2_x 2

00000050 mov eax,dword ptr [ebp-4]
00000053 mov edx,2
00000058 imul eax,eax,2
0000005b jno 00000062
0000005d call 617391D0
00000062 mov dword ptr [ebp-8],eax
'在下一句設置斷點
jg = jg jg
00000065 mov eax,dword ptr [ebp-8]
00000068 imul eax,dword ptr [ebp-8]
0000006c jno 00000073
0000006e call 617391D0
00000073 mov dword ptr [ebp-8],eax

從上面這段代碼可以看出來

sub2_x分配在了dword ptr [ebp-4] ,而jg分配在了dword ptr [ebp-8]

最后,離開函數時,恢復進入函數前棧的指針,相當于釋放了本次在棧中分配的空間

End Sub

00000083 mov esp,ebp
恢復棧頂指針

00000085 pop ebp

恢復基址指針

00000086 ret

2、修改默認棧的大小

Dim 線程變量名 As Thread = New Thread(函數名,以字節為單位的棧大小)

比如

Dim mythread As Thread = New Thread(myfun,1024*512)

分配了512kb字節

總結

以上是生活随笔為你收集整理的C指针原理(23)-win32汇编及.NET调试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。