自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

來看三段程序,你學(xué)會了什么?

開發(fā) 前端
debug 對我們來說非常重要,有很多代碼細(xì)節(jié)和問題通過肉眼是觀察出來的,我們?nèi)庋劭赡苣軌蚺袛嘁恍┖唵蔚某绦騿栴},但是對于很多隱藏較深的問題,還是要依據(jù) debug 才能發(fā)現(xiàn)。

學(xué)習(xí)任何一門語言都不能少的了 debug ,匯編也是。

debug 程序執(zhí)行過程

下面我們就依據(jù)這幾個功能來跟蹤一下程序的執(zhí)行過程。

debug 對我們來說非常重要,有很多代碼細(xì)節(jié)和問題通過肉眼是觀察出來的,我們?nèi)庋劭赡苣軌蚺袛嘁恍┖唵蔚某绦騿栴},但是對于很多隱藏較深的問題,還是要依據(jù) debug 才能發(fā)現(xiàn)。

下面是一段匯編代碼,這段匯編代碼我之前的文章中也給大家寫過。

assume cs:codesg
codesg segment

mov ax,0123h
mov bx,0456h
add ax,bx
add ax,ax

mov ax,4c00h
int 21h

codesg ends
end

新建文本文件,把代碼 cv 過去,然后右鍵保存,使用 dosbox 將其編譯為 1.obj 文件,鏈接為 1.exe 文件后,我們使用 ??debug 1.exe?? 命令來分析一下這段程序,并用 -r 命令來看一下初始的寄存器情況。

圖片

程序初始狀態(tài)下,可以看到 CX 中的數(shù)據(jù)為 000F,這也表示著程序的長度是 000F,1.exe 中共有 15 個字節(jié),CX 中的內(nèi)容為 000FH。

好,現(xiàn)在我們已經(jīng)知道程序被成功的載入內(nèi)存并運(yùn)行起來了,但是我們現(xiàn)在先不妨想一下,被鏈接成為 EXE 的程序會被裝入內(nèi)存的哪個地方的呢?我們怎么知道程序被裝入在哪里呢?

程序裝載的過程分下面幾步:

  1. 首先程序會從內(nèi)存中找到一塊區(qū)域,記為初始地址 SA,此時的偏移地址為 0 的這樣一塊足夠容量的內(nèi)存區(qū)域。

圖片

  1. 在這段區(qū)域內(nèi)的頭 256 個字節(jié)中,會創(chuàng)建一塊稱為程序段前綴(Program Segment Prefix ,PSP)的區(qū)域,這塊區(qū)域被 DOS 用來和被加載的程序進(jìn)行通信。

圖片

  1. 從這塊程序的 256 個字節(jié)開始處,也就是在 PSP 程序段前綴的后面,程序會被加載到這里,此時程序的初始地址是 SA + 10H,偏移地址為 0 。也就是 SA + 10H : 0,所以程序的初始地址就是 CS = 076AH ,IP = 0000H。

圖片

程序被裝入內(nèi)存后,由 DS 段寄存器存放著內(nèi)存區(qū)的段地址,此時內(nèi)存區(qū)域的偏移量為 0 ,所以此時的物理地址為 SA * 16:0,我們并不用知道真實的 DS 是多少,反正都是由操作系統(tǒng)和 DOS 分配的。

然后這個內(nèi)存區(qū)域的前 256 個字節(jié)被用于存放 PSP ,所以程序的物理地址為 SA * 16 + 256 : 0 。

SA * 16 + 256 = SA * 16 + 16 * 16 = (SA  + 16) * 16 ,轉(zhuǎn)換為 16 進(jìn)制就是 SA + 10H,所以物理地址就是 SA + 10H : 0。

我們上面 debug 1.exe 之后可以看到,DS 段寄存器的值為 076AH ,而 CS 段寄存器的值為 076BH ,正好符合 076A * 16 + 10 = 076BH (注意這里的 * 16 就是左移 4 位的意思,之前文章中也解釋過原因。)

我們使用 -u 指令可以看到完整的匯編源代碼。

圖片

上圖中用紅框圈出來的就是我們這段匯編程序的源代碼,可以看到這是一個程序段,程序段的段地址始終為 076A,偏移地址在不斷變化。

我們使用 -t 命令來單步執(zhí)行以下這段程序,如下圖所示。

圖片

(為了連續(xù)的觀察一下程序的執(zhí)行結(jié)果,我索性直接把主要的程序步驟執(zhí)行完了。)

這段程序就是 mov 和 add 的基本使用,將 0123 送入 AX 寄存器,將 0456 送入 BX 寄存器,對 AX 寄存器執(zhí)行 AX = AX + BX ,再對 AX 執(zhí)行 AX = AX + AX。

程序繼續(xù)向下執(zhí)行,當(dāng)執(zhí)行到 int 21H 處,程序執(zhí)行完畢,此時要使用 -p 命令結(jié)束程序的執(zhí)行,如下圖所示。

圖片

