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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Intel汇编语言程序设计学习-第三章 汇编语言基础-下

發布時間:2025/6/17 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Intel汇编语言程序设计学习-第三章 汇编语言基础-下 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

3.4 ?定義數據

3.4.1 ?內部數據類型

? ? MASM定義了多種內部數據類型,每種數據類型都描述了該模型的變量和表達式的取值集合。數據類型的基本特征是以數據位的數目量的大小:8,16,32,,48,64,80位。其他特征(如有符號、指針、浮點等)主要是為了方便程序員記憶變量中存儲的數據的類型。例如,聲明為DOWRD變量邏輯上存儲的是一個32位整數、一個32位的浮點數或一個32位的指針。MASM匯編器默認情況下是大小寫不敏感的,因此偽指令如DWORD可寫成dword,Dword.dWord等大小寫混合的格式。

下表中,除了最后三種之外,其余的所有的數據類型都是整數數據類型。表中IEEE符號是指IEEE委員會發布的標準實數格式。

?

3.4.2 ?數據定義語句

? ? ? 在數據定義語句中使用BYTE(定義字節)和SBYTE(定義有符號字節)偽指令,可以為一個或多個有符號及無符號字節分配存儲空間,每個初始值必須是8位整數表達式或者字符常量。例如:

? ? value1 ?BYTE ??‘A’????;字符常量

? ? value2 ?BYTE ???0 ???;最小無符號字節常量

? ? value3 ?BYTE ??255 ??;最大無符號字節常量

? ? value4 ?SBYTE ?-128 ??;最小有符號字節常量

? ? value5 ?SBYTE ?+127 ?;最大有符號字節常量

? ? 使用問號代替初始值可以定義未初始化的變量,這表示將由可執行指令在運行時為變量動態賦值:

value6 BYTE ?

? ? 可選的變量名是一個標號,標記該變量相對其所在段開始的偏移。例如,假設value1位于數據段的偏移0000出并占用1個字節的存儲空間,那么value2將位于段內偏移值0001的地方:

value1 BYTE 10h

value2 BYTE 20h

遺留的DB偽指令可以定義有符號或無符號的8位的變量:

val1 DB ?255 ??;無符號字節

val2 DB ?-128 ??;有符號字節

多個初始值

如果一條數據定義語句中有多個初始值,那么標號(名字)僅僅代表第一個初始值的偏移。在下列中,假設list位于偏移0000處,那么值10將位于0000處值20位于0001處,一次類推。

list BYTE 10,20,30,40

下圖以字節序列的形式顯示了list的定義情況:

?

并非所有的數據定義都需要標號(名字),如果想繼續以list開始的字節數組,就可以在隨后的行上接著定義其他數據:

list BYTE 10,20,30,40

?????BYTE 50,60,70,80

?????BYTE 81,82,83,84

????在單條數據定義語句中,初始值可使用不同的基數,字符和字符串課可以自由混用。在下面例子中,list1list2的內容是相同的。


list1 BYTE 10 ,32 ,41h ,00100010b

list2 BYTE 0Ah,20h,’A’?,22h

定義字符串

要想定義字符串,應將一組字符用單引號或雙引號括起來。最常見的字符串是以空字符(也稱為NULL,0)結尾的字符串,C/C++,Java程序使用這種類型的字符串:

????greeting1 BYTE "Good afternoon",0

????greeting2 BYTE 'Good night',0

每個字節都占用一個字節,對于前面提到過的數據定義中多個初始值必須以逗號分隔的規則,字符串是一個例外。如果沒有這種例外,就不得不這樣定義greeting1:

greeting1 BYTE ‘G’,’o’,’o’....etc.

這樣太冗長乏味了!

字符串可以占用多行,而無需為每一行都提供一個標號,如下例所示:

?

????十六進制字節0Dh0Ah也稱為CR/LF(回車換行符)或航結束字符,在向標準輸出設備上寫的時候,回車換行將光標移至下面一行左右開始處。

續行符(\)用來把兩行連接陳過一條程序語句,續行符只能放在每行的最后,下面的語句是等價的:

???greeting1 BYTE "Good afternoon",0

???greeting1 BYTE \

"Good afternoon",0

DUP操作符

