Thực hành Assembly - Bài 3: Ngăn xếp - Thủ tục - Macro

Mục đích

 Hiểu được cơ chế hoạt động của ngăn xếp, quá trình gọi một thủ tục.

 Biết cách sử dụng ngăn xếp, khai báo và gọi thủ tục.

 Biết cách tạo và sử dụng macro.

 

doc7 trang | Chuyên mục: Vi Xử Lý – Vi Điều Khiển | Chia sẻ: dkS00TYs | Lượt xem: 16871 | Lượt tải: 1download
Tóm tắt nội dung Thực hành Assembly - Bài 3: Ngăn xếp - Thủ tục - Macro, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
Bài thực hành số 3
Ngăn xếp – Thủ tục – Macro
Mục đích
Hiểu được cơ chế hoạt động của ngăn xếp, quá trình gọi một thủ tục.
Biết cách sử dụng ngăn xếp, khai báo và gọi thủ tục.
Biết cách tạo và sử dụng macro.
Tóm tắt lý thuyết
Ngăn xếp
Một số lưu ý:
Ngăn xếp (Stack) là vùng nhớ đặc biệt được truy cập theo cơ chế “vào trước ra sau” (LIFO – Last In First Out), nghĩa là dữ liệu nào đưa vào sau sẽ được lấy ra trước.
Ngăn xếp gồm nhiều phần tử, mỗi phần tử là một từ (2 bytes).
Vị trí của ngăn xếp trong bộ nhớ được xác định bởi cặp thanh ghi SS:SP (SS chứa địa chỉ đoạn, SP chứa địa chỉ ô của đỉnh ngăn xếp). Khi chưa sử dụng, ngăn xếp rỗng, vị trí được xác định bởi SP lúc đó là đáy ngăn xếp.
Khai báo: 
.STACK	
 Ví dụ: khai báo một vùng ngăn xếp có kích thước 256 bytes:
	.STACK 	100h
Các thao tác:
Đưa trị vào (đỉnh) ngăn xếp:
PUSH	; đưa nguồn (thanh ghi hay từ nhớ 
; 16 bit) vào đỉnh ngăn xếp
PUSHW	; đưa trực tiếp một hằng16 bit vào 
; đỉnh ngăn xếp
PUSHF	; đưa nội dung thanh ghi cờ vào đỉnh ; ngăn xếp
Lấy trị (ở đỉnh) ra khỏi ngăn xếp:
POP	; lấy giá trị (2 bytes) ở đỉnh ngăn xếp 
; đưa vào đích (thanh ghi (trừ thanh 
; ghi IP) hay từ nhớ 16 bit)
POPF	; lấy giá trị (2 bytes) ở đỉnh ngăn xếp 
; đưa vào thanh ghi cờ
 	Chú ý : Các lệnh PUSH, PUSHF, POP và POPF không ảnh hưởng tới các cờ.
Ví dụ: Chương trình xuất chuỗi ngược dùng stack:
000h
…
0FCh
0FCh
SS:SP à
…
0FCh
0FCh
SS:SP à
000h
…
0FCh
0FCh
SS:SP à
000h
100h
000h
…
0FCh
0FCh
100h
SS:SP à
…
0FCh
0FCh
SS:SP à
000h
100h
…
0FCh
0FCh
SS:SP à
000h
100h
…
0FCh
0FCh
SS:SP à
000h
100h
100h
100h
.model small
.stack 100h
.data
	msg1	DB 'Nhap vao 1 chuoi: $'
	msg2 	DB 10,13,'Chuoi nghich 	dao la: $'
.code
	mov	ax,@data
	mov	ds,ax
	mov	ah,9
	lea	dx,msg1
	int 	21h
	mov	cx,0
nhap:	
	mov 	ah,1
	int 	21h
	cmp 	al,13
	je	thongbaoxuat
	xor	ah,ah
	push	ax
	inc	cx
	jmp	nhap
thongbaoxuat:
	mov	ah,9
	lea	dx,msg2
	int	21h
xuat:	
	pop	ax
	mov	dl,al
	mov	ah,2
	int 	21h
	loop	xuat
	mov	ah,4ch
	int 	21h
END
Khai báo
Nhập lần lượt a,b,c đưa vào ngăn xếp:
 Nhập ký tự ‘a’:
00
61
 Nhập ký tự ‘b’:
00
62
00
61
Nhập ký tự ‘c’:
00
63
00
62
00
61
Xuất các giá trị trong ngăn xếp
 Xuất ký tự ‘c’:
00
63
00
62
00
61
 Xuất ký tự ‘b’:
00
62
00
61
 Xuất ký tự ‘a’:
00
61
Thủ tục
Khai báo:
	PROC	;kiểu là NEAR(mặc định) hay FAR
	; thân thủ tục
	……………
	RET
 ENDP
	Thủ tục thường được viết ở cuối chương trình.
Gọi thủ tục:
CALL 
CALL ; địa chỉ là thanh ghi hoặc vùng nhớ chứa địa chỉ 
 ; thủ tục
Hoạt động của lời gọi thủ tục:
Khi thực hiện lời gọi thủ tục (CALL) thì:
Địa chỉ ô của lệnh kế lệnh CALL (*) sẽ được cất vào ngăn xếp
Địa chỉ ô của lệnh đầu tiên trong thủ tục được đưa vào IP
Khi thực hiện lệnh RET để quay về trình gọi thì:
Địa chỉ trong ngăn xếp được lấy ra và được vào IP.
Do đó, nếu trong thủ tục có thao tác với ngăn xếp thì trong thủ tục, trước khi thao tác với ngăn xếp ta nên lưu lại địa chỉ (*) ở trên (chính là giá trị hiện thời trong ngăn xếp) để quay trở về trình gọi. Xem mô tả trong ví dụ sau.
Ví dụ: Nhập xuất chuỗi kí tự
000h
…
0FCh
0FCh
100h
SS:SP à
…
0FCh
0FCh
SS:SP à
000h
100h
000h
…
0FCh
0FCh
100h
SS:SP à
…
0FCh
0FCh
SS:SP à
000h
100h
000h
…
0FCh
0FCh
100h
SS:SP à
000h
…
0FCh
100h
0FCh
SS:SP à
.model small
.stack 100h
.code
	CALL Nhap
	CALL Xuat
	mov	ah,4ch
	int	21h
;---------------------------------------------------
Nhap PROC
	pop	bx
	mov	ah,2
	mov	dl,’?’
	int	21h
	xor	cx,cx
nhap:
	mov 	ah,1
	int 	21h
	cmp 	al,13
	je	ketthucnhap
	push	ax
	inc	cx
	jmp	nhap
ketthucnhap:
	push	bx
	RET
Nhap ENDP
;---------------------------------------------------
Xuat PROC
	pop	bx
	mov	ah,2
	mov	dl,13
	int	21h
	mov	dl,10
	int	21h
	jcxz	ketthucxuat
xuat:
	pop	dx
	int	21h
	loop	xuat
ketthucxuat:
	push	bx
	RET
Xuat ENDP
END
Khai báo
Gọi thủ tục Nhap
CALL Xuat
	IP = địa chỉ ô lệnh “pop bx”
Lưu lại địa chỉ quay về
	BX = địa chỉ lệnh “CALL Xuat”
Nhập ký tự a,b:
00
62
00
61
Trả lại địa chỉ quay về
	BX = địa chỉ lệnh “CALL Xuat”
CALL Xuat
00
62
00
61
Kết thúc thủ tục Nhập:
00
62
00
61
	IP = địa chỉ ô lệnh “CALL Xuat”
Lời gọi thủ tục xuất (CALL Xuat) cũng hoạt động tương tự như trên.
Macro
Một số lưu ý:
Khi chúng ta có nhiều đoạn code giống nhau, chúng ta có thể sử dụng macro để thay thế, giống như chúng ta dùng define ở trong C.
Bản chất là thay thế lời gọi macro bằng các lệnh trong thân macro.
Các macro nên phục hồi những thanh ghi mà nó sử dụng trừ những thanh ghi chứa kết quả.
Khai báo:
	MACRO	
 	; thân macro
	……………
 	ENDM 