當(dāng)顯示 Program terminated normally 時,表示程序正常結(jié)束,這里大家先不用考慮為什么執(zhí)行到 int 21 處才執(zhí)行 -p 命令,也不用關(guān)心 mov ax,4c00 和 int 21 是什么意思,大家先記住就行。

由于程序裝載的過程是 command 將程序裝載進(jìn)入內(nèi)存,然后 debug 程序?qū)?exe 程序其進(jìn)行跟蹤,所以程序退出后也是先從 exe 程序退出到 debug 程序中,由 debug 程序再退回到 command 程序中。

下面再分析一段程序,匯編原代碼

assume cs:codesg

codesg segment

mov ax,2000H
mov ss,ax
mov sp,0
add sp,10
pop ax
pop bx
push ax
push bx
pop ax
pop bx

mov ax,4c00H
int 21H

codesg ends

end

仍然是將其保存為 test.txt,然后執(zhí)行編譯和鏈接操作,將其生成可執(zhí)行文件 test.exe,觀察其執(zhí)行過程。

我們先使用 -r 查看一下初始寄存器的內(nèi)容。

圖片

主要觀察一下 CX 、DS 、CS 和 IP 的值,是否和我們上面描述的一致,CX 存放程序長度,DS 存放程序段地址,CS 存放程序初始地址,IP 存放程序偏移地址。

再使用 -u 看一下 exe 程序的源代碼,這個 exe 程序是經(jīng)過編譯和鏈接之后的程序。

圖片

我們來分析一下這段,這是一段棧段的入棧和出棧的程序,首先

mov ax,2000H
mov ss,ax
mov sp,0

是設(shè)置棧段的棧頂指令,執(zhí)行完成后會設(shè)置棧頂?shù)奈锢淼刂窞?20000 H ,即 SS:SP = 2000:0000。

圖片

我們執(zhí)行這個程序的過程中,發(fā)現(xiàn) mov sp,0 這個指令為什么沒有出現(xiàn)呢?難道是我們漏寫了?查看了一下,源代碼確實是有這條指令的,難道是沒有執(zhí)行?

為了驗證這個假設(shè),我們重新 debug 一下這段程序,然后先把 SP 的值進(jìn)行修改,如下圖所示。

圖片

剛開始,我們使用 -r 把 sp 的值改成 0002,然后單步執(zhí)行,在執(zhí)行到 mov ss,ax 之后,發(fā)現(xiàn) SP 的值變?yōu)?0000,這也就是說 mov sp,0 這條指令其實是執(zhí)行了的,只是 debug 模式下沒有顯示而已。

程序繼續(xù)向下執(zhí)行,下面是兩個 pop 出棧操作。

圖片

pop ax 和 pop bx 做了兩件事:把寄存器清空;棧頂位置 + 2 ,所以 ax 和 bx 寄存器的內(nèi)容為 0 ,并且 SP = SP + 2 ,執(zhí)行后 SP = 000E。

之后是兩個 push 操作,把出棧的兩個寄存器再進(jìn)行入棧,如下圖所示。

圖片

push 操作也做了兩件事情,將寄存器入棧,SP = SP - 2,由于 ax 和 bx 已經(jīng) pop 出棧了,所以寄存器內(nèi)容為 0 ,最后再進(jìn)行 pop 操作,然后再結(jié)束程序的執(zhí)行過程。

圖片

我們再來看一下 PSP 的情況,由于程序被裝入的時候前 256 個字節(jié)是 PSP 所占用的,此時 DS(SA)處就是 PSP 的起始地址,而 CS = SA + 10H ,也就是 CS = 076AH。

debug 循環(huán)程序

下面我們來 debug 一下循環(huán)程序,看看有哪些有意思的細(xì)節(jié)。

現(xiàn)在有這樣一道問題,計算 ffff:0006 單元中的數(shù)乘 3 ,讓結(jié)果存儲在 dx 中。

針對這個問題,有幾個點需要思考:

  • 我們知道 ,8086 匯編語言中單個存儲單元所能存儲的最大值是 8 位,一個字節(jié)長度,范圍是 0 - 255 之間,而一個寄存器 dx 中可容納的最大值是 16 位,兩個字節(jié)長度,范圍是 0 - 65535,即使 255 * 3 也小于 65535,很顯然乘以 3 之后,dx 中能夠存放的下。
  • 數(shù)乘 3 相當(dāng)于是循環(huán)做 add 自身操作 3 次,所以需要用加法來實現(xiàn)乘法,可以直接使用 dx 進(jìn)行累加,不過需要一個 ax 來進(jìn)行中轉(zhuǎn)。
  • ffff:6 內(nèi)存單元是一個字節(jié)單元,而 ax 寄存器能容納的是一個字單元,無法直接賦值,該如何做呢?因為 ax 可以看做 al 和 ah ,而 al 和 ah 又是兩個單獨(dú)的寄存器,它們之間不會發(fā)生值溢出,所以讓 ah = 0 ,al = 內(nèi)存單元的值即可。

