---
# System prepended metadata

title: Assembly Language - Note
tags: [組合語言, 大二下]

---

# 大二下 - Assembly Language - Note
###### tags: `大二下` `組合語言`
**考前筆記整理**
**前面有空再來補**

--
**20240131更 前面的就不補了:laughing:**


CH6 Conditional Processing
===
*條件處理*
> 一個看code一直跳來跳去的章節
> 主要看cmp的條件是否成立來決定jump or not

 布林&比較指令 
 ---
 Boolean and Comparison Instructions 
 
---
*  AND
 兩個運算元必須相同大小
 AND可用來清除位元 -> 遮罩(masking)
```MASM!
mov al,10101110b
and al,11110110b    ;al=10100110
```
轉大寫字母
```!
0 1 1 0 0 0 0 1 = 61h ('a')
0 1 0 0 0 0 0 1 = 41h ('A')
```
```MASM!
.data
array BYTE 50 DUP(?)
.code
mov ecx,LENGTHOF array
mov esi,OFFSET array
L1: 
and BYTE PTR [esi],11011111b ; 清掉 bit 5
inc esi
loop L1
```
:::info
:bulb: AND會清除OF & CF
:::
---
*  OR
 兩個運算元必須相同大小
:::info
:bulb: OR會清除OF & CF
:::
透過Flag看al的值
| ZF   | SF   | AL   |
| ---- | ---- | ---- |
|  ZF=0|SF=0  | 大於0 |
|  ZF=1|SF=0  | =0   |
|  ZF=0|SF=1  | 小於0 |
---
*  NOT
1's補數
```MASM!
mov al,11110000b 
not al             ; AL = 00001111b
```
:::info
:bulb: NOT不影響any flag
:::
---
*  XOR
    >互斥 異性戀代表 : 一個1 & 一個0 => 1

對稱式加密 -> 超帥的
>插播一則PF(同位flag)
PF=1 > 偶個1
PF=0 > 奇個1
```MASM!
mov al,10110101b ; 5 個 1
xor al,0         ; PF = 0
mov al,11001100b ; 4 個 1
xor al,0         ; PF = 1
```
:::info
:bulb: XOR會清除OF & CF
:::
---
*  TEST
    >TEST隱含ADN的運算
    >與AND不同點是 -> TEST不會改到*Destination*的值
```MASM!
test al,00001001b    ; 測 0 & 3 bit 也有 bit mask
```
:::info
:bulb: TEST會清除OF & CF
:::
---
*  CMP
>是個logic指令
>偷偷含有減法
>>unsigned