Hai cách sử dụng macro
Tạo macro trực tiếp trong chươnng trình: 
Các macro thường được khai báo ở đầu chương trình trước phần .code.
Ví dụ: Xuất một chuỗi ra màn hình sử dụng macro
.model	small
.stack 100h
.data
	chuoi1 db “hello”,10,13,’$’
	chuoi2 db “bye”,10,13,’$’
@xuatchuoi macro chuoi
	lea dx,chuoi
	mov ah,9
	int 21h
endm
.code
	…
	@xuatchuoi chuoi1
	@xuatchuoi chuoi2
	…
end
Xây dựng thư viện các macro:
Tạo 1 thư viện (tập tin) chứa các macro
include vào chương trình (thường trước phần .code) bằng lệnh include
Ví dụ: Xuất một chuỗi ra màn hình sử dụng thư viện macro
THUVIEN.INC
@xuatchuoi macro chuoi
	lea dx,chuoi
	mov ah,9
	int 21h
endm
TestMacro.asm
.model	small
.stack 100h
.data
	chuoi1 db “hello”,10,13,’$’
	chuoi2 db “bye”,10,13,’$’
INCLUDE THUVIEN.INC
.code
	…
	@xuatchuoi chuoi1
	@xuatchuoi chuoi2
	…
end
Các thành phần cục bộ của macro:
Trong macro, ta cũng có thể khai báo các biến, nhãn cục bộ để tránh gây ra lỗi khi gọi macro nhiều lần.
Cú pháp :
LOCAL 
Ví dụ: Xuất một chuỗi hằng ra màn hình sử dụng macro với biến cục bộ
.model	small
.stack 100h
@xuatchuoi macro chuoi
 LOCAL chuoicucbo, nhancucbo
 .data
	chuoicucbo db chuoi,’$’
 .code
	lea dx,chuoicucbo
	mov ah,9
	int 21h
endm
.code
	…
 nhancucbo:
	…
	@xuatchuoi 
	@xuatchuoi ”bye”
	…
end
Lưu ý: nếu cần truyền chuỗi phức tạp thì ta cần sử dụng để báo cho trình biên dịch biết đây là một đối số.
Tài liệu tham khảo
Nguyễn Minh Tuấn, Giáo trình hợp ngữ - Chương 6, ĐHKHTN, 2002
Randal Hyde, The art of assembly language programming – Chapter 11,12.
Norton Guide
Dan Rollins, TechHelp v.6.0
Bài tập
Bài 1: Viết chương trình kiểm tra một biểu thức đại số có chứa các dấu ngoặc (như (), [] và {}) là hợp lệ hay không hợp lệ . 
Ví dụ: 
	(a + [b – { c * ( d – e ) } ] + f)
 là hợp lệ nhưng
	(a + [b – { c * ( d – e )] } + f)
 là không hợp lệ. 
Bài 2: Tính giá trị biểu thức đã nhập ở bài tập 2 theo thứ tự từ trái sang phải.
Bài 3: Viết lại các bài tập tuần trước dưới dạng các thủ tục
Bài 4: Xây dựng một thư viện các macro
Mở rộng
Có những cách nào để truyền tham số cho thủ tục ? để nhận kết quả trả về ? 
Thử viết một thủ tục đệ quy.
Tìm hiểu cách phân chia chương trình thành nhiều file và cách biên dịch, liên kểt chúng.
Hướng dẫn
Bài 1. dùng ngăn xếp để PUSH các dấu ngoặc trái ( ‘(‘, ’{‘, ‘[‘ ) vào ngăn xếp. Nếu gặp dấu ngoặc phải ( ‘)’, ‘}’, ‘]’ ) thì POP từ stack ra. Nếu không POP được, hoặc POP ra không đúng loại với dấu ngoặc phải -> không hợp lệ . Ngược lại là biểu thức hợp lệ.

File đính kèm:

  • docThực hành Assembly - Bài 3 Ngăn xếp - Thủ tục - Macro.doc