![]()
โพรซีเดอร์ และมาโคร ในแอสเซมบลี้
| ![]() |
|
ปรับปรุง : 2562-02-01 (ปรับ template) |
| Digital logic | OS | คำสั่งดอส | Batch | Debug | Assembly | GWBasic | Docker | |
|
1. การเขียน procedure พิมพ์ A
- เขียน procedure นอก .code หรือ segment เหมือน macro ไม่ได้ - การเรียกใช้ procedure ต้องขึ้นต้นด้วยคำว่า call - ก่อน endp ต้องสั่ง ret เพื่อกลับมายังบรรทัดที่ call .model small
.data
.code
x: mov ax,@data
mov ds,ax
call oho1
y: mov ah,4ch
int 21h
; === procedure ===
oho1 proc near
mov ah,2h
mov dl,41h
int 21h
ret
oho1 endp
.stack 200h
end x
|
|
2. การเขียนมากกว่า 1 procedure
- procedure ถูกเรียกใช้ได้หลายครั้ง เช่นเดียวกับ macro - สามารถประการ procedure ใต้ .code แล้วเรียกใช้ภายหลังได้ .model small
.data
.code
x: mov ax,@data
mov ds,ax
call oho1
call oho2
call oho1
call oho2
y: mov ah,4ch
int 21h
; === procedure ===
oho1 proc near
mov ah,2h
mov dl,41h
int 21h
ret
oho1 endp
oho2 proc near
mov ah,2h
mov dl,61h
int 21h
ret
oho2 endp
.stack 200h
end x
|
|
3. การเขียน macro พิมพ์ A
- ประกาศ macro ก่อนเข้าโปรแกรม จะประกาศเหมือน procedure ไม่ได้ - เพียงพิมพ์ชื่อมาโคร ก็จะหมายถึงเรียกใช้ macro helloa macro
mov ah,2
mov dl,41h
int 21h
endm
; === end of macro ===
.model small
.data
.code
pmain proc far
push ds ; 1 of 5 line required for .exe
mov ax,0 ; 2 clear ax by xor ax,ax
push ax ; 3 send ax to stack
mov ax,@data
mov ds,ax
helloa
ret
pmain endp
.stack 200h ; not required (if have, will not warning in link)
end pmain
|
4. การเขียนมากกว่า 1 macro
setproc macro
push ds ; 1 of 5 line required for .exe
mov ax,0 ; 2 clear ax by xor ax,ax
push ax ; 3 send ax to stack
mov ax,@data
mov ds,ax
endm
prtout macro
mov ah,9
lea dx,msg
int 21h
endm
; =============
; Main program
; =============
.model small
.data
msg db 'This is the program testing $'
.code
pmain proc far ; can not change far to near
setproc
prtout
ret
pmain endp
.stack 200h ; not required
end pmain
|
5. การเขียน macro เพิ่มค่าให้กับ al ทีละ 1 แล้วพิมพ์ โดยเรียก macro 5 ครั้ง
love macro
mov bl,01h
add al,bl
mov sum,al
mov dl,sum
mov ah,2
int 21h
endm
; =============
; Main program
; =============
.model small
.data
n db 30h
sum db ?
.code
pmain proc far ; can not change far to near
push ds ; 1 of 5 line required for .exe
mov ax,0 ; 2 clear ax by xor ax,ax
push ax ; 3 send ax to stack
mov ax,@data
mov ds,ax
mov al,n
love
love
love
love
love
love
pmain endp
end pmain
|
|
6. โปรแกรมพิมพ์ 1 ถึง 15 โดยใช้ 2 macro
- macro ชื่อ jack ใช้พิมพ์ 1 ถึง 9 โดยแยกตัวเลขละ 1 บรรทัด - macro ชื่อ jack ใช้พิมพ์ 10 ถึง 15 โดยใช้การแสดง 1 และ 0 ถึง 5 แยกกันคนละตัวอักษร - ผู้เรียนต้องเข้าใจว่า 30h คือเลข 0
jack macro
mov al,cl
mov bl,01h
add al,bl
mov sum,al
mov dl,sum
mov ah,2
int 21h
mov cl,al
lea dx,lf
mov ah,9
int 21h
endm
mary macro
mov dl,31h
mov ah,2
int 21h
mov dl,bl
mov ah,2
int 21
mov al,cl
mov bl,01h
add al,bl
mov sum,al
mov dl,sum
mov ah,2
int 21h
mov cl,al
lea dx,lf
mov ah,9
int 21h
endm
; =============
; Main program
; =============
.model small
.data
n1 db 30h
n2 db 2fh
last1 db 39h
last2 db 35h
lf db 0dh,0ah,'$'
sum db ?
.code
pmain proc far ; can not change far to near
push ds ; 1 of 5 line required for .exe
mov ax,0 ; 2 clear ax by xor ax,ax
push ax ; 3 send ax to stack
mov ax,@data
mov ds,ax
mov cl,n1
boy: jack
cmp cl,last1
jl boy
mov cl,n2
girl: mary
cmp cl,last2
jl girl
ret
pmain endp
.stack 10h
end pmain
|
|
7. รับตัวอักษร และเลือกด้วย CMP ไปทำ Macro
- ถ้ารับตัวอักษร a ก็จะแสดงตัวอักษร C - ถ้ารับตัวอักษรที่ไม่ใช่ a ก็จะไม่แสดงอะไรเลย burin1 macro
mov ah,2
mov dl,43h ; C
int 21h
endm
.model small
.data
.code
pmain proc far
push ds
mov ax,0
push ax
mov ax,@data
mov ds,ax
mov ah,8
int 21h
cmp al,61h ; a
je work1
jmp bye
work1: burin1
bye: ret
pmain endp
.stack 200h
end pmain
|
|
8. แปลงโปรแกรมเข้ารหัส และถอดรหัสส่วนหนึ่งของ Kailas Jagtap เป็น macro
- โปรแกรมนี้นำมาจาก http://www.thaiall.com/assembly/loopbasic.htm - มีต้นฉบับที่ http://www.laynetworks.com/Assembly%20Program7.htm โดย Kailas Jagtap - โปรแกรมนี้แบ่งเป็น 4 procedure และ 4 macro - ลบ Comment ออกเพื่อให้ดูสั้นลง - ปรับไปอยู่ใน word ที่ kailas.docx - http://www.thaiall.com/assembly/interrupt.htm - http://www.emu8086.com/assembler_tutorial/8086_bios_and_dos_interrupts.html ; ตัวอย่างการย้ายบางส่วนของโปรแกรมมาไว้ใน macro ; โปรแกรมนี้ ได้แยกการทำงาน readnext ที่ทำงานเหมือนกันแต่เขียนต่างกันไว้ คือ encrypt เขียน readnext ใน label ; แต่ decrypt จะเขียน readnext ออกมาเป็นอีก macro หนึ่ง เป็นการทำงานร่วมกันของ burin3 และ burin4 ; เขียนบล็อก http://www.thaiall.com/blog/burin/3691/ burin4 macro ; move readnext1 in macro mov ah,3fh ; อ่านข้อมูลที่ handle ไว้ เข้ามาในหน่วยความจำ 512 Bytes mov bx,handle mov cx,512 lea dx,buffer int 21h jc err_out1 ; ถ้าอ่านได้ จะทำให้ carry เป็น 0 mov save_ax,ax ; ค่าของ ax คือจำนวนไบท์ที่อ่านได้ cmp ax,0 je done4 ; ถ้ากระโดดไป แสดงว่าจบแฟ้ม เพราะขนาดของ ax = 0 call decorrupt mov ah,40h ; เขียนข้อมูลขนาดเท่า save_ax ลงไปใน newhandle mov bx,newhandle mov cx,save_ax lea dx,buffer ; ข้อมูลที่ผ่านการยกเลิกแผลงหรือไขว้ (decorrupt) มาแล้ว int 21h jc err_out1 ; ถ้าเขียนได้ จะทำให้ carry เป็น 0 jmp readnext1 ; กระโดดไปเริ่มอ่านข้อมูลต่อจากจุดเดิม endm burin3 macro ; move decr in macro call disp_nl mov ah,9 ; แสดงข้อความว่า รับชื่อแฟ้มที่ต้องการ DECRYPT lea dx,s3 int 21h lea dx,fname ; กำหนดชื่อแฟ้มอ้างอิง เมื่อรับผ่านแป้นพิมพ์ call getname mov ah,3dh ; เปิดแฟ้มข้อมูล lea dx,fname+2 mov al,0 int 21h mov handle,ax ; เก็บตำแหน่งอ้างอิงแฟ้ม jc err_out ; ถ้าเปิดได้ จะทำให้ carry เป็น 0 mov ah,9 ; แสดงข้อความว่า รับชื่อแฟ้มที่ต้องการ DECRYPT lea dx,s33 int 21h lea dx,newf1 ; กำหนดชื่อแฟ้มอ้างอิง เมื่อรับผ่านแป้นพิมพ์ call getname mov ah,3ch ; สร้างไฟล์ใหม่ lea dx,newf1+2 mov cx,0 int 21h mov newhandle,ax ; เก็บตำแหน่งอ้างอิงแฟ้ม jc err_out ; ถ้าสร้างได้ จะทำให้ carry เป็น 0 endm burin2 macro ; move encr in macro call disp_nl mov ah,9 ; แสดงข้อความว่า รับชื่อแฟ้มที่ต้องการ ENCRYPT lea dx,s2 int 21h lea dx,fname ; กำหนดชื่อแฟ้มอ้างอิง เมื่อรับผ่านแป้นพิมพ์ call getname mov ah,3dh ; เปิดแฟ้มข้อมูล lea dx,fname+2 mov al,0 int 21h mov handle,ax ; เก็บตำแหน่งอ้างอิงแฟ้ม jc err_out2 ; ถ้าเปิดได้ จะทำให้ carry เป็น 0 mov ah,9 ; แสดงข้อความว่า รับชื่อแฟ้มที่ต้องการ ENCRYPT lea dx,s22 int 21h lea dx,newf1 ; กำหนดชื่อแฟ้มอ้างอิง เมื่อรับผ่านแป้นพิมพ์ call getname mov ah,3ch ; สร้างไฟล์ใหม่ lea dx,newf1+2 mov cx,0 int 21h mov newhandle,ax ; เก็บตำแหน่งอ้างอิงแฟ้ม jc err_out ; ถ้าสร้างได้ จะทำให้ carry เป็น 0 readnext: mov ah,3fh ; อ่านข้อมูลที่ handle ไว้ เข้ามาในหน่วยความจำ 512 Bytes mov bx,handle mov cx,512 lea dx,buffer int 21h jc err_out ; ถ้าอ่านได้ จะทำให้ carry เป็น 0 mov save_ax,ax ; ค่าของ ax คือจำนวนไบท์ที่อ่านได้ cmp ax,0 je done1 ; ถ้ากระโดดไป แสดงว่าจบแฟ้ม เพราะขนาดของ ax = 0 call corrupt mov ah,40h ; เขียนข้อมูลขนาดเท่า save_ax ลงไปใน newhandle mov bx,newhandle mov cx,save_ax lea dx,buffer ; ข้อมูลที่ผ่านการ แผลงหรือไขว้ (corrupt) มาแล้ว int 21h jc err_out ; ถ้าเขียนได้ จะทำให้ carry เป็น 0 jmp readnext ; กระโดดไปเริ่มอ่านข้อมูลต่อจากจุดเดิม err_out2: jmp err_out endm burin1 macro ; move rpt_disp in macro mov ah,9 ; แสดงคำว่า E หรือ D lea dx,s1 int 21h mov ah,1 ; รับตัวอักษร 1 ตัว int 21h cmp al,'E' je encr ; กระโดดไปยัง encr (ENCRYPT) cmp al,'e' je encr cmp al,'D' je decr2 ; กระโดดไปยัง decr2 (DECRYPT) cmp al,'d' je decr2 cmp al,'X' je stop2 cmp al,'x' je stop2 mov ah,9 ; แสดงข้อความว่าตัวเลือกที่ส่งมา ไม่ถูกต้อง lea dx,s4 int 21h jmp rpt_disp endm .model small .data s0 db 0dh,0ah,'PROGRAM FOR FILE ENCRYPTION AND DECRYPTION ..By Kailas Jagtap$' s1 db 0dh,0ah,'Do you want to ENCRYPT(E) or DECRYPT(D) a file ? : $' s2 db 0dh,0ah,'Enter Name of File(to be encrypted): $' s22 db 0dh,0ah,'Enter Name of File(which will store encrypted data): $' s3 db 0dh,0ah,'Enter Name of encrypted File(to be decrypted): $' s33 db 0dh,0ah,'Enter Name of File(which will store decrypted data): $' s4 db 0dh,0ah,'***************** ERROR!!! - INVALID INPUT ****************** $' s44 db 0dh,0ah,'***************** ERROR IN FILE OPERATION !!!!!! ************ $' s5 db 0dh,0ah,'$' s6 db 0dh,0ah,'.............. File ENCRYPTED Successfully ! ................. $' s7 db 0dh,0ah,'.............. File DECRYPTED Successfully ! ................. $' fname db 80 db 0 db 80 dup(0) newf1 db 80 db 0 db 80 dup(0) save_ax dw 1 dup(0) buffer db 512 dup(0) endbuffer db '$' handle dw ? newhandle dw ? .code start: mov ax,@data mov ds,ax call disp_nl mov ah,9 lea dx,s0 int 21h rpt_disp: burin1 decr2: jmp decr1 stop2: jmp stop1 encr: burin2 decr1: jmp decr stop1: jmp stop done1: lea dx,s6 ; พิมพ์ว่า การเข้ารหัส สำเร็จลุล่วงไปด้วยดี jmp done3 done2: lea dx,s7 ; พิมพ์ว่า การถอดรหัส สำเร็จลุล่วงไปด้วยดี done3: mov ah,9 int 21h jmp done stop: mov ah,4ch int 21h getname proc near mov ah,0ah ; รับข้อมูล String จากแป้มพิมพ์ int 21h mov si,dx ; บันทึกตำแหน่งของชื่อแฟ้มที่รับจากแป้นพิมพ์ mov bl,[si+1] add si,02 sub bh,bh mov BYTE PTR[si+bx],0 ret getname endp err_out: mov ah,9 lea dx,s44 ; การดำเนินการกับแฟ้ม ผิดพลาด int 21h jmp stop done: mov ah,3eh ; ปิดแฟ้มให้เรียบร้อย ก่อนจบการทำงาน mov bx,handle int 21h mov bx,newhandle int 21h jmp stop done4: jmp done2 corrupt proc near lea si,buffer ; ส่งตำแหน่ง buffer ให้ si (Load effective adress) mov cx,save_ax ; ค่า cx คู่กับ loop บอกว่า จะให้ทำใน loop กี่รอบ again: mov al,[si] ; สำเนาค่าของ si ที่ตำแหน่งปัจจุบัน ให้กับ al add al,07h ; บวกอีก 7 ให้กับ al เช่นเดิมคือ a ก็จะเป็น h mov [si],al ; ส่งผลการ corrupt ไปแทนค่าในตำแหน่งเดิม inc si ; ตรวจ loop again ret corrupt endp err_out1: jmp err_out decr: burin3 readnext1: burin4 decorrupt proc near lea si,buffer ; ส่งตำแหน่ง buffer ให้ si (Load effective adress) mov cx,512 ; ค่า cx คู่กับ loop บอกว่า จะให้ทำใน loop กี่รอบ again1: mov al,[si] ; สำเนาค่าของ si ที่ตำแหน่งปัจจุบัน ให้กับ al sub al,07h ; ลบอีก 7 ให้กับ al เช่นเดิมคือ 8 ก็จะเป็น 1 mov [si],al ; ส่งผลการ corrupt ไปแทนค่าในตำแหน่งเดิม inc si loop again1 ret decorrupt endp disp_nl proc near mov ah,9 lea dx,s5 int 21h ret disp_nl endp .stack 200h end start |
|
| "Imagination is more important than knowledge" - Albert Einstein |