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
1. Một số lưu ý:
− Ngănxế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ănxếp gồm nhiều phần tử, mỗi phần tử là một từ (2 bytes).
− Vị trí của ngănxế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ănxếp rỗng, vị
trí được xác định bởi SP lúc đó là đáy ngăn xếp.
2. Khai báo:
.STACK <kích thước của ngăn xếp>
Ví dụ: khai báo một vùng ngănxếp có kích thước 256 bytes:
.STACK 100h
3. Các thao tác:
• Đưa trị vào (đỉnh) ngăn xếp:
PUSH <nguồn> ; đưa nguồn (thanh ghi hay từ nhớ
; 16 bit) vào đỉnh ngăn xếp
PUSHW <hằng> ; đư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 <đích> ; lấy giá trị (2 bytes) ở đỉnh ngănxế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ănxế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:
.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
1. Khai báo
2. 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
3. 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
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
Thủ tục
1. Khai báo:
<Tên thủ tục>PROC<Kiểu>;kiểu là NEAR(mặc định) hay FAR
; thân thủ tục
……………
RET
<Tên thủ tục> ENDP
Thủ tục thường được viết ở cuối chương trình.
2. Gọi thủ tục:
CALL <Tên thủ tục>
CALL <Địa chỉ> ; địa chỉ là thanh ghi hoặc vùng nhớ chứa địa chỉ
; thủ tục
3. 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ănxếp được lấy ra và được vào IP.
Do đó, nếu trong thủtục có thao tác với ngănxế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ự
.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
1. Khai báo
2. Gọi thủtục Nhap
CALL Xuat
IP = địa chỉ ô lệnh “pop bx”
3. Lưu lại địa chỉ quay về
BX = địa chỉ lệnh “CALL Xuat”
4. Nhập ký tự a,b:
00 62
00 61
5. Trả lại địa chỉ quay về
BX = địa chỉ lệnh “CALL Xuat”
CALL Xuat
00 62
00 61
6. 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.
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
Macro
1. 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ả.
2. Khai báo:
<tên macro> MACRO <các đối số>
; thân macro
……………
ENDM
3. 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
4. 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 <danh sách các nhãn, các biến cục bộ>
− 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 <“hello”,10,13>
@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
1. Nguyễn Minh Tuấn, Giáo trình hợp ngữ - Chương 6, ĐHKHTN, 2002
2. Randal Hyde, The art of assembly language programming – Chapter 11,12.
3. Norton Guide
4. 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
1. Có những cách nào để truyền tham số cho thủtục ? để nhận kết quả trả về ?
2. Thử viết một thủtục đệ quy.
3. 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ănxế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ệ.
. 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.
000h
100h
100h
100h
Thủ tục
1. Khai báo:
<Tên thủ tục& gt;PROC<Kiểu>;kiểu là NEAR(mặc định) hay FAR
; thân thủ tục
……………
RET
<Tên thủ tục& gt; ENDP
Thủ tục thường