所以這段匯編程序的代碼如下

assume cs:codesg

codesg segment

mov ax,0ffffh
mov ds,ax

mov ah,0
mov al,[6]

mov cx,3
s: add dx,ax
loop s

mov ax,4c00h
int 21h

codesg ends
end

編寫完畢,編譯鏈接成 exe 程序后,對其進(jìn)行 debug xxx.exe 操作。

我們來看下程序的執(zhí)行過程。

圖片

前兩段沒毛病,設(shè)置 DS 段寄存器的值為 FFFF 。然后繼續(xù)向下執(zhí)行

圖片

執(zhí)行到 mov al,[6] 的時候我發(fā)現(xiàn),怎么 AX 寄存器中的內(nèi)容變成 0006 了?我不是想要把 06 放入 ax 中啊,我是想把 ffff:06 內(nèi)存單元中的值放入 ax 中啊,我突然意識到編譯器是個傻子。

經(jīng)過我認(rèn)真仔細(xì)細(xì)心耐心用心的排查了一番問題之后,我方才大悟,原來我是個傻子!不知道各位小伙伴們看出來我代碼的問題了嗎?

我怎么敢在源程序中把立即數(shù)當(dāng)做內(nèi)存偏移地址來用呢?必須要用 bx 中轉(zhuǎn)啊!

這也就是說,編譯器編譯完源代碼之后,會把 06 當(dāng)做立即數(shù)使用,如果想要使 06 表示內(nèi)存地址,必須要用 bx 進(jìn)行中轉(zhuǎn),修改之后的源代碼如下:

assume cs:codesg

codesg segment

mov ax,0ffffh
mov ds,ax
mov bx,6

mov ah,0
mov al,[bx] # 必須要用 bx 進(jìn)行中轉(zhuǎn),才能表示內(nèi)存地址
mov dx,0 # 累加寄存器清 0

mov cx,3
s: add dx,ax
loop s

mov ax,4c00h
int 21h

codesg ends
end

然后再重新鏈接成為 exe 程序之后,我們一步一步 debug 看一下。

圖片

執(zhí)行到 mov al,[bx] 的時候,我們發(fā)現(xiàn),此時右側(cè)有個 ds:0006 = 31,這段代碼表示的是 ds:0006 處內(nèi)存單元的值是 31,這才表明我們的程序是正確的。

繼續(xù)向下執(zhí)行程序。

圖片

前兩條指令執(zhí)行完成后,(dx) = 0 ,(cx) = 3,完成對累加寄存器的清空和循環(huán)計數(shù)器的賦值操作。最后一條指令是第一次循環(huán)操作指令,此時 CS:IP 指向 076A:0012 ,繼續(xù)向下執(zhí)行。

圖片

可以看到,第一次 add dx,ax 執(zhí)行完成后 IP = 0014H ,此時指向的指令是 LOOP 0012,這條指令的意思是讓程序再執(zhí)行一次 (IP) = 0012H 處的指令,也就是再執(zhí)行一次 add dx,ax,可以看到 cx 的值變成了 0002,因為循環(huán)指令執(zhí)行后 (cx) = (cx) - 2 ,然后再向下執(zhí)行,發(fā)現(xiàn)后面的循環(huán)指令還是 LOOP 0012 ,再執(zhí)行一次 add dx,ax,一直到 (cx) = 0 后結(jié)束程序執(zhí)行,如下圖所示

圖片

可以發(fā)現(xiàn),整個程序一共循環(huán)三次,最終 dx 中的值是 93 ,程序執(zhí)行到 int 21H 處,使用 -p 命令結(jié)束程序的執(zhí)行。

責(zé)任編輯:武曉燕 來源: 程序員cxuan
相關(guān)推薦

2023-07-26 13:14:13

業(yè)務(wù)項目技術(shù)

2023-05-19 07:31:48

2023-06-28 11:01:08

2024-07-22 09:52:42

2024-07-12 09:21:38

負(fù)載均衡HTTP網(wǎng)絡(luò)

2023-12-11 08:03:01

Java線程線程組

2022-11-18 12:03:01

2023-01-10 08:43:15

定義DDD架構(gòu)

2024-02-04 00:00:00

Effect數(shù)據(jù)組件

2023-07-26 13:11:21

ChatGPT平臺工具

2024-01-19 08:25:38

死鎖Java通信

2024-01-02 12:05:26

Java并發(fā)編程

2023-08-01 12:51:18

WebGPT機(jī)器學(xué)習(xí)模型

2019-06-19 08:09:05

CSSJavaScript前端

2023-04-26 07:46:21

2023-02-15 08:41:56

多層維表性能寬表

2025-01-16 00:17:44

2024-04-29 06:55:34

RustMIDI應(yīng)用程序

2024-01-26 06:05:16

KuberneteseBPF網(wǎng)絡(luò)

2024-05-06 00:00:00

InnoDBView隔離
點贊
收藏

51CTO技術(shù)棧公眾號