DUP操作符使用一個常量表達式作為計數器為多個數據項分配存儲空間。在為字符串和數組分配空間的時候,DUP偽指令就十分有用。初始化和未初始化數據均可使用DPU偽代碼定義:

BYTE 20 DUP(0) ??????;20字節,全部等于0

BYTE 20 DUP(?) ??????;20字節,未初始化

BYTE 4 ?DUP("STACK") ;20字節:"STACKSTACKSTACK"

3.4.4 ??定義WORDSWORD數據

???BYTE一樣,這里就簡單寫幾個例子。

???word1 WORD 65535

???word2 SWORD -32768

???word2 WORD ?

???val1 DW 65535

???val2 DW -32768

???myList WORD 1,2,3,4,5


3.4.5 ?定義DWORDSDWORD數據

BYTE一樣,直接上例子

val1 DWORD ???13245678h

val2 SDWORD ??-2147483684

val3 DWORD ???20 DUP(?)

val1 DD ???????12345678h

val2 DD ???????-2147483648

myList DWORD ?1,2,3,4,5


3.4.6 ?定義QWORD數據

quad1 ?QWORD 1234567812345678h

quad1 ?DQ ????1234567812345678h

3.4.7 ?定義TBYTE數據

val1 TBYTE ?100000000000000123456789Ah

val1 DT ????100000000000000123456789Ah


3.4.8 ?定義實數

REAL4定義4字節的單精度實數,REAL8定義8字節的雙精度實數,REAL10定義10字節的擴展精度實數。每個偽指令都要求一個或多個與其對應的數據尺寸相匹配的實數常量初始值,例如:

rVal1 ???????REAL4 ??-2.1

rVal2 ???????REAL8 ??3.2E-260

rVal3 ???????REAL10 ?4.6E+4096

ShortArray ??REAL4 ??20 DUP(0.0)

下表列出了每種實數類型的最少有小數據位和最大有效數據位

?

遺留的DD,DQDT偽指令也可以用于定義實數:

rVal1 ??DD ??-1.2

rVal2 ??DQ ??3.2E-260

rVal3 ??DT ??4.6E+4096

3.4.9 ?小尾順序

Intel處理器使用稱為小尾順序(little endian order)的方案存取內存數據,小尾的含義就是變量的最低有效字節存儲在地址值最小的地址單元中,其余字節在內存中按順序連續存儲。

考慮一下雙字節12345678h在內存中的存儲情況,如果將該雙字存儲在偏移0處,78h將存儲在第一個字節中,56h存儲在第二個字節中,其余存儲在第三和第四字節。如下圖:

?

大尾則相反:


3.4.10 ?AddSub程序添加變量

現在寫一個AddSub2,在里面添加一些變量:

TITLE Add and Subtract ,Version 2 (AddSub2.asm)

;This program adds and subtracts 32-bit unsigned

;integers and stores the sum in a variable

INCLUDE Irvine32.inc

.data

val1 DWORD 10000h

val2 DWORD 40000h

val3 DWORD 20000h

finalVal DWORD ?

.code

main PROC

mov ?eax,val1 ???;start whith 10000h

add ?eax,val2 ???;add 40000h

sub ?eax,val3 ???;subtract 20000h

mov ?finalVal,eax;store the result (30000h)

call DumpRegs ???;display the registers

exit

main ENDP

END main

這個新的程序是如何工作的呢?首先,變量val1里的整數倍送到EAX寄存器:

mov eax,val1 ????;start with 10000h

接下來,變量val2存儲的整數值被加到EAX寄存器中:

add eax,val2 ????;add 40000h

再接下來,EAX寄存器內的整數值減掉變量val3內的整數值:

sub eax,val3 ????;subtract 20000h

最后,EAX寄存器內的整數被復制到變量finalVal內:

Mov finalVal,eax ;store the result(30000h)


3.4.11 ?未初始化數據的聲明

“.DATA?”偽指令可用于聲明未初始化數據,”.DATA?”在定義大塊的未初始化數據時非常有用,因為它可以減少編譯后的程序的尺寸,下面的聲明是很有效率的:

.data

smallArray DWORD 10 DUP(0) ??;40字節

.data?

bigArray ??DWORD 5000 DUP(?) ;20000字節,未初始化

相反,下面的代碼例子編譯后將生成大于20000字節的程序:

.data

smallArray DWORD 10 DUP(0) ??;40字節

bigArray ??DWORD 5000 DUP(?) ;20000字節,未初始化

?

我自己做了個測試,發現果真有效果,除了上面的數據定義,其他配置選項或者是代碼完全一樣,下面是結果:

?

我的天!差距還真是大。

混合代碼和數據:匯編器允許程序在代碼和數據之間來回切換。在定義僅在局部程序中使用的變量時,這是非常方便的。下面的例子在兩端代碼中直接插入并創建一個名為temp的變量:

.code

??mov eax,ebx

.data

??temp DWORD ?

.code

??mov temp,eax

3.5 ?符號常量

符號常量(或符號定義)是通過將標示符(或符號)與整數表達式或文本聯系起來而創建的。與保留存儲空間的變量定義不同,符號常量并不占用任何實際的存儲空間。符號常量僅在編譯期間匯編器掃描程序的時候使用,在運行期間不能更改。下表總結了二者的區別:

?

??接下來講述如何使用等號偽指令(=)來創建代表整數表達式的符號常量,之后,還將講述如何使用EQUTEXTEQU偽指令創建可代表任意文本的符號常量。

3.5.1 ?等號偽指令

????等號偽指令將符號名和整數表達式聯系起來。格式如下:

名字=表達式

通常,表達式(expression)是32位的整數值,匯編程序的時候,所有出現名字(name)的地方都由匯編器在預處理階段替換為對應表達式的值。例如,當編譯器遇到下列語句的時候:

COUNT ??= ??500

mov ????ax,COUNT

將生成并編譯下面的語句:

mov ax,500

為什么要使用符號:跟C++的宏有點像(但不是,=號后面只能是表達式),改一個可以全改。

鍵值的定義:程序中經常要為重要的鍵盤字符定義符號,例如27Esc鍵的ASCII碼值:

Esc_key = 27

這樣在同一程序中,如果語句中使用了這個符號而不是一個立即數,那么語句的額含義就不言自明了。例如,應該使用下面的語句:

mov ?al,Esc_key ?;好的風格

而不是:

mov ?al,27 ?????;不好的風格

??使用DUP操作符:3.4.3節講述了如何使用DUP操作符為數組和字符串分配存儲空間。好的編程風格是使用符號常量作為DUP操作符的計數器,以簡化程序的維護。在下例中,如果COUNT已經預先定義,那么就可以用在下面的數據定義中:

array ?COUNT DUP(0)

重定義:同一程序中以”=”定義的符號可重定義。下面展示了在每次改變COUNT值時編譯器是如何對其進行求值的:

COUNT = 5

mov al,COUNT ????;AL = 5

COUNT = 10

mov al,COUNT ????;Al = 10

COUNT = 100

mov al,COUNT ????;Al = 100

行號(如COUNT)值的改變與運行時語句執行的順序無關,相反符號值是按照匯編器對源代碼的順序處理進行改變的。


3.5.2 ?計算數組和字符串的大小

使用數組的時候,有時候需要知道數組的大小。下列使用一個名為listSize的常量聲明數組list的大小:

list ?BYTE ?10,20,30,40

ListSize = 43

在數組可能會改變大小的時候,手動計算其大小并不是一個好主意。如果要為list添加幾個字節,就需要同時修正ListSize。處理這種情況講好的辦法是讓編譯器自動為我們計算ListSIze的值。MASM($)減掉list的地址偏移值就得到了ListSize值(4):

list BYTE 10,20,30,40

ListSize = ($ - list)

ListSize必須緊跟在list之后。例如,下例中ListSize的值過大,這是因為ListSize包括了var2占用的存儲空間:24

??List ??BYTE ?10,20,30,40

??var2 ?BYTE ?20 DUP(?)

??ListSize = ($ - list)

與其手動計算字符串的長度,不如讓編譯器自動做這種工作:(57

myString BYTE "This is a long string, containing"

?????????BYTE "any number of characters"

myString_len = ($ - myString)?

字數組和雙字數組:如果數組的每個元素都是16位的字,以字節計算的數組長度必須初一2才能得到數組元素的個數(4

list WORD 100h ,200h ,300h ,400h

ListSize = ($ - list) / 2

與此類推,雙字數組的呢個元素時4字節長的,因此/4 3

list DWORD 100000h ,200000h,300000h

ListSize = ($ - list) / 4

3.5.3 ?EQU偽指令

??EQU偽指令將符號名同整數表達式或任意文本聯系起來,有一下三種格式:

??name EQU ?expression

??name EQU ?symbol

??name EQU ?<text>

??在第一種格式中,表達式(expression)必須是有效的整數表達式;在第二種格式中,符號(synbol)必須是已經=EQU定義的符號名;第三種格式中,尖括號內可以是任意文本。當匯編器在后面遇到已經定義的 “名字”(name)時,就用改名字代表的整數值或文本替代。當定義任何非整數值的時候,EQU就可能非常有用了,例如實數常量就可以用EQU定義:

P1 EQU <3.1416>

例子:下列把一個符號同一個字符串聯系了起來,然后使用該符號創建了一個變量:


pressKey EQU <”Press any key to continue...”,0>

.

.

.data

pronpt BYTE pressKey

再來一個例子:

matrix1 EQU 10*10

matrix2 EQU <10*10>

.data

M1 WORD matrix1

M2 WORD matrix2

匯編器為M1M2生成不同的數據定義,martix1中的整數表達式被計算并賦給M1,而matrix2內的文本將直接復制到M2的數據定義中,實際的等效語句是:

M1 WORD 100

M2 WORD 10*10

不允許重定義:與”=”偽指令不同,用EQU定義的符號不能再同一源代碼文件中重定義,這個限制能夠防止已存在的符號被無意中賦了新值。

3.5.4 ?TEXTEQU偽指令

TEXTEQU偽指令與EQU非常相似,也可用來創建文本宏(text macro)。它有三種不同的使用格式:第一種格式將文本賦給符號;第二種格式將已定義的文本宏內容賦給符號;第三種格式將整數表達式常量賦給符號。

name TEXTEQU <text>

name TEXTEQU textmacro

name TEXTEQU %constExpr

例如,prompt1變量使用了continueMsg文本宏:

continueMsg TEXTEQU <”Do you wish to continue (Y/N)?”>

.data

Prompt1 BYTE continueMsg

可用文本宏方便地創建其他的文本宏。在下例中,count被設置為包含宏rowSize的整數表達式的值,接下來符號move被定義為movsetupAL則由movecount共同創建:

rowSize=5

count ??TEXTEQU %(rowSize*2)

move ???TEXTEQU <mov>

setupAL TEXTEQU <move al ,count>

因此下面的語句:

setupAl

將被匯編成

mov al,10

EQU偽指令不同的是,TEXTEQU可以在程序中重新定義。

?

?

3.6 ?實地址模式程序設計(可選)

MS-DOS設計的程序必須是云心更是低至模式下的16位應用。實地址模式應用程序使用16位的段并且遵循2.3.1節描述的分段尋址方案。如果使用的是IA-32處理器,則仍然可以使用32位通用寄存器存取數據。

3.6.1 ?基本的修改

將本章中的32位程序轉換成實地址模式程序,需要做一些修改:

INCLUDE偽指令要引用另外一個不同的庫文件:

INCLUDE Irvine16.inc

在啟動過程(main)的開始插入兩條額外的指令,這兩條指令將DS寄存器初始化為數據段的其實地址,數據段的其實地址用MASM的預定義常量@data表示:

mov ax ,@data

mov ds,ax

如何匯編16位程序的步驟請參見www.asmirvine.com

數據標號和代碼標號的偏移(地址)是16位而不是32位。

不能把@data直接送DSES寄存器,因為MOV指令不允許直接向段寄存器傳送常量;

實地址AddSub程序:

INCLUDE Irvine16.inc ?;changed

.data

val1 DWORD 10000h

val2 DWORD 40000h

val3 DWORD 20000h

finalVal DWORD ?

.code

main PROC

????mov ax,@data ;new

mov ds,ax ???;new

?

mov eax,val1

add eax,val2

sub eax,val3

mov finalVal,eax

call DumpRegs

exit

main ENDP

END main

PS:這個我本機沒有編過,我的環境是vs2012+masm32 debug模式。不查了,用到的時候再說吧,實地址模式我幾乎用不上。

3.7 ?本章小結

?

?

總結

以上是生活随笔為你收集整理的Intel汇编语言程序设计学习-第三章 汇编语言基础-下的全部內容,希望文章能夠幫你解決所遇到的問題。

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