Ví dụ ORG 100h: đoạn mã lệnh bắt đầu ở địa chỉ 100h,Code_seg: segment: tên Code_seg là đại diện cho 1 segment trong bộ nhớ • Chương trình được viết bằng các ký hiệu của ngôn ngữ Assembly
Trang 1Giới thiệu về Assembly Language (Hợp ngữ)
……… , tháng … năm …….
Trang 2BÀI 1 : MỞ ĐẦU
I Giới thiệu về Assembly Language (Hợp ngữ)
1 Giới thiệu về Assembly Language (Hợp ngữ)
Việc lập trình bằng ngôn ngữ máy đòi hỏi người lập trình cần phải nhớ các mã lệnh bằng số, phải sắp đặt vị trí của mã lệnh và tất cả các số liệu trong bộ nhớ của máy tính, ngay cả các số liệu cũng phải viết dưới dạng số Công việc này hết sức nặng nhọc và rất dễ gây nhầm lẫn
Chính vì vậy người ta cần đến Assembly Language, nó cho NSD các khả năng sau:
• Cho phép dùng các ký hiệu gợi nhớ thay cho các mã lệnh bằng số của bộ VXL, ví dụ ADD thay cho 00000000; INT 13h thay cho 11001101
00010011 v.v các ký hiệu loại này được gọi là mã lệnh (Op-Code)
• Cho phép dùng các tên gọi (nhãn: Label) để chỉ các địa chỉ nhớ, NSD gọi đến các tên này như việc gọi các thủ tục hoặc như là việc truy nhập đến các biến hay hằng số trong các ngôn ngữ lập trình bậc cao
• Cho phép dùng các chỉ thị cho chính Assembler (Assembler Directive),
để nó biết cần phải chuyển các mã của NSD như thế nào, chương trình bắt đầu
ở đâu; dự trữ khoảng trống bao nhiêu cho dữ liệu; báo rằng không còn lệnh để chuyển mã ngữ tiếp nữa v.v Ví dụ ORG 100h: đoạn mã lệnh bắt đầu ở địa chỉ 100h,Code_seg: segment: tên Code_seg là đại diện cho 1 segment trong bộ nhớ
• Chương trình được viết bằng các ký hiệu của ngôn ngữ Assembly được gọi là chương trình nguồn (Source Program) Chương trình ở dạng số tương tương với chương trình nguồn mà bộ VXL có thể hiểu được (microprocessor-
Trang 3compatible form) gọi là chương trình đích(Object Program) Assembler là chương trình thực hiện chuyển (convert) chương trình nguồn(Source Program) thành chương trình đích (Object Program).
2 Một số vấn đề về hệ đếm 2, số có dấu, số bù 2
2.1 Hệ đếm 2
Như ta đã biết, các phần tử nhớ cơ bản cấu tạo nên bộ nhớ cũng như các phần
tử trong khối tính toán của máy tính đều là các phần tử có 2 trạng thái cân bằng ổn định 'on' và 'off' (ta có thể dùng để biểu diễn số 1 và 0) giống như trạng thái đóng mạch và cắt mạch của một cái công tắc điện Tất cả chương trình và số liệu mà chương trình sử dụng đều đặt trong bộ nhớ trước khi được bộ VXL đọc Như vậy sự kết hợp của một dãy các số 0 và 1 có thể biểu diễn bất cứ con số nào Hệ đếm chỉ sử dụng các số 0 và 1 được gọi là hệ nhị phân (Binary numbering system) hay hệ đếm
2 , đó là hệ đếm cơ sở cho mọi loại MTĐT ngày nay
Một phần tử nhớ chỉ có 1 trong hai giá trị 0, 1 được gọi là 1 bit, đó là chữ viết tắt của Binary digit Cũng tương tự như trong hệ thập phân, trong một số nhị phân giá trị của mỗi bit trong con số phụ thuộc vào vị trí của nó trong con số đó như được thể hiện sau đây:
7 6 5 4 3 2 1 0 vị trí bit trong con số
x x x x x x x x
27 26 25 24 23 22 21 20 trọng số của bit
128 64 32 16 8 4 2 1 giá trị tương ứng trong hệ thập phân
Để chuyển một số từ hệ thập phân sang hệ nhị phân ta thực hiện một loạt các phép MOD 2 đối với số đó cho tới khi số thập phân bằng 0:
• Giá trị của phép tính MOD 2 đầu tiên là giá trị của bit 0
• Giá trị của phép tính MOD 2 tiếp theo là giá trị của bit 1.v.v Trong các lĩnh vực tin học, thường sử dụng một đơn vị lớn hơn, đó là byte, 1 byte gồm 8 bit, như vậy 1 byte có thể biểu diễn một con số có giá trị từ 00000000 đến 11111111 (0 - 255 trong hệ thập phân)
Ngoài ra còn có các đơn vị 1KB = 210 byte, 1MB = 220 byte
2.2 Số có dấu
Khi sử dụng 1 byte để biểu diễn số có dấu, người ta chỉ sử dụng 7 bit thấp để biểu diễn số, còn bit cao nhất (bit 7) để biểu diễn dấu của con số đó, nếu bit này = 0 thì con số là dương, nếu bit này = 1 thì con số là âm Như vậy với 1 byte có thể biểu diễn các số từ -128 đến +127
Theo quy ước này số -1 có giá trị như sau: 10000001 nếu ta đem cộng
với 1 thì kết quả lại = 10000010 = -2D! không như chúng ta chờ đợi là = 0; chính vì
lý do này mà người ta phải dùng một dạng số đặc biệt - dạng bù 2 (two's complemented) để biểu diễn số âm
Trang 4Để tìm dạng biểu diễn nhị phân của một số âm (nghĩa là tìm dạng bù 2 của nó),
ta chỉ việc lấy số dương tương ứng rồi đảo giá trị các bit, sau đó cộng 1 vào kết quả
là xong Thí dụ tìm biểu diễn nhị phân của số -1: 0000 0001 đảo các bit thành 1111
1110, đem cộng thêm 1 trở thành 1111 1111.Nếu ta đem số -1 này cộng với +1 thì kết quả là 1 0000 0000, ta lờ số nhớ (1) đi thì được số 0000 0000 như mong muốn!
đó là cách biểu diễn số âm trong máy tính!
Nhìn vào số âm dạng bù 2 ta khó mà hiểu được số thập phân (âm) tương ứng bằng bao nhiêu, nếu muốn tính, ta vẫn áp dụng quy tắc trên để tính được số dương tương ứng.Thí dụ muốn biết 1101 0000 có giá trị thập phân tương ứng bằng bao nhiêu?
Ngay từ khi máy tính điện tử mới ra đời, người lập trình cũng đã thường thao tác trên từng nhóm bit chứ không phải trên từng bit Các bộ VXL đầu tiên là loại 4 bit, vì thế người ta có thể nhóm 4 bit lại và biểu diễn bằng một ký hiệu duy nhất Với
4 bit có thể biểu diễn 16 giá trị khác nhau, người ta dùng các ký hiệu 0 9, A, B, C, D,
E, F để biểu diễn các giá trị nhị phân từ 0000 đến 1111 Hệ đếm như vậy được gọi là
hệ thập lục phân (hệ đếm cơ số 16) - hexadecimal numbering system
3 Một số vấn đề cần nhắc lại (sau giáo trình CTMT) về bộ VXL
Các Mode làm việc: Các bộ VXL 80286 (và các bộ VXL mới hơn của INTEL)
có thể hoạt động trong 2 mode khác nhau: Real Address Mode và Protected Virtual Address Mode
• Real Address Mode : Trong Mode này 80286 hoạt động cũng giống như 8086, nhưng thực hiện các chương trình nhanh hơn từ 2 đến
5 lần, nó hỗ trợ tất cả các lệnh của 8086, thêm vào đó là các lệnh của riêng 80286 Khi chúng ta mới bật máy, 80286 bắt đầu ở Mode này, chỉ khi nào chương trình ra lệnh cho nó chuyển sang Mode kia (Protected Mode)
• Protected Mode : Trong Mode này 80286 vẫn có mọi tính năng như ở Real Address Mode nhưng được thêm vào một số tính năng tinh
vi để bảo vệ dữ liệu và quản lý bộ nhớ Tính năng nổi bật nhất của Mode này là nó cho phép 80286 truy cập một bộ nhớ rất lớn (so với 8086) bằng cách sử dụng một kỹ thuật gọi là Virtual Addressing.Bằng
kỹ thuật này 80286 có thể làm việc với 2 loại bộ nhớ: không gian địa chỉ vật lý (Physical address space) và không gian địa chỉ ảo (Virtual address space)
1 Không gian địa chỉ vật lý là miền bộ nhớ mà 80286 có thể làm việc với nó tại một thời điểm, bằng 224 = 16MB
Trang 52 Không gian địa chỉ ảo là miền bộ nhớ mà 80286 có thể đánh địa chỉ, bằng 230 = 1GB (1 Giga byte) Thuật ngữ ảo (Virtual) được sử dụng bởi vì nếu một chương trình cần truy cập bộ nhớ mà địa chỉ không thuộc không gian địa chỉ nhớ vật lý, hệ điều hành có thể sử dụng khả năng quản lý
bộ nhớ của 80286 để chuyển đổi (swap) một phần thích hợp (applicable piece) của bộ nhớ ảo Việc chuyển đổi bộ nhớ (swapping) này người lập trình không thấy được vì vậy anh ta có thể viết chương trình truy cập bất cứ địa chỉ nhớ nào trong toàn bộ không gian địa chỉ lớn đến 1GB Virtual Disk từ Version 3.0 trở lên, DOS hỗ trợ việc sử dụng bộ nhớ trên 1MB, ta có thể sử dụng nó như 'Virtual Disk' (đĩa
ảo hay RAM Disk) Để truy cập vùng nhớ cao này, bộ VXL tạm thời (momentarily) chuyển (switch) sang Protected Mode, thực hiện việc (vận) chuyển dữ liệu rồi lại chuyển trở về Real Mode như bình thường Kết quả chung là ta có thể sử dụng một bộ nhớ RAM có kích thước lớn, tốc độ thao tác cực nhanh so với tốc độ thao tác trên đĩa * Protected Mode được người thiết kế OS quan tâm, với người lập trình bình thường chỉ cần quan tâm tới Real Mode là đủ
Trang 6CMP dest, src so sánh (bằng cách trừ, nhưng không làm thay đổi dest và src) để đặt các cờ hiệu là nhớ, tràn, v.v
MUL src nhân AL hay AX với một số dương (không có dấu) là src (src là reg/mem)
AX:= (AL*src8); DX:AX:=(AX*Immed16)
IMUL src nhân AL hay AX với một số nguyên có dấu
DIV src chia AL hoặc AX cho giá trị trong reg/mem không dấu nếu chia cho 0 hoặc kết quả quá lớn sẽ gây ra INT 0
AL < (AX*src8); AH < (AX MOD src8)
AX < (DX:AX*src16); DX < (DX:AX MOD src16)
IDIV src chia AL hoặc AX cho giá trị trong reg/mem có dấu CBW đổi byte thành Word
AL mở rộng theo dấu vào AH
AH được điền đầy theo bit 7 của AL
CWD đổi Word thành Word
AX mở rộng theo dấu vào DX
DX được điền đầy theo bit 15 của AX
.v.v
2/ Các lệnh logic
AND dest,src : nhân logic từng bit trong dest và src
OR dest,src : OR logic từng bit trong dest và src
XOR dest,src : XOR logic từng bit trong dest và src
NOT dest : đảo từng bit trong dest (lấy bù 1)
.v.v
3/ Các lệnh vận chuyển số liệu
MOV dest,src : copy dữ liệu từ src (reg/mem) tới dest Lưu ý rằng không thể MOV
từ ô nhớ (mem) vào ô nhớ
XCHG dest,src đổi (chỗ) giá trị giữa 2 thanh ghi hoặc giữa thanh ghi và bộ nhớ
IN Port8 (or DX) nhận dữ liệu từ cổng vào AL hay AX
không phải dữ liệu chứa trong mem1
( nạp kết quả việc tính toán EA của địa chỉ tương đối vào
reg16)
PUSH src cất giá trị thanh ghi 16 bit (hoặc r/mem16) vào stack PUSH immed cất giá trị 16 bit (hoặc 8 bit mở rộng dấu) vào stack
PUSHF cất giá trị của thanh ghi cờ vào stack
POP dest chuyển giá trị từ stack vào dest (reg16 hoặc r/mem
hoặc thanh ghi đoạn)
POPF chuyển giá trị từ stack vào thanh ghi cờ
Trang 74/ Các lệnh thao tác trên xâu ký tự
CLD Clear direction flag to UP (DF:=0)
string Ops auto-increment
STD set direction flag to Down (DF:=1)
string Ops auto-decrement
5/ Các lệnh điều khiển sự thực hiên chương trình
JMP short/near/far target nhảy không điều kiện đến nhãnshort : IP (IP + (target displacement sign-extended))
báo cho assembler là nhãn đích của lệnh nhảy JMP không xahơn 127 bytes kể từ địa chỉ của lệnh tiếp theo
near : IP (IP + (target displacement)
far : SS target_seg; IP target_offset
indirect : IP (register or value in memory)
JCXZ: nhảy tới nhãn khi CX=0, không kiểm tra cờ
CLD clear direction flag
(các lệnh với xâu ký tự tự động tăng)
Trang 8(chưa đưa vào chương trình phần này) 3 Phân tích một số mã lệnh - Trong hệ lệnh của 8088/8086 có nhiều lệnh tính chất giống nhau,
chỉ khác nhau ở địa chỉ của các toán hạng Chính vì vậy có những
lệnh chỉ cần 1 byte mã lệnh là đủ để bộ VXL thực hiện, lại có những
lệnh cần thêm một số thông tin nữa mới có thể thực hiện được, các thông tin này được chứa trong 1 byte, đi ngay sau byte mã lệnh thứ nhất Việc xác định xem 1 lệnh nào đó có cần đọc thêm byte lệnh thứ 2
hay không được bộ giải mã lệnh quyết định - Ta phân tích lệnh ADD làm ví dụ:
Có các khả năng sau đối với việc cộng 2 toán hạng
1/ r/m r8 : cộng nội dung thanh ghi 8 bit vào một thanh ghi
hay 1 ô nhớ
2/ r/m r16 : cộng nội dung một thanh ghi 16 bit và một thanh
ghi 16 bit hoặc vào (2) ô nhớ
3/ r8 r/m cộng nội dung từ thanh ghi (8 bit) hoặc từ 1 ô nhớ (tất nhiên là 8 bit) vào
1 thanh ghi 8 bit
4/ r16 r/m cộng nội dung một thanh ghi hoặc ô nhớ vào 1
thanh ghi 16 bit
5/ AL im8 cộng trực tiếp 1 giá trị 8 bit vào AL
6/ AX im16 cộng trực tiếp 1 giá trị 16 bit vào AX
7/ r im8 hoặc im16; trường hợp này r # AX
Cấu tạo của mã lệnh như sau:
1/ trường hợp 1 d: direction
reg/memory with reg to either = 1: 'to' reg
= 0 : 'from' reg
0 0 0 0 0 0 d w mod reg r/m w : word operation
= 1 : with word = 0: with byte
mã lệnh này chứa đựng các khả năng:
1 0 0 0 0 0 s w mod 0 0 0 r/m data data
byte 1 byte 2 nếu
Trang 9byte 1 byte 2 nếu
s:w = 01
mã lệnh này chứa đựng các khả năng:
nêu ở trên
III Cấu tạo của lệnh, các Mode địa chỉ của Assembly Language
Trên thị trường có một số Assembler, trong tài liệu này chúng ta sử dụng
MACRO ASSEMBLER (MASM); về MASM sẽ được đề cập ở bài 2
1 Cấu tạo của lệnh
nhãn Mã lệnh các toán hạng ghi chú
Data: MOV cx,ax ;nạp vào cx giá trị trong ax
- Trường nhãn (label field), Nhãn dài tối đa 31 ký tự ấn định một tên đại diện cho 1 lệnh assembly, để cho các lệnh khác có thể dùng tên này thay cho địa chỉ của lệnh đó trong bộ nhớ
Nhãn không được bắt đầu bằng 1 con số, không chứa dấu phân cách, nhãn kết thúc bằng dấu:; trong nhãn có thể có các ký tự '$', '?', '@','_' - Mã lệnh (Op-code) dài từ 2-7 ký tự, là những chữ viết tắt gợi trí nhớ, để chỉ các lệnh của bộ vxl Mã lệnh có thể đứng liền sa dấu ': ' của nhãn hoặc phân cách bởi 1 số dấu cách (space) Giữa mã lệnh
và các toán hạng phải có một số dấu cách - Các toán hạng (operands): báo cho MPU biết phải tìm các toán hạng ở đâu - các ghi chú (comments) dùng để diễn giải dòng lệnh trong chương trình, để đọc lại cho dễ hiểu hơn Trong các chương trình dài các chú thích rất quan trọng và cần thiết
ghi chú phải đi sau ký hiệu ';' và kết thúc bởi dấu xuống dòng (Enter)
2 Các Mode địa chỉ
- Phương pháp xác định vị trí trong bộ nhớ của của 1 toán hạng được gọi là Mode địa chỉ (Addressing Mode) Mode địa chỉ của một toán hạng phụ thuộc vào vị trí trong bộ nhớ của dữ liệu ứng với toán hạng đó Có một số cách phân loại Mode địa chỉ khác nhau, dưới đây nêu ra hai trong các cách đó: - Cách thứ nhất: chia làm 3 loại Mode địa chỉ:
1 Mode địa chỉ tức thời (Immediate Addressing Mode): sử dụng chính
giá trị bằng số ở vị trí của toán hạng
ví dụ mov ax,0001h
trong mode địa chỉ này phải có 1 vị trí nhớ hay thanh ghi làm
destination.(số chu kỳ máy cần thiết tương ứng là 10 và 4)
2 Mode địa chỉ thanh ghi (register addressing mode) cả dest và src
đều là thanh ghi Vì cả hai đều ở bên trong MPU nên được thực hiện rất
nhanh
ví dụ mov ax,cx cần 2 chu kỳ máy
3 Mode địa chỉ bộ nhớ (Memory Addressing Mode)
dest hoặc src là địa chỉ nhớ (hay nhãn cũng vậy)
có 2 loại mode địa chỉ bộ nhớ:
1 Địa chỉ trực tiếp (direct)
2 Địa chỉ gián tiếp (indirect)
-direct: dest hoặc src là một địa chỉ nhớ được xác định bằng số địa
chỉ hoặc nhãn
Trang 10ví dụ: mov ax, mem1 thì nội dung ô nhớ có nhãn mem1 được chuyển
Có một số biến cách của mode gián tiếp này, tuy vậy ý nghĩa cơ bản
không khác nhau - Cách thứ 2: chia làm 7 Mode địa chỉ
1 Register addressing địa chỉ thanh ghi
thí dụ MOV AX,BX
2 Immediate addressing địa chỉ tức thời
MOV CL,-30; MOV CL, PI (PI EQU 3.14)
3 Direct addressing địa chỉ trực tiếp
thí dụ MOV AX,TABLE (trong đó TABLE là một nhãn)
4 Register indirect addressing địa chỉ gián tiếp thanh ghi
MOV AL, TABLE[DI] (trong đó TABLE là một tên của 1 byte (tên biến)
7 Base indexed addressing địa chỉ được chỉ số hoá cơ sở
MOV AX, [BX][DI+2] IV Các chỉ thị cho Assembler (Assembler Directives)
(có khoảng 60)
Các chỉ thị Assembler trông rất giống các mã lệnh ngôn ngữ Assembly, mỗi chỉ thị gồm có 4 trường (Fields)
tên Chỉ thị đối số (argument) ghi chú
PI EQU 3.14 ;xác định giá trị của PI
- tên (name field) cũng giống như trường nhãn trong dòng lệnh
có chỉ thị assembler cần trường tên, có chỉ thị không cần, tên bắt đầu bằng chữ cái, kết thúc bằng khoảng trống - Chỉ dẫn Assembler (directive field)
cũng tương tự như Op_code trong dòng lệnh
bắt đầu bằng khoảng trống và kết thúc bằng khoảng trống hoặc xuống dòng - argument field: chứa 1 địa chỉ nhớ hoặc 1 số để sử dụng cùng với chỉ thị
và do chỉ thị xác định
bắt đầu bằng khoảng trống và kết thúc bằng xuống dòng
*trong các chương trình đơn giản thường dùng các chỉ thị sau:
ASSUME chỉ định các thanh ghi đoạn; giúp Assembler đổi các nhãn thành các địa chỉ bằng cách báo cho Assembler biết ta định
dùng thanh ghi đoạn nào để đánh địa chỉ các nhãn này
format: ASSUME Seg-reg: Seg-name [, ]
trong đó Seg-reg là một trong các thanh ghi đoạn sau DS, CS,
ES, SS; Seg-name là tên sẽ đứng trước chỉ thị SEGMENT
thí dụ assume cs: cseg, ds: dseg
SEGMENT Định nghĩa đoạn
Trang 11Dạng chung: SEGMENT COMBINE-TYPE ALIGN_TYPE CLASS ALIGN_TYPE: chỉ ra biên của segment bắt đầu ở đâu trong bộ nhớ.
- BYTE: begin anywhere
- WORD: begin at an even-numbered address (word)
- PARA: begin at an address divisible by 16
- PAGE: begin at an address divisible by 256
COMBINE_TYPE: chỉ ra một Segment sẽ được kết hợp với các Segment khác có cùng tên như thế nào Một chương trình có thể sử
dụng 4 Segment: Data, Code, Extra và Stack
Code, Data và Extra có thể được nối lại (joined) với nhau
(PUBLIC) hoặc trùm lên nhau (Overlapped) (COMMON)
Stack Segment nhất thiết phải có kiểu STACK
CLASS TYPE: ảnh hưởng tới thứ tự sắp đặt các Segment trong bộ nhớ Các Segment
có cùng tên Class được sắp đặt liên tiếp, Các Segment khác tên Class được sắp đặt theo thứ tự mà
chương trình LINK gặp
- CODE - DATA
- EXTRA
Với SEGMENT directive ta có thể dùng như sau:
với DATA SEGMENT: SEGMENT PARA PUBLIC 'DATA' với CODE SEGMENT: SEGMENT PARA PUBLIC 'CODE'
với EXTRA SEGMENT: SEGMENT PARA PUBLIC 'EXTRA' với STACK SEGMENT: SEGMENT PARA STACK 'STACK'
ENDS nơi kết thúc đoạn hay cấu trúc SEGMENT và ENDS chỉ đánh dấu điểm đầu
và điểm cuối của một Segment, chúng không cho Assembler biết đang định nghĩa loại Segment gì; việc này là
nhiệm vụ của Pseudo-Op: ASSUME
ORG địa chỉ khởi đầu của chương trình
DB định vùng dữ liệu dạng byte
DW định vùng dữ liệu dạng word
DD định vùng dữ liệu dạng 2 word, thí dụ DD 0 nghĩa là 4 byte
bằng 0
DUP lặp lại dữ liệu
EQU Equate: gán tên cho một hằng số (kiểu số hoặc kiểu String) tên này vĩnh viễn nhận giá trị hằng số đó (khác với
Directive = ') thí dụ PI EQU 3.14
Message EQU 'Hay vao so lieu'
PUBLIC khai báo tên dùng chung, làm cho 1 hoặc nhiều symbol đã được ĐN có thể được dùng chung trong nhiều Module mà các Module
đó sẽ được Linked với Module chứa khai báo PUBLIC này
Trang 12format: External name: type[, ]
Như EXTRN get_hex
chỉ ra các SYMBOL đã được định nghĩa trong Modul
get_hex
- NAME là một Symbol đã được định nghĩa và được mô tả là
PUBLIC ở một Modul hợp ngữ khác
- TYPE có thể là một trong các kiểu sau:
+ nếu NAME là một ký hiệu trong DATA SEGMENT, EXTRA
SEGMENT thì kiểu có thể là BYTE, WORD hoặc DWORD
+ nếu NAME là một nhãn thủ tục thì kiểu có thể là NEAR
hoặc FAR
+ nếu NAME là một hằng được định nghĩa bởi EQU, =, thì
kiểu phải là ABS
* chú ý:
PUBLIC và EXTRN thường được sử dụng để phân chia các thủ tục Chẳng hạn để chạy một thủ tục có tên là SORT từ chương trình chính thì MODUL trong đó định nghĩa SORT phải chứa khai báo PUBLIC SORT và MODUL chính có chứa lời gọi tới SORT
phải có chứa khai báo:
EXTRN SORT: NEAR (hoặc FAR)
PROC và ENDP đánh dấu chỗ bắt đầu và chỗ kết thúc thủ tục Thủ tục là một khối các chỉ thị (instructions) có thể được gọi thực
hiện từ các vị trí khác nhau trong chương trình
END nơi kết thúc chương trình nguồn
Dạng: END Nhãn điểm vào chương trình (nhãn của lệnh đầu
tiên của chương trình)
Nếu chương trình của ta có chứa nhiều MODUL, ta (phải) gán nhãn cho chỉ dẫn END ở cuối MODUL chương trình chính, còn trong các MODUL phụ khác nhau không được gán nhãn cho chỉ
dẫn END
*sau đây là bảng các chỉ thị cho assembler
AND và logic, ví dụ: mov ax,7 and 8 BYTE định dữ liệu dài 1 byte COMMENT bắt đầu của lời bình CREF cross reference:danh sách các ký hiệu dùng để tham chiếu chéo CGROUP
(TLTK, bản dịch của LNH, trg 44) DGROUP
(TLTK, bản dịch của LNH, trg 44) DQ define quadruple:định vùng dữ liệu dạng 4 word
như DQ 0:tám byte 0 DT define ten: định vùng dữ liệu dạng 10 byte
như DT 0: mười byte 0 DW define word: định vùng dữ liệu dạng word (2 byte) DWORD double word: định dữ liệu dài 2 word
như: JMP DWORD PTR[SI] DUP Duplicate: lặp lại một xâu Như 10 DUP ('stack') ELSE ENDIF ENDM end macro ENDP EQ Equal: so sánh logic EVEN Đặt địa chỉ chẵn EXITM Exit macro Thoát khỏi macro FAR Báo nhãn nằm ở ngoài đoạn Như old_e LABEL FAR GE Greater than or Equal Phép toán logic lớn hơn hay bằng GROUP Nhóm các đoạn thành một đoạn; Như Nhóm GROUP code, data
Trang 13(TLTK, bản dịch của LNH, trg 44) GT Greater Than Phép toán logic lớn hơn HIGH Chỉ byte cao của một word ;* Về các Pseudo_Op điều kiện, xem
(TLTK, bản dịch của LNH, trg 45) IF Khối điều kiện IF1 Khối điều kiện cho lần duyệt thứ nhất IF2 Khối điều kiện cho lần duyệt thứ hai IFB If blank Khối điều kiện khi không có tham số IFDEF If Defined Khối điều kiện khi đã có định nghĩa IFDIF
If diffent Khối điều kiện khi hai tham số khác nhau IFE If Equal Khối điều kiện khi bằng 0 IFIDN If Identical Khối điều kiện khi hai tham số bằng nhau IFNB If not Blank Khối điều kiện khi có tham số INCLUDE Chèn thêm vào chương trình một số chỉ thị lấy từ một tập tin
khác Như INCLUDE mylib.mac IRP Indefinite Repeat Macro có số lần lặp không xác định
Như IRP para? <one,two,three,four> sẽ lặp lại 4 lần IRPC Indefinite Repeat Character Macro có số lần lặp chữ
không xác định Như IRPC para? ABCD sẽ lặp lại 4 lần LABEL Nhãn
(TLTK, bản dịch của LNH, trg 44) LE Less than or Equal Phép toán logic nhỏ hơn hay bằng LENGTH Xác định chiều dài một kí hiệu LOCAL Định các kí hiệu chỉ được dùng trong nội bộ macro LOW Chỉ byte thấp của một word LT Less Than Phép toán logic nhỏ hơn LALL Liệt kê toàn bộ macro LFCOND Liệt kê khối điều kiện LIST Liệt kê chương trình MACRO Bắt đầu macro MASK Mặt nạ dạng bit MOD Modulo Cho số dư trong phép chia NAME Định tên của một chương trình hay mô-đun NE Not Equal Phép toán logic không bằng NEAR Báo nhãn nằm trong đoạn NOT Phép toán logic lấy bù OFFSET Offset trong đoạn OR Phép toán logic hoặc
%OUT In xâu ra màn hình PAGE Bắt đầu trang mới và định kích thước trang sẽ được in ra
(màn hình và máy in) khi hợp dịch
Dạng: PAGE [LINE], [COLLUMN]
ngầm định là: 57,80 (hợp với khổ giấy A4) PTR Pointer Dùng chung với BYTE, WORD, DWORD, NEAR và FAR để
định kích thước của một nhãn hay một biến RADIX Định cơ số RECORD Định kiểu bản ghi REPT Repeat Macro lặp SALL Không liệt kê macro SEG Giá trị đoạn ứng với một kí hiệu SHL Shift left Phép dịch chuyển trái.Như MOV AX,7 SHL 1 SHORT Nhảy xuôi gần SHR Shift right Phép dịch chuyển phải
Như MOV A,8 SHR 1 SFCOND Không liệt kê các khối điều khiển sai STRUC Structure Định nghĩa cấu trúc TCOND Liệt kê mặc định cho các khối điều kiện TITLE Psuedo_Op để tạo ra một tiêu để được căn thẳng trái trên dòng thứ 2 của mỗi trang (in) TITLE thường được đặt ở đầu chương trình, nhưng ta cũng có thể đặt nó ở bất cứ đâu trong
chương trình
Độ dài tối đa của TITLE: 60 dòng SUBTTL Sub Title để tạo ra một tiêu đề phụ được định tâm ở dòng thứ 3 (của trang tiếp theo ?), tiêu đề này thường được sử
dụng để mô tả nội dung của trang đó
Độ dài tối đa của SUBTITLE: 60 dòng XOR Phép toán logic hoặc Như MOV AX,7 XOR 9 XALL Liệt kê các macro sinh ra các mã lệnh hoặc dữ liệu XCREF Không liệt kê danh sách để tham chiếu chéo XLIST Không liệt kê chương trình WIDTH Định độ rộng của trường trong bản ghi WORD Định dữ liệu dài một word = Gán tên cho một hằng (kiểu số hoặc kiểu String) sau này trong
chương trình có thể gán lại
Trang 14(khác với Directive EQU) 286C giả lệnh chế độ, báo cho Assembler sử dụng tập lệnh của 80286 phải đặt nó tại đầu chương trình, ngay sau các Pseudo-Op liệt
kê danh sách .8086 giả lệnh chế độ, báo cho Assembler sử dụng tập lệnh của 8086 đây là chế độ ngầm định $ Offset hiện hành
V các toán tử trong Assembly language
( Phần này sử dụng để tra cứu, TLTK số 1, trang 48 )
Toán tử là một sự sửa đổi (modifier) được sử dụng trong trường toán hạng (Operand Field) của một Op_code hay Pseudo_Op Có 5 loại toán tử: Số học, logic, quan hệ, trả lại giá trị, cho thuộc tính (An operator is a modifier used in the operand field of
an assembly language or pseudo-op statement.)
1 Toán tử số học (xem trang 29)
* format: value1 * value2;multiplies value2 by value1 * format: value1 * value2;multiplies value2 by value1
/ format: value1 / value2;divides value1 by value2 and returns the
the quotient
MOD format: value1 MOD value2; divides value1 by value2 and
returns the remainder
SHL format: value SHL expression; shifts values left by expression
bit positions
SHR format: value SHR expression; shifts values right by expression
bit positions 2 Toán tử logic (xem trang 29)
AND format: value1 AND value2; takes logical AND of value1 and
value2
OR format: value1 OR value2; takes logical inclusive-OR of
value1 and value2
XOR format: value1 XOR value2; takes logical exclusive-OR of
value1 and value2
NOT format: NOT value; reverses the state of each bit
in value; that is, it takes the
one's complement 3 Toán tử quan hệ (xem trang 30)
EQ format operand1 EQ operand2; true if the two operands are
GE format operand1 GE operand2; true if operand1 is greater
than or equal to operand2
4 Toán tử trả lại giá trị (xem trang 30)
$ format: $
cho lại giá trị hiện thời của bộ đếm vị trí bộ nhớ
Trang 15SEG format: SEG Var_name, hoặc
SEG Label_name
trả lại giá trị Segment của biến hoặc nhãn
OFFSET format: OFFSET Var_name hoặc
OFFSET Label_name
trả lại giá trị OFFSET của biến hoặc nhãn
LENGTH format: LENGTH Var_name
trả lại độ dài tính bằng đơn vị (Byte hoặc Word) của biến đã
được định nghĩa bằng DUP
TYPE format: TYPE Var_name, hoặc
TYPE Label_name
đối với các biến, TYPE cho lại 1 nếu là kiểu Byte, 2 nếu là kiểu Word, 4 nếu là kiểu Double Word đối với các nhãn TYPE cho lại
-1 nếu là NEAR, -2 nếu là FAR
SIZE Dạng SIZE Var_name
trả lại giá trị là tích của Length và Type
5 Toán tử thuộc tính
PTR format: TYPE PTR EXPRESSION
khai báo lại kiểu (type) (BYTE hoặc WORD) hoặc khoảng cách (NEAR hoặc FAR) của một toán hạng địa chỉ bộ nhớ TYPE là thuộc tính mới còn Expression là một tên (indentifier) mà thuộc tính của nó
bị thay đổi (overriden)
DS: format: seg-reg:addr-expr hoặc ES: seg-reg:label hoặc
SS: seg-reg:variable
CS: thay thế (overrides) thuộc tính đoạn (segment attribute) của một
nhãn, biến hoặc biểu thức địa chỉ
SHORT xem ở lệnh JMP, trang
HIGH format: HIGH value hoặc
HIGH expression
trả lại giá trị là byte cao của 1 giá trị số hoặc địa chỉ 16 bit
LOW format: LOW value hoặc
LOW expression
trả lại giá trị là byte thấp của 1 giá trị số hoặc địa chỉ 16
bit VI Hằng số trong chương trình nguồn
Assembler chấp nhận việc sử dụng một vài dạng hằng số sau: 1 Binary
là một dãy số 0,1 kết thúc bởi ký tự B, thí dụ 10111010B 2 Decimal
là một dãy các chữ số từ 0 đến 9, có thể kết thúc bởi ký tự D hoặc không
đó là một dãy các chữ cái, chữ số, ký hiệu được ghi trong dấu nháy đơn
hay kép, thí dụ 'Hello World!', "Don't enter a number here" bài tập 1 Đổi các số thập phân sau sang dạng nhị phân:
a) 12; b) 17; c) 45; d) 72 2 Đổi các số nhị phân sau sang dạng thập phân:
Trang 16a) 00001000; b) 00010101; c) 00011111; d) 11000011 3 Đổi các số ở câu 2 sang dạng thập lục phân 4 Đổi sang dạng thập phân số 0D8H trong trường hợp: - 0D8H biểu diễn số không dấu - 0D8H biểu diễn số có dấu
hết bài 1
Bài giảng môn Assembly Language, Bài 1 - $ - Nguyễn Đình Việt, Khoa CNTT, ĐHQGVN,HN 1995 -
Bài 2 Các bước trong quá trình tạo 1 chương trình chạy được
Trên thị trường có khá nhiều Assembler, trong các bài giảng môn học này chúng ta
sẽ sử dụng Macro Assembler của MicroSoft (MASM.EXE), nó tương thích với IBM Macro Assembler
Cho đến nay (1990), IBM đã đưa ra thị trường 2 Version của Macro Assembler, Version 1 , version2 Để xây dựng chương trình cho họ máy AT, chúng ta cần phải dùng version 2 (của IBM Macro Assembler) hoặc version 3 (của MicroSoft Macro Assembler)
Đĩa Macro Assembler của IBM có 2 chương trình Assembler tách biệt: - Small
Assembler (ASM): để dùng cho các máy tính có bộ nhớ <= 128 KB và
có tập lệnh ít hơn của MASM MicroSoft không có Small Assembler như IBM - Macro Assembler (MASM)
I Các bước chính
Bứơc 0:
Xác định nhiệm vụ của chương trình, thiết kế chương trình Trong bước này ta
thường cần vẽ lưu đồ (Flowchart) Bước này đặc biệt quan trọng nếu chương trình là dài và phức tạp Nên thực hiện chiến thuật "Top-Down Program Design"
Bước 1 Soạn chương trình nguồn
Dùng 1 chương trình soạn thảo văn bản, ví dụ SideKick, Turbo Pascal
để soạn thảo chương trình nguồn - Không nên dùng các hệ soạn thảo trong đó có sử dụng các mã ASCII mở
rộng, hoặc các ký tự điều khiển (Như Word Perfect, Bked v.v ) - dùng SideKick có rất nhiều tiện lợi, vì đó là chương trình thường trú nhỏ
các lệnh soạn thảo khá giống Turbo Pascal Version 3.01a, quen thuộc với
sinh viên - dùng Turbo Pascal để soạn thảo rất dễ trình bày chương trình nguồn đẹp
vì chức năng TAB của nó rất tiện lợi cho soạn thảo chương trình - (hướng dẫn sinh viên sử dụng SideKick nếu cần thiết) - ghi file nguồn lên đĩa, ví dụ với tên là
Trang 17sau đó ta phải trả lời 3 câu hỏi sau:
Object filename [vidu1.obj]: nếu ta đồng ý thì ấn Enter (nói chung là ta
đồng ý với các gợi ý của MASM)
Source Listing [Nul.lst]: Cross Reference [Nul.crf]:
Sau đó MASM sẽ hiển thị như sau:
Microsoft (R) Macro Assembler Version 5.10 Copyright (C) Microsoft Corp
1981-1985 All right reserved 51712 + 154624 Bytes symbol space free
Trong file lst Macro Assembler còn đưa ra cả địa chỉ (Segment:Offset) của các lệnh
và dữ liệu của chương trình, việc này rất có ích khi chúng ta muốn phân tích các chương trình khó, chẳng hạn phân tích các đoạn mã
Virus v.v - cross-reference listing file:
File vidu1.crf (crf: cross reference) còn gọi là File tham khảo chéo, (cross-reference listing), nó cho số dòng tại đó mỗi ký hiệu (symbol) được định nghĩa và số hiệu tất cả các dòng khác, tại đó có tham chiếu
(refer to) tới ký hiệu này Để MASM.EXE sinh ra file này khi được hỏi:
Cross Reference [Nul.crf]:
ta cần đánh tên file (đuôi ngầm định là crf) Sau khi đã hợp dịch (chạy
MASM.EXE) cần chạy chương trình CREF.EXE
CREF VIDU1; - MAP - Map listing file (file bản đồ chương trình)
Việc tạo ra file này là tuỳ chọn đối với LINK.EXE File này tóm tắt về các đoạn của chương trình, trong mỗi đoạn nó chỉ ra địa chỉ offset 'start' và 'stop' , chiều dài mỗi đoạn của chương trình và class (loại)
của các đoạn
Để tạo ra file MAP ta làm như sau:
LINK VIDU1,,; (2 dấu phẩy trước dấu chấm phẩy)
Lưu ý: - trường hợp có đánh dấu '; ' sau tên của chương trình nguồn: MASM.EXE tự động đặt tên file đích là vidu1.obj , không tạo các file lst và crf
tương ứng - trường hợp không đánh dấu '; ' sau tên của chương trình nguồn:
MASM.EXE
thực hiện theo các bước nêu trên
- cách sử dụng các chỉ dẫn cho MASM.EXE để có thể in các thông báo lỗi ra máy
in, tạo các file tham chiếu chéo, định trang in (số dòng/1 trang,
số cột mỗi dòng)
* sau bước này Assembler mới tạo ra File vidu1.obj; đây là một File trung gian, gọi
là File đích (Object file), nó chứa chương trình của chúng ta ở dạng ngôn ngữ máy, nhưng kèm theo một số thông tin mà chương trình Link
của DOS sẽ dùng đến - sửa các lỗi do Assembler thông báo:
Trang 18nếu có lỗi, Assembler sẽ thông báo số thứ tự của dòng có lỗi, loại lỗi, sau đó
Assembler tiếp tục hợp dịch các dòng chương trình nguồn tiếp sau
và lại thông báo lỗi nếu gặp phải
Ta nên ghi lại các thông báo lỗi và STT dòng có lỗi để sửa (có thể in
luôn ra giấy bằng lệnh Print Screen) luôn một lần - hợp dịch lại và lại sửa lỗi cho đến khi hết lỗi
* Một số thông báo lỗi của Macro Assembler:
- Block nesting error:
thông báo lỗi này thường kèm theo thông báo "Open procedures" hoặc "Open
segments", hãy xem giải thích về các thông báo này như ở dưới đây - End of file, no END directive:
thiếu chỉ thị assembler END ở cuối file hoặc phải thêm 1 dòng trống sau
dòng chứa chỉ thị END - Must be declared in pass 1:
thông báo này thường liên quan đến giả lệnh GROUP, có thể ta chưa định
nghĩa một tên đoạn được khai báo trong giả lệnh GROUP - No or Unreadable CS:MASM cần thấy giả lệnh ASSUME khi hợp dịch một số chỉ thị như CALL hay
JMP - Open procedures:
thiếu nhãn PROC hay ENDP hoặc các tên không trùng nhau trong cặp giả
lệnh PROC - ENDP - Open segments:
thiếu giả lệnh Segment hoặc ENDS hoặc tên đi cùng với hai giả lệnh này - Symbol not defined
Đây là một thông báo lỗi thường thấy khi chúng ta mới học ngôn
ngữ Assmblly, cần kiểm tra các vấn đề sau:
+ sử dụng một tên chưa khai báo hoặc đánh sai một tên đã được khai báo
+ thiếu khai báo EXTRN mà chương trình lại sử dụng một tên nằm trong Modul ngoài; hoặc tên trong modul ngoài và tên được gọi đến không
trùng nhau (do ta đánh sai chẳng hạn)
Bước 3 Link (kết nối chương trình và số liệu v.v )
chương trình LINK có 2 nhiệm vụ chính: 1./ DOS có thể để 1 chương trình ở chỗ nào đó do nó sắp đặt cho thuận tiện Việc này tránh cho NSD không phải chỉ ra việc đặt chương trình ở đâu Muốn cho chương trình nguồn (và sau đó là dạng obj) sử dụng được đặc
điểm này (relocatable) cần phải có chương trình LINK của DOS 2./ NSD thường viết chương trình theo các modul, thử riêng rẽ từng Modul, do vậy sẽ tạo ra nhiều file obj tương ứng Nhiệm vụ thứ 2 của LINK chính là kết nối các object module lại thành 1 modul duy nhất, chạy
được
Thí dụ LINK MOD1 + MOD2 + MOD3 sẽ kết nối các file MOD1.OBJ,
MOD2.OBJ, MOD3.OBJ để tạo thành file MOD1.EXE chạy được
Ta cần sử dụng chương trình Link.exe (lệnh ngoại trú của DOS) để tạo ra
một file exe từ File obj - A:\> Link vidu1;
Microsoft 8086 Object Linker
Version 3.02 (C) Copyright Microsoft Corp 1983, 1984, 1985
Warning: No stack segment
There was an error detected
Trang 19Error là lỗi nhưng chính là điều chúng ta muốn, nó báo rằng chưa có đoạn
stack * sau khi thực hiện bước này, ta có file vidu1.exe, nói chung có thể cho
chạy ngay được Tuy nhiên ta cần nghiên cứu cách tạo file com trước đã * Xem tuỳ chọn của LINK để tạo ra file MAP đã trình bày ở bước 2
* Một số thông báo lỗi của LINK
- Fixup offset exceeds field with:
Với thông báo này ta cũng khó tìm ra được lỗi, có thể là do có một lời gọi xa tới một thủ tục (Call far) nhưng trong thủ tục đó lại khai báo nó là near (Proc near) Lỗi này cũng có thể xảy ra nếu toàn bộ chương
trình vượt quá 64KB, dùng file MAP có thể thấy được điều này
- Symbol defined more than once:
xảy ra khi LINK phát hiện thấy 1 biến hay thủ tục được định nghĩa
trong hai file
- Unresolved externals:
có thể do thiếu khai báo public cho 1 biến hay thủ tục, hoặc tên trong
1 thủ tục external sai
- Warning: no stack segment
Đây thực ra không phải là thông báo lỗi mà là lời nhắc nhở của LINK, ta
thường luôn thấy nó khi LINK các file OBJ để tạo ra các file COM
Bước 4 Dịch chương trình sang File dạng COM
Để tạo ra file com, ta cần chương trình Exe2bin.exe của DOS Chương trình này chuyển 1 file dạng exe hay bin sang file dạng com - Exe2bin vidu1 vidu1.comChúng ta dùng lệnh DIR của DOS để kiểm tra sự tồn tại của vidu1.com trên
đĩa
Đôi khi có thể thấy thông báo lỗi 'File cannot be converted', đây là thông báo lỗi duy nhất của EXE2BIN, nguyên nhân sinh ra lỗi này có thể
như sau:
+ các đoạn xếp sai thứ tự, cần kiểm tra lại bằng file MAP (xem phụ lục
C trong sách 'Nhập môn Assembler', Peter Norton
+ chương trình chính không đứng đầu tiên trong lệnh LINK
+ chương trình chính không có chỉ thị Assembler ORG 100H đứng liền dưới
khai báo CODE_SEG SEGMENT PUBLIC
Ngoài ra cần kiểm tra lại xem sau chỉ thị END cuối cùng trong modul chương trình chính đã ghi nhãn của lệnh đầu tiên của chương trình chưa
- Lưu ý: các Version Dos sau 5.0 không có File Exe2bin.exe vì DOS không chủ trương hỗ trợ việc tạo các file com, muốn thực hiện bước 4 này ta
cần đặt lệnh
DEVICE=PATH_NAME\SETVER.EXE
trong file CONFIG.SYS, tất nhiên cần phải có SETVER.EXE tại đường dẫn
PATH_NAME
Bước 5 Chạy thử chương trình
- Nếu chương trình không dài, thì tốt nhất là dùng Debug để chạy thử từng bước Lệnh T (Trace), theo dõi quá trình biến đổi nội dung các thanh ghi,
việc chuyển số liệu v.v - Nếu chia chương trình thành từng khối, có thể hợp dịch từng khối và cho
Trang 20chạy thử từng Modul, sau khi chạy tốt mới ghép nối lại với nhau - Nếu có lỗi thì lặp lại các bước trên
II Hướng dẫn sử dụng chương trình Debug
Trình bày 19 lệnh của DEBUG, 4 lệnh còn lại liên quan đến bộ nhớ mở rộng
XMS và EMS không cần trình bày
Bài tập 2.1 In ra màn hình 1 ký tự (ký tự 'A')
Bài tập 2.2 In ra màn hình một xâu ký tự 'Darling, I love you'
Bài tập 2.3 hỏi tên người (từ bàn phím) rồi gửi lời chào người đó
Bài tập 2.4 Nhận vào từ bàn phím 5 xâu ký tự (n <= 5); in ra màn hình 1 trong 5 xâu
ký tự đó
Bài tập 2_1 (BT2_1.ASM) In ra màn hình 1 ký tự (ký tự 'A')
Seg_a segment:100 jmp 103
assume cs:seg_a, ds:seg_a:102 db 41
org 100h:103 mov ah,02 start: jmp short loc_1:105 mov dl,[102] data_1 db 41h:109 int 21 loc_1 mov ah,02:10b int 20
assume cs:seg_a, ds:seg_a:102 db'Darling, I love you$'
org 100h:118 mov dx,0102 start: jmp short loc_1:11b mov ah,09 data_1 db'Darling, I love you$':11d int 21 loc_1 mov dx,offset data_1:11f int 20
============== SEG_A SEGMENT BYTE PUBLIC
ASSUME CS:SEG_A, DS:SEG_A
ORG 100h
BT2_3 PROC FAR
94E0:0100 START: 94E0:0100 EB 25 JMP SHORT LOC_1;(0127) 94E0:0102 90
DB 90H 94E0:0103 0D 0A 24 DATA_1 DB 0DH, 0AH, '$' 94E0:0106 57 68 61 74
20 69 DATA_2 DB 'What is your name ?: $' 94E0:010C 73 20 79 6F 75 72;xref 94E0:0129, 012C 94E0:0112 20 6E 61 6D 65 20 94E0:0118 3F 20 3A 20 24
94E0:011D 48 65 6C 6C 6F 20 DATA_3 DB 'Hello Mr.$';xref 94E0:0143, 0146 94E0:0123 4D 72 2E 24 94E0:0127 LOC_1:;xref 94E0:0100 94E0:0127 B4 09
Trang 21MOV AH,9 94E0:0129 BA 0106 MOV DX,OFFSET DATA_2 94E0:012C CD 21 INT 21H;DOS Service 09h
;display char string at ds:dx 94E0:012E B4 0A MOV AH,0AH 94E0:0130 BA 015F MOV DX,OFFSET DATA_4 94E0:0133 8B DA MOV BX,DX 94E0:0135 C6 07
FE MOV BYTE PTR [BX],0FEH 94E0:0138 CD 21 INT 21H; DOS Service 0Ah
; get keybd line, put at ds:dx 94E0:013A B4 09 MOV AH,9 94E0:013C BA 0103 MOV DX,OFFSET DATA_1 94E0:013F CD 21 INT 21H 94E0:0141 B4 09 MOV AH,9 94E0:0143 BA 011D MOV DX,OFFSET DATA_3 94E0:0146 CD 21 INT 21H 94E0:0148 B4 09 MOV AH,9 94E0:014A BB 015F MOV BX,OFFSET
DATA_4 94E0:014D 8B D3 MOV DX,BX 94E0:014F 02 5F 01 ADD BL,[BX+1] 94E0:0152 83 C3 02 ADD BX,2 94E0:0155 C6 07 24 MOV BYTE PTR [BX],24H; '$' 94E0:0158 83 C2 02 ADD DX,2 94E0:015B CD 21 INT 21H 94E0:015D CD 20 INT 20H; Program Terminate 94E0:015F 3F DATA_4 DB 3FH; '?'
BT2_3 ENDP SEG_A ENDS
END START
Bài tập 2.4 Nhận vào từ bàn phím 5 xâu ký tự (n <= 5); in ra màn hình 1 trong 5 xâu
ký tự đó
;GET 5 STRING FROM KBD, THEN ASK WHICH OF THEM WILL BE SEND
TO SCR CGROUP GROUP CODE_SEG
ASSUME CS: CGROUP CODE_SEG SEGMENT BYTE PUBLIC
ORG 100H
START: JMP FIRST
MSG DB "Enter 5 string ",0DH,0AH,"$" MSG1 DB "one:$" MSG2 DB "two:$" MSG3 DB "three:$" MSG4 DB "four:$" MSG5 DB "five:$" ASK_FOR_OUT DB
"Which string will be out ?: $" NUMBER DB 0
FIRST: MOV AH, 09H
Trang 22MOV AH,09H;ask for 3rd string
Trang 23INT 20H ; - CR_LF PROC NEAR
0FEH,?,0FEH DUP(0) STR4 DB 0FEH,?,0FEH DUP(0) STR5 DB 0FEH,?,0FEH DUP(0)
CODE_SEG ENDS END START
Bài giảng môn Assembly Language, Bài 2 - $ - Nguyễn Đình Việt, Khoa CNTT, ĐHQGVN,HN 1995 -
Bài 3 Dạng của 1 chương trình mẫu
Bài này trình bày
-các mô hình tổng quát để xây dựng nên 1 chương trình Mẫu chương trình này là chung nhất cho mọi chương trình Khi chúng ta viết chương trình của mình, ta chỉ cần điền số liệu và các chỉ thị cho chương trình cụ thể đó
-về sự khác nhau giữa com files và exe files
I Main Program Module: Mô dul chương trình chính
Sau đâu là 1 mẫu chung cho 1 modul nguồn, nó bao gồm 1 chương trình đầy đủ hoặc
nó sẽ được kết nối với 1 hoặc 1 số modul (phụ) khác để tạo nên 1 chương trình
PAGE ,132 TITLE (Insert title here) SUBTTL (Insert sub_title here) (Insert EXTRN statement, if approriate)
STACK SEGMENT PARA PUBLIC 'STACK'
DB 64 DUP('STACK ') STACK ENDS
DSEG SEGMENT PARA PUBLIC 'DATA'
(Insert data here) DSEG ENDS
CSEG SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CSEG, DS:DSEG, SS:STACK
ENTRY PROC FAR;entry point
;set up the stack to contain the proper values so this program ;can return to DOS or Debug
Trang 24MOV AX,DSEG
MOV DS,AX
(insert instructions here)
RET;return to DOS or Debug ENTRY ENDP CSEG ENDS END ENTRY
chú ý mẫu này là chương trình tổng quát, ta có thể sửa đổi 1 số điểm sau: -Title: Tiêu đề thường chỉ ra tên File trên đĩa của chương trình này -Nếu Modul này có chứa tham chiếu tới các thủ tục hoặc biến, mà chúng được dịnh nghĩa ở Modul phụ, thì nhất thiết phải có chỉ thị EXTRN để liệt kê
danh sách chúng -Ta dùng AX để khởi tạo STACK và địa chỉ đoạn dữ liệu, nhưng cũng có thể
dùng các thanh ghi đa năng khác
Vì vậy, nếu chương trình của ta nhận giá trị vào của người sử dụng từ thanh ghi AX, khi đó ta bắt buộc phải dùng thanh ghi khác (ví dụ DI) để
khởi tạo -Về thủ tục:
Các Pseudo_Op Proc và Endp đánh dấu điểm đầu và điểm cuối của 1 thủ tục Thủ tục
là một khối lệnh mà có thể được gọi thực hiện từ nhiều nơi trong
chương trình
Nếu thủ tục kết thúc bằng lệnh RET (Return from Procedure) thì ta có thể gọi nó là một chương trình con (Subroutine) Lệnh RET làm cho MPU thực hiện chương trình
đã gọi (tới thủ tục)tiếp tục thực hiện lệnh (trình tự)
sau lời gọi đó
Một thủ tục luôn có một trong hai thuộc tính: NEAR và FAR được chỉ
ra bởi Operand đứng ngay sau Proc directive, trong đó NEAR là ngầm định
+ Proc_name PROC NEAR: thủ tục Proc_name chỉ có thể được gọi từ trong chính SEGMENT chứa thủ tục đó Khi gặp lời gọi tới 1 thủ tục NEAR,
MPU chỉ cất Offset (IP) của địa chỉ trở về lên Stack
Với chương trình dạng COM, luôn luôn dùng NEAR
+ Proc_name PROC FAR: thủ tục Proc_name có thể được gọi từ bất cứ
SEGMENT nào Khi gặp lời gọi tới 1 thủ tục FAR, MPU chỉ cất địa chỉ
trở CS:IP lên Stack
Với chương trình dạng EXE, luôn luôn dùng FAR cho thủ tục chính
II SECONDARY Module: Mô dul phụ
sau đây là mẫu modul phụ, sẽ được Linked với Main Modul ở ví dụ trên
Page ,132 Title (điền các tiêu đề ở đây.) public pname
(khai báo public cho các biến tại đây nếu cần thiết) dseg segment para public 'data'(đặt các dữ liệu tại đây) dseg ends cseg segment para public 'code'
assume cs:cseg, ds:dseg pname proc near
(đặt các lệnh ở đây)
ret;trở lại chương trình gọi pname endp cseg ends
end
Chú ý có thể sửa đổi lại một số khai báo như sau:
1 Vì Code segment của modul phụ này có cùng tên (cseg) với tên của code segment thuộc modul chính, nên ta khai báo Pname proc near Để gọi Pname từ segment khác, phải thay near bằng far 2 vì data segment của modul phụ này có cùng tên với data segment của modul chính, nên ta không cần khởi tạo DS (không cần assume
Trang 25ds:dseg) Nếu modul phụ này dùng data segment khác tên với data segment của modul chính thì ta phải dùng pseudo op: assume ds: tên data segment <> dseg 3 ở đây ta đặt tên thủ tục là Pname, khi lập chương trình của mình, ta có thể thay bằng tên theo ý ta ở các vị trí: + khai báo public ở trên đầu thủ tục + khai báo proc ở giữa + khai báo endp ở cuối 4 ở modul phụ, ta có khai báo public để tương ứng với khai báo Extrn ở modul chính trong 2 ví dụ này, nếu modul chính gọi modul phụ, thì ở modul chính phải có khai báo
extrn pname: near III .com file
DOS có thể chạy được 2 loại file chương trình viết bằng assembly language, đó là com file và exe file Nói chung người sử dụng dùng exe file khi cần tạo các chương trình lớn, dài hơn 64 KB, và dùng com file khi cần tạo các file chương trình <= 64KB việc tạo ra com file cần theo một số quy tắc khác exe file, sau đây là một số điểm quan trọng:
1 Các quy tắc để tạo ra com file
1/ bỏ qua tất cả các stack, data và extra segments
2/ chỉ xác định 1 code segment, nhưng để tất cả lệnh và dữ liệu vào đó
3/ ở assume pseudo-op ta trỏ tất cả 4 thanh ghi đoạn tới code segment
ví dụ
cseg segment para public 'code'
assume cs:cseg, ds:cseg, es: cseg, ss: cseg
4/ đặt trước điểm vào của chương trình (lệnh đầu tiên của ch tr) với
chỉ thị assembler
org 100h; để dành 256 byte đầu tiên cho PSP (Program segment prefix)
5/ đặt tất cả các dữ liệu trước các lệnh của ch trình Tất nhiên trước
dữ liệu phải có 1 lệnh JMP để nhảy qua vùng dữ liệu
2 Các quy tắc tạo các modul phụ của com file
cũng tuân theo các quy tắc trên, nhưng cần lưu ý: - đặt tên cho segment ở modul phụ giống tên segment ở modul chính
ví dụ tên cseg dùng ở cả modul chính lẫn phụ - cũng giống như ở exe file, ở lệnh END cuối modul phụ, không được viết
nhãn sau END
3 Mẫu cho 1 com file
Mẫu cho 1 mô đun chính
Page ,132 Title (ta để tiêu đề ở đây) (đặt khai báo Extrn tại đây nếu cần)
Cseg segment Para Public 'Code'
Assume cs: cseg, ds: cseg, es:cseg, ss:cseg
Trang 26Mẫu cho 1 mô đun phụ (ch trình con) của com file
Page ,132 Title (ta để tiêu đề ở đây)
public Pname (đặt Public cho các biến tại đây, nếu có)
Cseg segment Para Public 'Code'
Assume cs: cseg, ds: cseg, es:cseg, ss:cseg
jmp Pname; nhảy qua miền dữ liệu
1) ngắn hơn hẳn so với exe files
2) nói chung nạp vào bộ nhớ nhanh hơn exe files
3) dễ viết hơn vì không phải khởi tạo các thanh ghi cho Stack, DS,
ES
4) các ch trình thường trú phải viết dưới dạng com 4.1 nhược điểm
1) Không thể dài hơn 64 KB
2) chúng yêu cầu phương pháp viết ch trình chặt chẽ hơn
3) vì chỉ sử dụng có 1 segment nên không có sự tách biệt hoàn toàn
giữa các lệnh và số liệu
4) Không truy nhập được các thủ tục hoặc số liệu ở các segment khác, do đó rất khó
sử dụng các modul được NSD khác xây dựng, nếu các modul này đặt tên cho
segment mà chúng dùng khác tên segment của
CODE_SEG SEGMENT BYTE PUBLIC
ASSUME CS:CODE_SEG, DS:CODE_SEG
Trang 27ORG 100H
START: JMP FIRST
MSG DB "Enter 2 number (0 =< x <= 255):$" MSG1 DB "number 1:$" MSG2 DB
"number 2:$" msg3 DB "The Product is: $" NUMBER_1 DB 0 NUMBER_2 DB 0 RESULT LABEL BYTE PRODUCT DW 0
FIRST: MOV AH,09H
; - ;This procedure get in
an integer number between 0 255 ;Return it to calling prog in
AX ; - Get_an_Int_num PROC; 0 <= X <= 255
mov cx,1;CX counts digits typed in loop_2: Call Get_a_dec_digit
cmp al,0Dh je exit_2 sub al,30h
xor ah,ah mov dx,ax
Trang 28JA EXIT_2 jmp loop_2 exit_2: mov ax,temp_var
pop dx pop cx pop bx
ret Get_an_Int_num
ENDP ; - ;This
procedure gets in a decimal digit between 0 9 ;checks input for digit ;Return it to calling prog in AL ; - Get_a_dec_digit PROC loop_1:
push dx
mov ah,08
int 21h
cmp al,0Dh je exit_1 cmp al,30h jb loop_1 cmp al,39h ja loop_1
mov dl,al mov ah,02
int 21h exit_1: pop dx
ret Get_a_dec_digit ENDP
; - ;This Prog will Write out an Integer number in AX (Int number) ;let refer to example in 'Nhap mon
Assembler', Peter norton, Pg 83 WRITE_INT_NUMBER PROC NEAR
MOV BX,10 XOR CX,CX NONE_ZERO: XOR DX,DX
DIV BX PUSH DX INC CX
MOV AH,02 MOV DL,13
Trang 29Bài giảng môn Assembly Language, Bài 3 - $ - Nguyễn Đình Việt, Khoa CNTT, ĐHQGVN,HN 1995 -
Bài 5 Các thao với File
TLTK: 1 Assembly Language for Pascal Programmers; Steven Holzner, Brady
Page 71
2 PC Intern System Programming, Michael Tischer, Chapter 19
Mục đích của tính toán là tạo ra các OUTPUT có thể sử dụng được bên ngoài chương trình Output lên màn hình là một trong các phương pháp như vậy, nhưng sử dụng File rất quan trọng vì nó là bộ nhớ ngoài, có thể lưu trữ thông tin ngay cả khi tắt máy
Ta có thể in ra một File, có thể tổ chức một file để lưu giữ dữ liệu và các ký tự cho 1 Editor, file có thể là chính chương trình
DOS có một bộ dịch vụ về File rất phong phú, phần lớn là các dịch vụ trong INT 21h
Các Service của INT 21h represent most of the resources mà những người lập trình
sử dụng trong DOS Bên cạnh INT 20h (kết thúc chương trình) và các ngắt cho phép đặt một chương trình thường trú, những ngắt khác thực sự cần thiết là các ngắt cho phép đọc/ghi đĩa, INT 25h và INT 26h Trong khi đó số lượng các Service của INT 21h không ngừng tăng lên, ở DOS version 4.0 con số đã lên tới 6Ch (=108d)
I File Control Blocks (FCB)
Trước DOS 2.0, DOS thường làm việc với File thông qua FCBs FCBs giữ các
thông tin về file: Filename, tên ổ đĩa chứa file, kích thước file Tuy nhiên FCBs hạn chế độ dài tối đa của File là 11 character Từ DOS 2.0 trở đi, IBM đưa ra Directory
và vì vậy cần phải chỉ ra đường dẫn tới file, tất nhiên 11 ký tự nói chung là không đủ,
đó là lý do mà File handles đã được IBM (và Microsoft) đưa ra
II File handles
Một File handle là một từ 16 bit làm đại diện cho 1 file trước DOS (A file handle is a 16-bit word that stands, to DOS, for a file.) Khi chúng ta muốn sử dụng một file, ta trao cho DOS filename còn DOS thì trả lại một File handle trong một thanh ghi
(thường là AX) Khi chúng ta muốn làm một việc gì đó với file - rename file, open file, read from file thì dịch vụ của INT 21h sẽ cần file handle 16 bit đó trong một thanh ghi nào đó (thường là BX)
Trình tự điển hình để Copy một file rất giống với trong ngôn ngữ lập trình Pascal - ta
sẽ mở, đọc, ghi và đóng file lại - ngưng ta sẽ sử dụng DOS chứ không phải là
PASCAL ở đây
Ta thực hiện công việc đó như sau: - tạo một xâu ký tự tên file (ASCIIZ string) trong
bộ nhớ, ví dụ:
Trang 30FILE_36 DB "C:\Novel\Chapter.89",0 - mở file và lấy file handle cho nó (INT 21h service 3Dh) - tạo một file mới (INT 21h service 3Ch) - đọc từ file nguồn (file thứ nhất) (INT 21h service 3Fh) - viết vào file mới (file đích hay file thứ hai) (INT 21h service 40h) - sau đó đóng cả hai file lại (INT 21h service 3Eh) service 3Fh giống như Read() service 40h giống như Write() Cũng giống như trong Pascal, chúng ta có thể coi các thiết bị (devices) như các file logic Đặc biệt chúng ta có thể sử dụng Predefined handle để truy cập tới các thiết bị vật lý khác nhau.
Sau đây là một số Predefined handles:
handle Device
0 Standard Input (STDIN), usually keyboard 1 Standard Output (STDOUT), usually screen
2 Standard Erro device (STDERR)
3 Standard Auxiliary device (STDAUX)
4 Standard Printer
Thí dụ, nếu chúng ta chọn service 40h và trao giá trị 04h cho file handle thì Output
sẽ đi ra máy in
II Các dịch vụ file handle của DOS và các mã lỗi (error codes)
1 Các dịch vụ File Handle
Có rất nhiều dịch vụ file handle của DOS, sau đây là một số service:
File Handle Service Number You set It Returns
- Create Subdirectory 39h DS:DX to ASCIIZ if CY=1, AX chứa mã lỗi
string Delete Subdirectory 3Ah DS:DX to ASCIIZ if CY=1, AX chứa mã lỗi
string Change Directory 3Bh DS:DX to ASCIIZ if CY=1, AX chứa mã lỗi
string Create File 3Ch DS:DX to ASCIIZ if CY=1, AX chứa mã lỗi
DS:DX=Buffer Write to File 40h BX=Handle if CY=1, AX chứa mã lỗi CX=#Byte wanted
DS:DX=Buffer Delete a File 41h DS:DX to ASCIIZ if CY=1, AX chứa mã lỗi string Move Read/Write pointer 42h CX:DX=#Bytes to if CY=1, AX chứa mã lỗi
move if CY=0, DX:AX=new
BX=File Handle location in file
AL="Methode" Find 1st Matching file 4Eh DS:DX to ASCIIZ if CY=1, AX chứa mã lỗi
CX=Attribute if CY=0 then DTA has
21 bytes reserved
1 byte: file's attrib
1 word: file's time 1 word: file's date
Trang 311 Dword: file's size 13 byte: ASCIIZ name Find next Matching file 4Fh DTA as set same as for 4Eh
by service 4Eh Rename File 56h DS:DX to ASCIIZ if CY=1, AX chứa mã lỗi
ES:DI to new
name (also ASCIIZ)
Còn có rất nhiều Serice khác nữa, trong đó có các Service tạo các file tạm
(temporary file), lấy hoặc đặt lại các thuộc tính Date, Time của file
1.1 Các mã lỗi trả về trong AX (Error Codes)
Trong DOS version 4.0 có 91 mã lỗi khác nhau, ở các version sau này con số đó còn lớn hơn Sau đây là một số mã lỗi thường gặp:
Error codes Means
1 Invalid function number
2 File not found
3 Path was not found
4 Too many files open at once
5 Access denied for this operation
6 File handle used is invalid
7 Memory Control Blocks destroyed
8 Insufficient memory
15 Invalid drive was specified
16 Cannot delete current directory
19 Cannot write on a write-protected diskette
21 Drive not ready 23 Disk data error 25 Disk seek error
27 Sector not found
28 Printer needs paper
29 Write fault
30 Read fault
61 Print queue is full 1.2 File Access Modes
Mode truy cập file được truyền qua AL, có các Mode sau:
Access Mode for Opening Files Means
0 Open file for Read only 1 Open file for Write only
2 Open file for both Read and Write
1.3 Các thuộc tính của File (không được là tên nhãn đĩa) truyền qua CX
File Attribute Means
0 Plain old file
1 Read-Only
2 Hidden File (Hidden from directory searches)
4 A System file
8 Used for the Volume label of a Disk
10 This file name is the name of a subdirectory
1.4 Cách dịch chuyển Read/Write Pointer khi dùng service 42h