Tải bản đầy đủ (.doc) (63 trang)

Giới thiệu về Assembly Language (Hợp ngữ) potx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (254.14 KB, 63 trang )


Giới thiệu về Assembly
Language (Hợp ngữ)
……… , tháng … năm …….
BÀ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ớ
end: hết mã ngữ.
• Cho phép viết các chú thích trong chương trình, làm cho chương trình dễ
đọc, dễ bảo trì.
• Khi hợp dịch, các mã lệnh được chuyển trực tiếp thành các lệnh của bộ
vxl để nó có thể thực hiện trực tiếp được. Các nhãn, các chỉ thị cho Assembler
chỉ được chính Assembler sử dụng, không chuyển thành mã máy; còn các chú


thích (comment) thì bị bỏ qua. Chính vì vậy mà các chương trình viết bằng
Assembly rất ngắn gọn, chạy rất nhanh.
• 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-
compatible 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
2
7
2
6
2
5

2
4
2
3
2
2
2
1
2
0
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 = -2
D
! 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.
Để 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?
• Đảo các bit 0010 1111
• Cộng thêm 1 = 0000 0001
• Kết quả = 0011 0000 = 32 + 16 = +48 , số thập phân tương ứng là
-48
2.3. Hệ đếm thập lục phân (hệ 16)
Biểu diễn số trong hệ cơ số 2 có nhiều điểm bất tiện cho người lập trình, vì vậy
người ta tìm cách biểu diễn khác cho tiện lợi hơn, tuy vậy cần phải nhấn mạnh rằng
bên trong máy tính tất cả lệnh và số liệu đều được biễu diễn dưới dạng nhị phân.
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 2
24
= 16MB
2. Không gian địa chỉ ảo là miền bộ nhớ mà 80286 có thể
đánh địa chỉ, bằng 2
30
= 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à đủ.
II Tập lệnh của bộ vi xử lý 8088/8086
1. Bảng lệnh 8088/8086 (xem tài liệu chụp)
2. Phân loại các lệnh
Căn cứ vào công việc mà lệnh thực hiện, có thể chia làm 5 nhóm
lệnh như sau:
1/ Các lệnh số học:
ADD dest,src cộng 2 toán hạng, đặt kết quả trong dest
dest:= dest + src
ADC dest, src cộng 2 toán hạng, cộng thêm số nhớ (Carry) từ lệnh ADD trước đó
dest:= dest + src +Cf
INC dest tăng destination lên 1 (dest có thể là thanh ghi hoặc địa chỉ)
dest:= dest + 1
DEC dest giảm destination bớt 1 (dest có thể là thanh ghi hoặc địa chỉ)
dest:= dest - 1
SUB dest,src lấy dest trừ đi src, để kết quả trong dest
dest:= dest - src
SBB dest,src lấy dest trừ đi src và trừ thêm số mượn từ lệnh SUB trước đó ,kết quả
để trong dest
dest:= dest - src - CF
NEG dest đổi dấu của toán hạng

dest:= 0-dest
CMP 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
byte : AL port

