匯編學習筆記(4)-偽指令(MASM)


前言

  編寫匯編代碼的時候會使用到兩種語句,一種就是前面介紹的匯編指令又CPU提供功能支持,另一種呢叫做偽指令,偽指令是由匯編的編譯器提供支持。所以偽指令的運行結果都必須實在編譯的時候就能確定的,下面介紹的就是偽指令了。

  注意接下來介紹的偽指令都是基於MASM匯編編譯器,比較常用的還有NASM 它的語法以后有機會介紹

 

數值表達式

  數值表達式不是匯編指令,表達式的值是在匯編代碼的匯編過程中就由匯編編譯器計算出結果而寫到二進制程序中了,並不是在程序運行的過程中才計算的

  (1) 常數表達式

    常數就是直接的數字,直接寫數字默認表示10進制數,也可以用符號指定為其他進制

    D = 十進制   ; MOV AL, 1234D

    B = 二進制   ; MOV AL,  0101B

    H = 十六進制  ; MOV AL,  0FFFFH , 注意常數必須是數字開頭不能是字母開頭,如果16進制數第一個數字是字母的話就要補一個0在前面

    Q = 八進制   ; MOV AL, 123Q

 

    因為在程序中字母也是數字,所以其實也可以直接將字母或者字符串當成數字,比如

    MOV AL, 'a'

    MOV AX,"ab"  ; 雙引號和單引號都是可以使用的

 

   (2) 算數運算符

    就是簡單的 正(+) 負(-) 加(+) 減(-) 乘(*) 除(/) 模(mod)

    mov ax, 100+200

    mov ax, 100/2

 

  (3) 關系運算符

    等於(EQ) 不等(NE) 大於(GT) 小於(LT) 大於等於(GE) 小於等於(LE)

    如果等式成立則實際的值為0FFFF就是補碼表示的-1, 如果關系不成立那么結果就是0

    mov ax, 123 gt 234

    mov ax, 1234+5 lt 1235

 

  (4) 邏輯運算 

    與(and) 或(or) 非(not) 異或(xor) 左位移(shl) 右位移(shr)

    mov ax, 1 shl 3

    mov al, 3 and 47

 

  (5) 其他操作符

    HIGH LOW WIDTH MASK 

    HIGH 表示取數據的高八位

    LOW 表示取數據的低八位

  

地址表達式

  地址表達式所表示的是存儲器操作數的地址。前面介紹的各種尋址方式實際上也是地址表達式。

  一般格式是

  mov ax, varw+4

 

  注意 varw 變量或者標號的地址,這個是在編譯的時候就知道的,所以varw+4 計算出來的就是varw 地址偏移4的地址,所以AX的值不是 varw+4的值,而是varw+4 內存地址處的值,所以AX的值是不確定的。

  當然還有其他的寫法

  [varw+bx]

  varw[bx]

  varw[bx+di]

  varw[bx][di]

 

變量和標號

  (1) 數據定義語句

    [變量名]  變量類型 表達式[, 表達式]

    其中變量類型有

    DB  字節

    DW  字

    DD   雙字

    

    所以數據定義就可以是這樣的

    a db 1,2,3,4,5

    db 7,8,9,10

    b dw 123,123,123

    c dd 123,?,?,?

 

    匯編中的數據定義意義其實就是C中的數組指針。這些數據都是順序存放在內存中的,所以雖然第二行的數據沒有定義名字,但是因為他緊跟在a 數組之后 b數組之前,所以使用a+5,或者 b-1 也是可以訪問的,只是需要注意的是數據類型和 大端小端的問題。

    后面跟實際數據的就表示定義的時候就直接初始化了數據,如果只是想留着位置,並不需要初始化的話也可以使用? 表示,?的意思就是只留位置不初始化內容

  

    前面也說過,字符其實也可以表示為數字,所以也之后直接定義字符數組,下面的兩種方式都是可行的

    str  db “hello”

    str db "h","e","l","l","0"

  

  (2) 循環定義 DUP

    數字表達式 DUP(數據[, 數據,數據...])

    有時候定義數組只是想預留一些空間,可能需要預留100個字節那么使用

    buff db ?,?,?,?.......? 

    這種方式要打100個? 這樣顯然很沒效率所以有個偽指令可以幫忙

    buff db 100 dup(?);   定義100個DB 數據不用初始化

    也可以這樣

    buff  db 5 dup("ab") = buff db 'a','b','a','b','a','b','a','b','a','b'

    dup 也是可以嵌套的比如

    buff db 2 dup(1,2,5 dup(?)) =  buff db 1,2,?,?,?,?,?,1,2,?,?,?,?,?

 

  (3) this   

     this 類型

     類型可以是byte word dword this返回下一個將分配的地址的

    my_byte equ this byte  ; equ是等效定義符號,下面或解釋

    my_word dw 8 dup(?)

    這樣就是定義了一個 byte的地址指針指向了一個 word數組等效的C語言就是

    short[8]  my_word[];

    byte* my_byte = (byte*)my_word;

 

  (4) 等價語句  EQU

    符號名 EQU 表達式

    說白了 EQU 就類似C的 #define 語句 

    用法可以是這樣的

    COUNT EQU 100      ; #define COUNT 100

    BUFF_EN EQU 4*COUNT  ; #define BUFF_EN  4*COUNT

    HELLO EQU "how are you"   ; #define HELLO "how are you"

    MOVE EQU MOV        ;#define MOVE MOV

    

    VARW EQU THIS WORD  ; 這個就和#dfine不一樣了意義上面說過

    VARB DB 2 DUP(?)

  

  (5) 等於語句 =

     符號名 = 數值表達式

    其實就是專用的 EQU,功能和EQU是一樣的,只不過試用范圍比EQU小,只能用在數值表達式上

    x = 10 ;  x equ 10

    y =20 +50*60 ; y equ 20+50*60

  

  (6) 定義符號名語句

    符號名 LABEL 類型

    類型可以是 BYTE WORD DWORD NEAR FAR

    他的作用其實應該是包含上面 this 指令中的用法即

      my_byte equ this byte

      my_word dw 8 dup(?)

      換成LABEL的寫法就是    

      my_byte label byte 

      my_word dw 8 dup(?)

 

   同時LABLE 還比this強大就是還能作用在標號上

   quit label far

   exit: mov ah,4ch

   這樣的用法就 mov ah,4ch這條指令同時擁有 exit的短調指令和quit的長跳指令了。

 

   (7) 變量和標號的屬性

    變量和標號的屬性無非就是對應的類型 地址 大小等,對應的操作符

    LENGTH SIZE OFFSET SEG TYPE PTR

    seg 返回變量或標號的段地址    假設 VAR 的地址是 100+2   那么mov al, seg var ; al=100

    offset 返回變量或標號的偏移地址  假設 VAR 的地址是 100+2   那么mov al, offset var ; al=2

    type 返回變量或標號的類型   字節=1 字=2 雙字=3 近=-1 遠=-2,變量類型就是實際占用的字節數

    length 返回的是DUP定義的長度  DUP將在下面講到, 注意這里返回的是個數,如果數組沒用DUP那么總是返回1 如果嵌套了就返回最外層的

    size  返回DUP定義的實際占用字節數

    ptr  強制類型轉化 就是C語言中的(int)A;的作用 用法就是     類型 ptr  變量/數據地址  類型可以是 byte word dword near far

        例如:

        mov word ptr [si],1

        jmp far ptr ok

 