```
小-大要借位 -> CF=1
```
| CMP  | ZF   | CF   |
| ---- | ---- | ---- |
|  左<右|0 | 1 |
|  左>右|0 | 0 |
|  左=右|1 | 0 |
>>signed
>>
```
SF = 負的時候, SF = 1
減法的時候不可能溢位, OF 不可能 = 1, OF 在CMP都 = 0
```
| CMP | Flag |
| -------- | -------- |
| 左<右     |  SF(1) != OF(0) |
| 左>右     |  SF(0) = OF(0)  |
| 左=右     | ZF=1      |
---
* stc & clc
```MASM!
stc ; CF = 1
clc ; CF = 0
```
:::success
:joy: 接下來要跳個不停了:joy: 
:::
 條件跳躍 
 ---
 Conditional Jumps 
 ```html
 C = CF
 O = OF
 S = SF
 P = PF
 E = '='
 N = NOT
 Z = '0'
 CXZ = 'CX=0'
 ```
 ![](https://i.imgur.com/yjEbwqi.jpg)
 ![](https://i.imgur.com/9ljVkgQ.png)

 ```MASM
 CMP leftOp,rightOp
 ```
 
:::warning
:i_love_you_hand_sign: signed & unsigned不一樣的part
:::
```MASM!
mov al,+127      ; 7Fh
cmp al,-128      ; 80h
ja IsAbove       ; 7Fh < 80h so 不跳 ,無號數
jg IsGreater     ; +127 > -128 so 跳
```
* Unsigned
   >A = above
    B = below
    
![](https://i.imgur.com/NpnvQEP.png)
* Signed
   >G = greater
    L = lowerer
    
![](https://i.imgur.com/eJmaxvS.png)
* 可以玩比大小
```MASM!
;找最小的

.data
V1 WORD ?
V2 WORD ?
V3 WORD ?
.code
mov ax,V1     ; 假設 V1 最小
cmp ax,V2     ; if AX <= V2
jbe L1        ; 跳去 L1
mov ax,V2     ; else 把 V2 丟到 AX
L1: cmp ax,V3 ; if AX <= V3
jbe L2        ; jump to L2 
mov ax,V3     ; else 把 V3 丟到 AX
L2:
```
* 這邊一個Readkey
`找到user按下鍵 => ZF=1`

    ```MASM!
    .data
    char BYTE ?
    .code
    L1: mov eax,10 
    call Delay
    call ReadKey    ; 檢查user按下keyboard了沒
    jz L1        
    mov char,AL 
    ```
* 字串加密
    >XOR
![](https://i.imgur.com/xT0EGzY.png)

 
 條件迴圈指令 
 ---
 Conditional Loop Instructions
 * LOOPZ
     >if ZF=1 則繼續loop
 * LOOPE
     >if '=' 則繼續loop
 * LOOPNZ
     >if ZF=0 則繼續loop
 * LOOPNE
     >if '!=' 則繼續loop
    ```MASM!
    .data
    array SWORD -3,-6,-1,-10,10,30,40,4
    sentinel SWORD 0

    .code
    mov esi,OFFSET array
    mov ecx,LENGTHOF array
    L1: test WORD PTR [esi],8000h ; 看這行執行後的 ZF = ?
    pushfd 
    add esi,TYPE array
    popfd 
    loopnz L1 
    jnz quit 
    sub esi,TYPE array 
    quit:
    ```
 
 條件結構 
 ---
 Conditional Structures
 * 白箱測試
     >programmer自行指定給input, 然後...
     >trace trace trace
 * 捷徑估算
     >利用 ja, jbe 等...之類的不同以簡短code
 * WHILE loop
     ```MASM
     mov eax,val1 
    beginwhile:
    cmp eax,val2     ; if (val1 < val2) 是 false
    jnl endwhile
    inc eax 
    dec val2 
    jmp beginwhile 
    endwhile:
    mov val1,eax 
     ```
 * 表格驅動式
     >table-drive
     >![](https://i.imgur.com/nrWDsYS.png)

 應用:有限狀態機 
 ---
 Finite-State Machines(FSM)
* 驗證輸入的string
    >找x & z夾住的string
    >![](https://i.imgur.com/e3VYQ3a.png)
    >```
    >xaabcdefgz
    >xz
    >xyyqqrrstuvz
* 驗證signed int
    >IsDigit
    >```MASM
    >call IsDigit      ; ZF = 1 if AL 是數字
    >jz StateC 
    >```
    >![](https://i.imgur.com/uFngseF.png)

    :::info
    檢查是否在 ' 0 ' ~ ' 9 ' (也就是30~39) 就好
    :::

 條件控制流程指引 
 ---
 Conditional Control Flow Directives
* Conditional Control Flow Directives 
![](https://i.imgur.com/gMh0Gb0.png)
* Runtime Relational and Logical Operators
    `Runtime的relationship & 邏輯運算子`
![](https://i.imgur.com/3Bzy4Uv.png)
* 寫法
    ```MASM
    .data
    val1 DWORD 5
    result DWORD ?
    .code
    mov eax,6
    .IF eax > val1    ;很像高階語言的if
     mov result,1
    .ENDIF            ;一定要有這傢伙
    ```

    組譯器會生出這段

    ```MASM!
    mov eax,6
    cmp eax,val1
    jbe @C0001 
    mov result,1
    @C0001:
    ```

 `//以下還有兩種loop`


* .REPEAT
    ```MASM
    mov eax,0
    .REPEAT
    inc eax
    call WriteDec
    call Crlf
    .UNTIL eax == 10
    ```
* .WHILE
    ```MASM
    mov eax,0
    .WHILE eax < 10
    inc eax
    call WriteDec
    call Crlf
    .ENDW
    ```

CH7 Integer Arithmetic
===
*整數算數運算*
> 把一堆10移來移去的章節
> 分辨CF=1 or CF=0
> 分辨各指令是否包含把位元移進CF

 位移&旋轉指令 
 ---
 Shift and Rotate Instructions
 * SHL & SHR
     >邏輯移位
     >*SHL:*
     >高的去CF 
     >低的補0
     ![](https://i.imgur.com/0ltlYkE.png)
    ```MASM!     
    mov bl,8Fh     ; BL = 10001111b 
    shl bl,1       ; CF = 1, BL = 00011110b
    ```
     >可以乘法:無號數才可
     >左移n次 -> x 2^n
     >
     >---
     >*SHR*
     >
     >![](https://i.imgur.com/28fE0r6.png)
     >可以除法:無號數才可
     >右移n次 -> / 2^n
     ---
 * SAL & SAR
     >跟上面SHL & SHR很像
     >只差在signed跟unsigned
     >*SAL:*
     >![](https://i.imgur.com/SnyiJfM.png)
     >
     >---
     >*SAR:*
     >複製正負號位元 -> 第一個自己複製自己擺回去
     >這個可以執行有號除法!!!
     >![](https://i.imgur.com/uh4T5z9.png)
     >```MASM
     >;AX -> EAX
     >mov ax,-128 ; EAX = ????FF80h
     >shl eax,16  ; EAX = FF800000h
     >sar eax,16  ; EAX = FFFFFF80h
     >```
 * ROL & ROR
     >*ROL:*
     >![](https://i.imgur.com/JvKdWFR.png)
     >可交換位元:
     >ex: 1111 0000 上半和下半交換(byte)
     >-> 0000 1111
     >```MASM!
     >mov al,26h
     >rol al,4     ; AL = 62h
     >```
     >
     >---
     >*ROR:*
     >就 看圖吧 :smile:
     >![](https://i.imgur.com/XiWNzQS.png)
 * RCL & RCR
     >包含CF的旋轉 -> CF加入一起轉
     >*RCL:*
     >![](https://i.imgur.com/hqrgxoX.png)
     >
     >---
     >*RCR:*
     >![](https://i.imgur.com/1sIZmtY.png)
:::success
:bulb:有號數的OF:
旋轉後超過範圍(ex: AL 在 -128 ~ 127)
則OF = 1
:::
 * SHLD & SHRD
     >-> D : double
     >-> 適合做點陣圖影像(manipulate bit-mapped images)
     >*SHLD:*
     >```
     >SHLD dest, source, count
     >```
     >![](https://i.imgur.com/rCqGSU6.png)
     >
     >---
     >*SHRD:*
     >```
     >SHRD dest, source, count
     >```
     >![](https://i.imgur.com/PmMEK2p.png)
 
 應用:位移&旋轉應用
 ---
 Shift and Rotate Applications
 * 移多個DWORD
 ![](https://i.imgur.com/Dg04mxs.png)
 ![](https://i.imgur.com/AGN9ePU.png)
 ![](https://i.imgur.com/eFMqOFj.png)
 ![](https://i.imgur.com/017zSK4.png)
 `總之就是藉由CF把全部移動啦~`
 來個code
 ```MASM!
 .data
ArraySize = 3
array BYTE ArraySize DUP(99h) ; 1001 pattern in each nybble
.code
main PROC
mov esi,0
shr array[esi+2],1            ; high byte
rcr array[esi+1],1            ; middle byte, include CF
rcr array[esi],1              ; low byte, include CF
 ```
---
    
 * 二進位乘法
     >利用分配律
     >![](https://i.imgur.com/ZgGj4nJ.png)
     >![](https://i.imgur.com/M1XyRfu.png)
     >```MASM!
     >mov eax,123
     >mov ebx,eax
     >shl eax,5      ; x 2^5
     >shl ebx,2      ; x 2^2
     >add eax,ebx    ; 加起來
     >```
 ---
 * 日期
     >![](https://i.imgur.com/PhTKyta.png)
     >比較特別是year最後要加上1980
 
 乘法&除法指令
 ---
 Multiplication and Division Instructions
 * MUL
     >無號數
     >記得看CF是否 = 1 (超過AL AX EAX(跑到DX EDX裡面的話)會進位)
     >![](https://i.imgur.com/Ie4ktKb.png)
 * IMUL
     >有號數
     >```MASM!
     >; 因為AH不是AL的+-延伸 -> OF = 1
     >mov al,48
     >mov bl,4
     >imul bl      ; AX = 00C0h, OF = 1
     >                     ; -  這裡C是- 前面最高位元是+
     >```
     >```MASM!
     >; 因為AH是AL的+-延伸 -> OF = 0
     >mov al,-4
     >mov bl,4
     >imul bl      ; AX = FFF0h, OF = 0
     >                     ; -  這裡F是- 前面最高位元是-
     >```
 * DIV
     >無號
     >餘數 商數
     >![](https://i.imgur.com/MgheH1T.png)
 * IDIV
     >AX必須被完全符號延伸 -> 餘數要跟被除數+-號一樣
     >```MASM!
     >; CBW CWD CDQ => 延伸+-號
     >.data
     >wordVal SWORD -101 ; FF9Bh
     >.code
     >mov ax,wordVal     ; AX = FF9Bh
     >cwd                ; DX:AX = FFFFFF9Bh
     >```
     >
 
 延伸加法&減法
 ---
 Extended Addition and Subtraction
 * ADC
     >包含進位的加法
     >```MASM
     >mov dl,0
     >mov al,0FFh
     >add al,0FFh   ; AL = FEh
     >adc dl,0      ; DL/AL = 01FEh
     >; 把CF塞進DL
     >```
 * SBB
     >包含借位的減法
     >![](https://i.imgur.com/7i8BjyM.png)
 
 ASCII&未壓縮十進制算術運算
 ---
 ASCII and Unpacked Decimal Arithmetic
 最高4個位元永遠是0
 ![](https://i.imgur.com/qqYHFJQ.png)
 * AAA
     >加法後調整ASCII
     >可以調的: ADD ADC
     >```MASM
     >mov ah,0
     >mov al,'8'      ; AX = 0038h
     >add al,'2'      ; AX = 006Ah
     >aaa             ; AX = 0100h (ASCII adjust result)
     >or ax,3030h     ; AX = 3130h = '10' (轉成ASCII)
     >```
 * AAS
     >減法後調整ASCII
     >可以調的: SUB SBB
     >減完結果是負的才需要
 * AAM
     >乘法
     >```MASM
     >.data
     >AscVal BYTE 05h,06h
     >.code
     >mov bl,ascVal        ; first operand
     >mov al,[ascVal+1]    ; second operand
     >mul bl               ; AX = 001Eh
     >aam                  ; AX = 0300h 
     >```
 * AAD
     >把0307h轉為二進位
     >才好執行DIV
     >```MASM!
     >.data
     >quotient BYTE ?
     >remainder BYTE ?
     >.code
     >mov ax,0307h          ; dividend
     >aad                   ; AX = 0025h
     >mov bl,5              ; divisor
     >div bl                ; AX = 0207h
     >mov quotient,al
     >mov remainder,ah
     >```
 
 壓縮十進制算術運算
 ---
 Packed Decimal Arithmetic
 比未壓縮的簡單
 但是沒有乘法&除法
 * DAA(+)
     >```MASM!
     >mov al,35h
     >add al,48h    ; AL = 7Dh
     >daa           ; AL = 83h (直接變成美妙的十進位)
     >```
 * DAS(-)
     >```MASM!
     >mov bl,48h
     >mov al,85h
     >sub al,bl     ; AL = 3Dh
     >das           ; AL = 37h (直接變成美妙的十進位)
     >```
     
  
  
CH8 Advanced Procedures
===
*進階程序*
> 都是指引
> 各種越來越high-level的指引(directive)
:::danger
:warning: 這章節重點考！！！
:::

 堆疊框
 ---
 Stack Frames
 (Activation record)
 * push 進 stack
     >**根據值**
     >![](https://i.imgur.com/CEwY8dW.png)
     >
     >---
     >**根據reference**
     >一堆OFFSET
     >![](https://i.imgur.com/VsJLYyV.png)
     >傳遞array用reference比較快
:::info
:bulb:引數(argument)是倒著push進stack的
:::
* 開場程式碼(prologue)
    ```MASM
    AddTwo PROC
    push ebp
    mov ebp,esp
    ```
    ![](https://i.imgur.com/0wMI1hq.png)
    ```
    ESP會變
    
    EBP不會變 
    EBP當位移參考基準
    ```
 * Explicit Stack Parameters(明確堆疊參數)
     明白地寫出參數所在的位移位址 like -> [ebp + 8],
     ```MASM!
     y_param EQU [ebp + 12]
    x_param EQU [ebp + 8]
    AddTwo PROC
    push ebp
    mov ebp,esp
    mov eax,y_param
    add eax,x_param
    pop ebp            ;要先pop EBP, 再 ret, 否則沒有清除到 stack
    ret
    AddTwo ENDP
     ```
 * 32 - bit 呼叫慣例(32-Bit Calling Conventions)
     >:warning:STDCALL
     >```MASM
     >AddTwo PROC
     >push ebp
     >mov ebp,esp          ; base of stack frame
     >mov eax,[ebp + 12]   ; second parameter
     >add eax,[ebp + 8]    ; first parameter
     >pop ebp
     >ret 8                ; 清除stack , 8 是指process耗掉的space
     >AddTwo ENDP
     >```
 * 區域變數
     >通常在EBP下面
     >![](https://i.imgur.com/BsQttCT.png)
     >```MASM
     >MySub PROC
     >push ebp
     >mov ebp,esp
     >sub esp,8                     ; 建立區域變數
     >mov DWORD PTR [ebp-4],10      ; X
     >mov DWORD PTR [ebp-8],20      ; Y
     >mov esp,ebp                   ; 從stack移除區域變數,讓ESP回去EBP紀錄那
     >pop ebp
     >ret
     >MySub ENDP
     >```
 * LEA
     >回傳間接運算元的位移
     >```MASM
     >makeArray PROC
     >push ebp
     >mov ebp,esp
     >sub esp,32                  ; 30個byte, 但要對齊
     >lea esi,[ebp–30]            ; load address of myString
     >mov ecx,30 ; loop counter
     >L1: mov BYTE PTR [esi],'*'  
     >inc esi 
     >loop L1 
     >add esp,32                  ; 移除array, 恢復ESP
     >pop ebp
     >ret
     >makeArray ENDP
     >```
     >這裡不要用OFFSET

 * ENTER
    ```MASM
    MySub PROC
    push ebp
    mov ebp,esp
    sub esp,8
    ```
    ![](https://i.imgur.com/vHgePMX.png)

* LEAVE
    ```MASM
    mov esp,ebp
    pop ebp
     ret
    ```
* LOCAL
    >可以一次宣告多個區域變數
    >會自己分好指定要的記憶體大小
    >Example1示意圖:
    ![](https://i.imgur.com/X0KAAeV.png)

    ```MASM
    Example1 PROC
    LOCAL temp:DWORD
    mov eax,temp
    ret
    Example1 ENDP
    ; 下面這坨是 LOCAL temp: DWORD
    push ebp 
    mov ebp,esp 
    add esp,0FFFFFFFCh ; add -4 to ESP
    mov eax,[ebp-4]
    leave
    ret
    ```
 遞迴
 ---
 Recursion
* 階乘
    >去mov eax, [ebp+8] 找 n
    ![](https://i.imgur.com/8lGcjvk.png) 
    全部打開長這樣![](https://i.imgur.com/22o4Hrc.png)
    
    
 INVOKE,ADDR,PROC,PROTO
 ---
 這些directive幾乎有high-level language的便利
* INVOKE
    >將argumant push 進 stack
    >可以用任意個引數(arguments)
    ```
    用法:
    (避免覆寫EAX,EDX,用32-bit)
    INVOKE DumpArray,   ; displays an array
    OFFSET array,       ; points to the array
    LENGTHOF array,     ; the array length
    TYPE array          ; array component size
    ```
    ---
* ADDR
    >傳遞指標引數
    >必須跟INVOKE一起
    ```MASM
    .data
    Array DWORD 20 DUP(?)
    .code
    ...
    INVOKE Swap, 
    ADDR Array,
    ADDR [Array+4]
    ```
    組譯後長這樣:
    ```MASM
    push OFFSET Array+4
    push OFFSET Array
    call Swap
    ```
    ---
* PROC
    ```MASM
    AddTwo PROC,
    val1:DWORD,
    val2:DWORD
    mov eax,val1
    add eax,val2
    ret
    AddTwo ENDP
    ```
    來喔組譯了
    ```MASM
    AddTwo PROC
    push ebp
    mov ebp, esp
    mov eax,dword ptr [ebp+8] 
    add eax,dword ptr [ebp+0Ch] 
    leave
    ret 8
    AddTwo ENDP
    ```
    先定義好,並且生出
    push ebp
    mov ebp, esp
    ```
    因為每個參數都是DWORD:
    所以ret (n*4)
    
    push ebp
    mov ebp,esp
    .
    leave
    ret (n*4)
    ```
* PROTO
    指出程式外部的process
    :bulb:像是先宣告我等等要用這個function的意思
    >PROTO -> INVOKE -> PROC
    >PROC在INVOKE前的話也可以不要PROTO
* 來一個完整code範例
```MASM
ArraySum PROC USES esi ecx,  ; PROC是自己的PROTO
ptrArray:PTR DWORD,          ; 省掉EBP ESP 那坨
szArray:DWORD 
mov esi,ptrArray 
mov ecx,szArray 
mov eax,0 
cmp ecx,0 
je L2 
L1: add eax,[esi] 
add esi,4 
loop L1 
L2: ret 
ArraySum ENDP

.data
array DWORD 10000h,20000h,30000h,40000h,50000h
theSum DWORD ?
.code
main PROC
INVOKE ArraySum,
 ADDR array,        ; address of the array
 LENGTHOF array     ; number of elements
mov theSum,eax      ; store the sum
```
 
 建立多模組程式
 ---
 Creating Multimodule Programs
>將程式分割成多個modules
>2種方法
* EXTERN
    ```MASM
    ;插播一下:
    OPTION PROC : PRIVATE ;設定私用,封裝(encapsulation)
    
    main PROC PUBLIC      ;阿main一定要PUBLIC
    ```
    ```MASM
    INCLUDE Irvine32.inc
    EXTERN sub1@0:PROC   ; 這個 @0 是被宣告的傢伙用掉的總stack空間
    .code
    main PROC
    call sub1@0
    exit
    main ENDP
    END main
    ```
* INVOKE & PROTO
    比對INVOKE傳遞的list & PROC宣告的參數list
    這裡就展示了一堆modules -> 我懶得全貼了
 
 
 (選讀)
 ---
 * Advanced Use of Parameters
     * *USES:*
     >列出register名稱
     >自動產生push & pop
     ```MASM
     MySub2 PROC USES ecx edx
    push ebp
    mov ebp,esp 
    mov eax,[ebp+8] 
    pop ebp 
    ret 4 
    MySub2 ENDP
     ```
     變這樣:多塞了2個傢伙 -> ecx edx
     ![](https://i.imgur.com/GaKF83j.png)

     ```MASM
     push ecx
    push edx
    push ebp
    mov ebp,esp
    mov eax,dword ptr [ebp+8]   ; [ebp+8]是錯的, [ebp+16]才對
    pop ebp
    pop edx
    pop ecx
    ret 4
     ```
    * 傳8-bit & 16-bit
    要在進stack前先擴展成32-bit movzx
    ```MASM
    .data
    word1 WORD 1234h
    word2 WORD 4111h
    .code
    movzx eax,word1       ; 藉由eax轉32-bit
    push eax
    movzx eax,word2
    push eax
    call AddTwo           ; sum is in EAX
    ```
     
 * Java Bytecodes(skip)
 