word : AL [port]
AH [port+1]
OUT Port8 (or DX) gửi dữ liệu từ AL hay AX ra cổng
byte : AL port
word : AL [port]
AH [port+1]
LEA reg16, mem1 nạp địa chỉ vào thanh ghi, mem1 phải là một nhãn. reg16 được
nạp địa chỉ của mem1 chứ
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ờ
.v.v
4/ 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
REP/REPE/REPZ
lặp lại thao tác xâu ký tự (CX:= CX-1) cho đến khi C=0
REPNE/REPNZ
lặp lại thao tác xâu ký tự ,sử dụng kết hợp với lệnh CMPS và
SCAS
.v.v
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ãn
short : IP (IP + (target displacement sign-extended))
báo cho assembler là nhãn đích của lệnh nhảy JMP không xa
hơ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ờ
LOOP short_label CX CX-1
JA/JNBE JAE/JNB
JB/JC JE/JZ
JG/JNGE JGE/JNL
.V.V
INT TYPE thực hiện ngắt phần mềm (call a systen function)
INTO type: if OF=OV=1 then perform INTO type
IRET quay trở về từ lệnh gọi ngắt. Nó có ảnh hưởng như
lệnh POP IP; POP CS; POPF
6/ Các lệnh điều khiển bộ VXL
CLS xoá cờ CY thành NC (CF 0)
CMC lấy phần bù (đảo giá trị của) cờ Carry)
STC đặt cờ carry thành CY
CLD clear direction flag
(các lệnh với xâu ký tự tự động tăng)
CLI cấm các ngắt (có thể che)
STI bỏ mặt nạ ngắt (cho phép có thể ngắt)
HLT ngừng xử lý (thực hiện các lệnh NOP cho đến khi một
lời gọi ngắt xảy ra)
.v.v
7/ Các lệnh điều khiển tính bảo vệ (80286/80386/80486)
(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:
nêu ở trên
2/ trường hợp 2
Immediate to reg/mem (not to AX) s: sign

s= 1: signed value
s= 0: unsigned value
1 0 0 0 0 0 s w mod 0 0 0 r/m data data
byte 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
3/ trường hợp 3
Immediate to AX (Accumulator)
0 0 0 0 0 1 0 w data data
byte 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.
ví dụ: mov ax, mem1 thì nội dung ô nhớ có nhãn mem1 được chuyển
vào ax.
-indirect: địa chỉ nhớ không được nêu ra trực tiếp. có một thanh ghi dùng để chứa địa
chỉ của ô nhớ chứa dữ liệu. Như vậy thanh ghi có
tác dụng như là một địa chỉ gián tiếp để xác định vị trí dữ liệu.
ví dụ: mov [bx],cx

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
thí dụ MOV AX,[BX]
5. Base relative addressing địa chỉ tương đối cơ sở
thí dụ MOV AX,[BX] + 4
6. Direct indexed addressing địa chỉ được chỉ số hoá trực tiếp
(MOV DI,2)
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
Dạ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.
Dạng: PUBLIC Symbol [, ]
Symbol ở đây có thể là các tên biến, nhãn kể cả các nhãn của Proc và các tên đã được
định nghĩa bởi các
Pseudo_Op EQU, = .
PUBLIC có bạn đồng hành là EXTRN
EXTRN External - Báo là tham chiếu ngoài;
format: 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
(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
(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
identical.
NE format operand1 NE operand2; true if the two operands are

not identical.
LT format operand1 LT operand2; true if operand1 is less than
operand2.
GT format operand1 GT operand2; true if operand1 is greater
than operand2.
LE format operand1 LE operand2; true if operand1 is less than
or equal to operand2.
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ớ.
SEG 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
cũng được, thí dụ 512 , 512D 3. Hexadecimal
là một dãy các chữ số từ 0 đến 9 và các ký tự A, B, C, D, E, F
- phải kết thúc bởi ký tự H
- ký tự đầu tiên nhất thiết phải là chữ số (0 9)
thí dụ 8FH, 0EDH 4. Character
đó 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:
a) 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à
vidu1.asm
Bước 2. Hợp dịch chương trình nguồn
- Hợp dịch
A:\> masm vidu1
sau đó 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
nn nnn Byte Free
m Warning Errors l Severe Errors
A:\>
trường hợp không có lỗi nào xảy ra thì m=0, l=0
- Về File .lst
Đây là File văn bản nguồn do MASM tạo ra, nó chứa các lệnh nguồn và các mã số
của chúng để ta có thể in ra xem cách Assembler biên dịch chương
trình của mình.
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:
nế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
Error 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.com
Chú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
chạ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
mov dl,data_1
int 21h int 20h seg_a ends end start
;
Bài tập 2.2 In ra màn hình một xâu ký tự 'Darling, I love you'
Seg_a segment:100 jmp 118
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
mov ah,09
int 21
int 20 seg_a ends end start
;
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 đó
;============================================================
============== ;== BT2_3.LST == ;== Created: 4-Aug-95 == ;== Passes: 5
Analysis Options on: QRSUX ==
;============================================================
============== 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
MOV 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
MOV DX,OFFSET MSG
INT 21H
MOV AH,09H;ask for 1st string
MOV DX,OFFSET MSG1
INT 21H
MOV AH,0AH
MOV DX,OFFSET STR1
INT 21H
CALL CR_LF
MOV AH,09H;ask for 2nd string
MOV DX,OFFSET MSG2
INT 21H
MOV AH,0AH
MOV DX,OFFSET STR2
INT 21H
CALL CR_LF
MOV AH,09H;ask for 3rd string
MOV DX,OFFSET MSG3
INT 21H
MOV AH,0AH
MOV DX,OFFSET STR3
INT 21H
CALL CR_LF
MOV AH,09H;ask for 4th string
MOV DX,OFFSET MSG4
INT 21H
MOV AH,0AH
MOV DX,OFFSET STR4
INT 21H

CALL CR_LF
MOV AH,09H;ask for 5th string
MOV DX,OFFSET MSG5
INT 21H
MOV AH,0AH
MOV DX,OFFSET STR5
INT 21H
CALL CR_LF
MOV AH,09H
MOV DX,OFFSET ASK_FOR_OUT
INT 21H
MOV AH,01;GET STRING NUMBER TO SEND OUT
INT 21H
CALL CR_LF
SUB AL,30H
MOV NUMBER,AL
MOV AX,100H;256d
XOR CX,CX
MOV CL,NUMBER
DEC CL MUL CX
ADD AX,OFFSET STR1
MOV BX,AX
MOV CL,[BX+1]
ADD BX,CX
ADD BX,2
MOV BYTE PTR [BX],"$"
MOV DX,AX
ADD DX,2
MOV AH,09H
INT 21H

INT 20H ; CR_LF
PROC NEAR
PUSH AX PUSH DX
MOV AH,02 MOV DL,13
INT 21H
MOV DL,10
INT 21H
POP DX POP AX
RET CR_LF ENDP ;
STR1 DB 0FEH,?,0FEH DUP(0) STR2 DB 0FEH,?,0FEH DUP(0) STR3 DB
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
PUSH DS
SUB AX,AX
PUSH AX
;initialize the data segment address
MOV 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
ds: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
ví dụ entry: jmp our_prog
source db 10,20,30,40
dest db 4 dup(?)
our_prog proc near
(các lệnh )
6/ xác định tất cả các Procedure là near (ngầm định)
7/ cuối chương trình sau END pseudo_op phải có nhãn của lệnh đầu tiên
của chương trình
ví dụ
end entry
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

×