優先級

   1. 各種括號,LENGTH SIZE WIDTH MASK

   2. PTR OFFSER SEG TYPE THIS 冒號

   3. * / shl shr

   4. HIGH LOW

   5. + -

   6. eq ne lt le gt ge

   7. not

   8. and

   9. or, xor

   10. short

 

程序組織偽指令

  這些指令是為了方便匯編程序的結構組織的

  (1) 段定義語句

    為了與存儲器的分段結構相對應,所以匯編指令也提供了對應的段的組織方式

    段的開始

      段名 SEGMENT [定位類型] [組合類型] [‘類別’]

      。。

    段的結束

      段名 ENDS

 

    例子

    ;數據段

    DSEG SEGMENT

    MESS DB 'HELLO'

    DSEG ENDS

    ;代碼段

    CSEG SEGMENT

      MOV AX, DSEG

        ...

        ...

    CSEG ENDS

 

  (2) 段使用設定語句

    ASSUME 段寄存器名: 段名 [, 段寄存器名: 段名, 段寄存器名: 段名 ..]

    設定了段之后匯編程序需要知道各自段對應是用來干嘛的,並設置對應的段寄存器。ASSUME就是這個作用

    ASSUME CS: CSEG,DS:DSEG

    ASSUME 是偽指令所以匯編編譯器其實是將其轉換成了對應的匯編指令,所以ASSUME可以出現在代碼段的任何位置。隨時進行切換

    這里有個需要注意的是,如下代碼

    DSGE1 SEGMENT

        .....

    DSGE ENDS

 

    DSEG2 SEGMENT

        ......

    DSGE2 ENDS

 

    CSEG SEGMENT

    ASSUME CS:CSEG DS:DSEG1 ES:DSEG2

    MOV AX,DSEG1      ; 由於此時數據段就是DSEG1 所以指令就是直接翻譯的

    MOV AX,DSEG2      ; 由於此時數據段是DSEG1,所以實際語句會被翻譯成 MOV AX, ES:DSEG2

 

  (3) ORG 指令

    ORG 數值表達式

    匯編編譯器在匯編的時候使用匯編地址計算器來計算每條指令的偏移地址,而ORG指令就是用於手動修改當前地址的

    比如

    test segment

       org 100h

    begin: mov ax,1234h

    test ends

    mov ax,1234h 是段內的第一條語句偏移應該是0 ,但是由於ORG 100H的緣故,實際的偏移地址就變成了100H

  

  (4) 當前地址 $

    $表示當前指令的第一個字節的地址

    org $+8 表示表示地址計算器從此處開始向后空8個字節出來

    他也可以用在其他指令中,比如

    jmp  $+ 6 ; 轉跳到本條指令之后6個字節處,注意計算地址是JMP指令的開始位置不是結束位置,所以這6個自己包含了JMP本身的長度

    ARRAY 1,2,$+4; 這里的% 表示的是ARRAY的地址不是 $ +4的地址

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM