แอสเซมบลี - คำแนะนำทางคณิตศาสตร์
คำแนะนำ INC
คำสั่ง INC ใช้สำหรับการเพิ่มตัวถูกดำเนินการทีละตัว ทำงานบนตัวถูกดำเนินการเดียวที่สามารถอยู่ในรีจิสเตอร์หรือในหน่วยความจำ
ไวยากรณ์
คำสั่ง INC มีไวยากรณ์ต่อไปนี้ -
INC destination
ปลายทางตัวถูกดำเนินการอาจเป็นตัวถูกดำเนินการ 8 บิต 16 บิตหรือ 32 บิต
ตัวอย่าง
INC EBX ; Increments 32-bit register
INC DL ; Increments 8-bit register
INC [count] ; Increments the count variable
คำสั่ง DEC
คำสั่ง DEC ใช้สำหรับการลดค่าตัวถูกดำเนินการทีละตัว ทำงานบนตัวถูกดำเนินการเดียวที่สามารถอยู่ในรีจิสเตอร์หรือในหน่วยความจำ
ไวยากรณ์
คำสั่ง DEC มีไวยากรณ์ต่อไปนี้ -
DEC destination
ปลายทางตัวถูกดำเนินการอาจเป็นตัวถูกดำเนินการ 8 บิต 16 บิตหรือ 32 บิต
ตัวอย่าง
segment .data
count dw 0
value db 15
segment .text
inc [count]
dec [value]
mov ebx, count
inc word [ebx]
mov esi, value
dec byte [esi]
คำแนะนำในการเพิ่มและย่อย
คำสั่ง ADD และ SUB ใช้สำหรับการเพิ่ม / ลบข้อมูลไบนารีอย่างง่ายในขนาดไบต์คำและคำคู่เช่นสำหรับการเพิ่มหรือลบตัวถูกดำเนินการ 8 บิต 16 บิตหรือ 32 บิตตามลำดับ
ไวยากรณ์
คำสั่ง ADD และ SUB มีไวยากรณ์ต่อไปนี้ -
ADD/SUB destination, source
คำสั่ง ADD / SUB สามารถเกิดขึ้นได้ระหว่าง -
- ลงทะเบียนเพื่อลงทะเบียน
- หน่วยความจำในการลงทะเบียน
- ลงทะเบียนในหน่วยความจำ
- ลงทะเบียนกับข้อมูลคงที่
- หน่วยความจำกับข้อมูลคงที่
อย่างไรก็ตามเช่นเดียวกับคำแนะนำอื่น ๆ การดำเนินการจากหน่วยความจำต่อหน่วยความจำจะไม่สามารถทำได้โดยใช้คำสั่ง ADD / SUB ชุดการดำเนินการ ADD หรือ SUB หรือล้างแฟล็กโอเวอร์โฟลว์และดำเนินการ
ตัวอย่าง
ตัวอย่างต่อไปนี้จะถามตัวเลขสองหลักจากผู้ใช้เก็บตัวเลขในทะเบียน EAX และ EBX ตามลำดับเพิ่มค่าเก็บผลลัพธ์ไว้ในตำแหน่งหน่วยความจำ ' res ' และสุดท้ายแสดงผลลัพธ์
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .data
msg1 db "Enter a digit ", 0xA,0xD
len1 equ $- msg1
msg2 db "Please enter a second digit", 0xA,0xD
len2 equ $- msg2
msg3 db "The sum is: "
len3 equ $- msg3
segment .bss
num1 resb 2
num2 resb 2
res resb 1
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg1
mov edx, len1
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num1
mov edx, 2
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg2
mov edx, len2
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num2
mov edx, 2
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg3
mov edx, len3
int 0x80
; moving the first number to eax register and second number to ebx
; and subtracting ascii '0' to convert it into a decimal number
mov eax, [num1]
sub eax, '0'
mov ebx, [num2]
sub ebx, '0'
; add eax and ebx
add eax, ebx
; add '0' to to convert the sum from decimal to ASCII
add eax, '0'
; storing the sum in memory location res
mov [res], eax
; print the sum
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res
mov edx, 1
int 0x80
exit:
mov eax, SYS_EXIT
xor ebx, ebx
int 0x80
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานโค้ดจะได้ผลลัพธ์ดังนี้ -
Enter a digit:
3
Please enter a second digit:
4
The sum is:
7
The program with hardcoded variables −
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov eax,'3'
sub eax, '0'
mov ebx, '4'
sub ebx, '0'
add eax, ebx
add eax, '0'
mov [sum], eax
mov ecx,msg
mov edx, len
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov ecx,sum
mov edx, 1
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db "The sum is:", 0xA,0xD
len equ $ - msg
segment .bss
sum resb 1
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานโค้ดจะได้ผลลัพธ์ดังนี้ -
The sum is:
7
คำสั่ง MUL / IMUL
มีสองคำแนะนำสำหรับการคูณข้อมูลไบนารี คำสั่ง MUL (Multiply) จัดการกับข้อมูลที่ไม่ได้ลงชื่อและ IMUL (Integer Multiply) จะจัดการกับข้อมูลที่ลงนาม คำแนะนำทั้งสองมีผลต่อแฟล็ก Carry และ Overflow
ไวยากรณ์
ไวยากรณ์สำหรับคำสั่ง MUL / IMUL มีดังนี้ -
MUL/IMUL multiplier
ตัวคูณในทั้งสองกรณีจะอยู่ในตัวสะสมขึ้นอยู่กับขนาดของตัวคูณและตัวคูณและผลิตภัณฑ์ที่สร้างขึ้นจะถูกเก็บไว้ในสองรีจิสเตอร์ขึ้นอยู่กับขนาดของตัวถูกดำเนินการ ส่วนต่อไปนี้อธิบายคำแนะนำของ MUL ในกรณีที่แตกต่างกันสามกรณี -
ซีเนียร์ | สถานการณ์ |
---|---|
1 | When two bytes are multiplied − ตัวคูณอยู่ในทะเบียน AL และตัวคูณเป็นไบต์ในหน่วยความจำหรือในรีจิสเตอร์อื่น ผลิตภัณฑ์อยู่ใน AX ผลิตภัณฑ์ 8 บิตลำดับสูงจะถูกเก็บไว้ใน AH และ 8 บิตลำดับต่ำจะถูกเก็บไว้ใน AL
|
2 | When two one-word values are multiplied − ตัวคูณควรอยู่ในทะเบียน AX และตัวคูณเป็นคำในหน่วยความจำหรือรีจิสเตอร์อื่น ตัวอย่างเช่นสำหรับคำสั่งเช่น MUL DX คุณต้องจัดเก็บตัวคูณใน DX และตัวคูณใน AX ผลิตภัณฑ์ผลลัพธ์คือคำสองคำซึ่งจะต้องมีการลงทะเบียนสองรายการ ส่วนลำดับสูง (ซ้ายสุด) จะถูกเก็บไว้ใน DX และส่วนลำดับล่าง (ขวาสุด) จะถูกเก็บไว้ใน AX
|
3 | When two doubleword values are multiplied − เมื่อคูณค่า doubleword สองค่าตัวคูณควรอยู่ใน EAX และตัวคูณคือค่า doubleword ที่เก็บไว้ในหน่วยความจำหรือในรีจิสเตอร์อื่น ผลิตภัณฑ์ที่สร้างขึ้นจะถูกเก็บไว้ในรีจิสเตอร์ EDX: EAX กล่าวคือลำดับสูง 32 บิตจะถูกเก็บไว้ในรีจิสเตอร์ EDX และลำดับต่ำ 32 บิตจะถูกเก็บไว้ในทะเบียน EAX
|
ตัวอย่าง
MOV AL, 10
MOV DL, 25
MUL DL
...
MOV DL, 0FFH ; DL= -1
MOV AL, 0BEH ; AL = -66
IMUL DL
ตัวอย่าง
ตัวอย่างต่อไปนี้คูณ 3 ด้วย 2 และแสดงผลลัพธ์ -
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov al,'3'
sub al, '0'
mov bl, '2'
sub bl, '0'
mul bl
add al, '0'
mov [res], al
mov ecx,msg
mov edx, len
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov ecx,res
mov edx, 1
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db "The result is:", 0xA,0xD
len equ $- msg
segment .bss
res resb 1
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานโค้ดจะได้ผลลัพธ์ดังนี้ -
The result is:
6
คำแนะนำ DIV / IDIV
การดำเนินการหารสร้างสององค์ประกอบ - ก quotient และก remainder. ในกรณีของการคูณการล้นจะไม่เกิดขึ้นเนื่องจากมีการใช้รีจิสเตอร์ความยาวสองเท่าเพื่อเก็บผลิตภัณฑ์ไว้ อย่างไรก็ตามในกรณีของการแบ่งอาจเกิดการล้น โปรเซสเซอร์จะสร้างอินเทอร์รัปต์หากเกิดโอเวอร์โฟลว์
คำสั่ง DIV (Divide) ใช้สำหรับข้อมูลที่ไม่ได้ลงชื่อและ IDIV (Integer Divide) ใช้สำหรับข้อมูลที่เซ็นชื่อ
ไวยากรณ์
รูปแบบสำหรับคำสั่ง DIV / IDIV -
DIV/IDIV divisor
เงินปันผลอยู่ในตัวสะสม คำสั่งทั้งสองสามารถทำงานร่วมกับตัวถูกดำเนินการ 8 บิต 16 บิตหรือ 32 บิต การดำเนินการมีผลต่อแฟล็กสถานะทั้งหกสถานะ ส่วนต่อไปนี้อธิบายกรณีการแบ่งสามกรณีที่มีขนาดตัวถูกดำเนินการต่างกัน -
ซีเนียร์ | สถานการณ์ |
---|---|
1 | When the divisor is 1 byte − เงินปันผลจะถือว่าอยู่ในการลงทะเบียน AX (16 บิต) หลังจากหารแล้วผลหารจะไปที่รีจิสเตอร์ AL และส่วนที่เหลือจะไปที่รีจิสเตอร์ AH
|
2 | When the divisor is 1 word − การจ่ายเงินปันผลจะถือว่ามีความยาว 32 บิตและในการลงทะเบียน DX: AX 16 บิตลำดับสูงอยู่ใน DX และ 16 บิตลำดับต่ำอยู่ใน AX หลังจากหารแล้วผลหาร 16 บิตจะไปที่รีจิสเตอร์ AX และส่วนที่เหลือ 16 บิตจะไปที่รีจิสเตอร์ DX
|
3 | When the divisor is doubleword − การจ่ายเงินปันผลจะถือว่ายาว 64 บิตและในการลงทะเบียน EDX: EAX 32 บิตลำดับสูงอยู่ใน EDX และ 32 บิตลำดับต่ำอยู่ใน EAX หลังจากหารแล้วผลหาร 32 บิตจะไปที่รีจิสเตอร์ EAX และส่วนที่เหลือ 32 บิตจะไปที่รีจิสเตอร์ EDX
|
ตัวอย่าง
ตัวอย่างต่อไปนี้หาร 8 ด้วย 2 dividend 8 ถูกเก็บไว้ในไฟล์ 16-bit AX register และ divisor 2 ถูกเก็บไว้ในไฟล์ 8-bit BL register.
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov ax,'8'
sub ax, '0'
mov bl, '2'
sub bl, '0'
div bl
add ax, '0'
mov [res], ax
mov ecx,msg
mov edx, len
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov ecx,res
mov edx, 1
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db "The result is:", 0xA,0xD
len equ $- msg
segment .bss
res resb 1
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานโค้ดจะได้ผลลัพธ์ดังนี้ -
The result is:
4