🔬 آموزش کامل اسمبلی x86-64 از صفر تا صد (NASM + Linux) (آموزش عمیق)

Assembly همه سطوح
parsakarimidev.ir

🔬 آموزش کامل اسمبلی x86-64 از صفر تا صد (NASM + Linux) (آموزش عمیق)

Assemblyمفهوم سطح: همه سطوح 1405/07/09

آموزش کامل اسمبلی x86-64 از صفر تا صد (NASM + Linux)

⚡ خلاصه سریع — اصل کاری‌ها

این‌ها مهم‌ترین چیزهایی هستن که اگه هیچی ندونی، فقط اینا رو بدونی کافیه:

  • اسمبلی زبان قابل خواندن برای CPU است؛ هر دستور تقریباً مستقیم به یک کد ماشین تبدیل می‌شود.
  • رجیسترها حافظه‌های خیلی سریع داخل CPU هستند؛ مهم‌ترین‌ها: rax، rbx، rcx، rdx، rsi، rdi، rsp، rbp، r8-r15.
  • سینتکس NASM اینتل است: mov rax, 1 یعنی مقدار ۱ را در رجیستر rax قرار بده.
  • آدرس‌دهی حافظه با [base + index*scale + displacement] انجام می‌شود.
  • فراخوانی سیستم لینوکس روی x86-64 با دستور syscall انجام می‌شود: شماره در rax و آرگومان‌ها در rdi، rsi، rdx، r10، r8، r9.
  • سکشن‌ها .data برای داده‌های مقداردار، .bss برای داده‌های صفرنشده و .text برای کد است.
  • پشته با push و pop مدیریت می‌شود؛ مکانیزم فراخوانی توابع هم call و ret است.
  • خروج از برنامه بدون syscall شماره ۶۰ باعث Segmentation Fault می‌شود.

۳ اشتباه رایج که باید ازشون پرهیز کنی:

  1. فراموش کردن syscall خروج (mov rax, 60 + syscall).
  2. استفاده از mov برای انتقال مستقیم حافظه به حافظه (mov [a], [b] غیرمجاز است).
  3. قاطی کردن سینتکس AT&T و Intel — در NASM مقصد اول است.

اگر فقط ۵ دقیقه وقت داری، این‌ها رو یاد بگیر:

  1. mov برای جابه‌جایی داده بین رجیستر/حافظه/مقدار ثابت.
  2. syscall برای صحبت با سیستمعامل و خروج از برنامه.
  3. ساختار _start و نحوه مونت/لینک کردن با nasm و ld.

۱. مقدمه

اسمبلی چیست؟

اسمبلی نزدیک‌ترین زبان برنامه‌نویسی به زبان ماشین است. هر دستور اسمبلی معمولاً دقیقاً یک کار ساده انجام می‌دهد:

mov rax, 42

یعنی عدد ۴۲ را داخل رجیستر rax بگذار. همین یک خط توسط مونت‌کننده (Assembler) به چند بایت کد ماشین تبدیل می‌شود که CPU آن را اجرا می‌کند.

چرا باید اسمبلی یاد بگیریم؟

  • درک عمیق سخت‌افزار: می‌فهمی CPU چطور داده را جابه‌جا می‌کند، مقایسه می‌کند و تصمیم می‌گیرد.
  • مهندسی معکوس و امنیت: بدافزارها، کرک نرم‌افزار، تحلیل باینری و اکسپلویت‌نویسی.
  • سیستم‌عامل و هسته‌نویسی: بوت‌لودرها، درایورها و بخش‌های سطح پایین.
  • بهینه‌سازی: کامپایلرها را بهتر می‌فهمی و می‌توانی کد C/C++ بهتری بنویسی.
  • ابزارسازی: دیباگر، شبیه‌ساز، ماشین مجازی و کتابخانه‌های runtime.

کجا استفاده می‌شود؟

  • بوت‌لودرها و firmware
  • کرنل لینوکس و ویندوز
  • درایورهای سخت‌افزاری
  • موتورهای بازی برای بهینه‌سازی مسیرهای داغ
  • ابزارهای مهندسی معکوس
  • بدافزار و آنتی‌ویروس
  • سیستم‌های نهفته (Embedded) با منابع محدود

۲. پیش‌نیازها

چیزهایی که بهتر است از قبل بدانی

  • مفاهیم پایه برنامه‌نویسی: متغیر، حلقه، شرط، تابع
  • آشنایی ابتدایی با سیستم‌عامل لینوکس و ترمینال
  • عدد دودویی و هگزادسیمال
  • اینکه CPU چیست و حافظه یعنی چه

ابزارهای لازم

ابزار کاربرد
NASM مونت‌کننده x86-64
ld لینک‌کننده GNU
gdb دیباگر
objdump مشاهده disassembly
readelf مشاهده ساختار فایل ELF
strace ردیابی syscallها
ویرایشگر متن Vim، VS Code، nano

۳. نصب و راه‌اندازی

نصب روی دبیان/اوبونتو

sudo apt update
sudo apt install -y nasm binutils gdb

نصب روی آرچ

sudo pacman -S nasm binutils gdb

بررسی نصب

nasm -v
ld -v
gdb --version

اولین پروژه: چاپ Hello Assembly

فایل hello.asm را بساز:

section .data
    msg db "Hello, Assembly!", 10
    len equ $ - msg

section .text
    global _start

_start:
    mov rax, 1          ; sys_write
    mov rdi, 1          ; stdout
    mov rsi, msg        ; آدرس رشته
    mov rdx, len        ; طول رشته
    syscall             ; فراخوانی کرنل

    mov rax, 60         ; sys_exit
    xor rdi, rdi        ; کد خروج ۰
    syscall

مونت و لینک

nasm -f elf64 hello.asm -o hello.o
ld hello.o -o hello
./hello

خروجی:

Hello, Assembly!

بررسی کد خروج:

echo $?

خروجی:

0

۴. مفاهیم پایه

۴.۱ رجیسترها

رجیسترها حافظه‌های کوچک اما فوق‌سریع داخل پردازنده هستند. در x86-64 این رجیسترهای عمومی مهم‌اند:

رجیستر ۶۴ بیتی رجیستر ۳۲ بیتی رجیستر ۱۶ بیتی رجیستر ۸ بیتی (پایین) کاربرد رایج
rax eax ax al مقدار بازگشتی توابع، جمع/ضرب
rbx ebx bx bl پایه داده، callee-saved
rcx ecx cx cl شمارنده حلقه
rdx edx dx dl داده، باقیمانده تقسیم
rsi esi si sil آرگومان دوم، ایندکس مبدا
rdi edi di dil آرگومان اول، ایندکس مقصد
rbp ebp bp bpl Base Pointer در stack frame
rsp esp sp spl Stack Pointer
r8-r15 r8d-r15d r8w-r15w r8b-r15b رجیسترهای عمومی اضافه

۴.۲ سکشن‌ها

section .data
    ; داده‌های مقداردار فقط‌خواندنی/خواندنی-نوشتنی

section .bss
    ; داده‌های بدون مقدار اولیه که صفر می‌شوند

section .text
    ; کد اجرایی

مثال:

section .data
    name db "Sara", 0
    age dq 30

section .bss
    buffer resb 128
    array resq 10

section .text
    global _start
_start:
    mov al, [name]
    mov rax, [age]
    ; ...

۴.۳ فرمت دستورها

دستورهای NASM معمولاً این شکلی هستند:

mnemonic destination, source

مثال:

mov rax, 5
add rax, rbx
cmp rax, 10

۴.۴ اعداد: باینری، هگز، دسیمال

mov rax, 10          ; ده‌دهی
mov rax, 0b1010      ; باینری
mov rax, 0xA         ; هگزادسیمال
mov rax, 0o12        ; اکتال

۴.۵ دایرکتیوهای مهم NASM

دایرکتیو معنی مثال
db بایت db 0x41
dw word دو بایتی dw 0x1234
dd double word چهار بایتی dd 0xDEADBEEF
dq quad word هشت بایتی dq 0x123456789
resb رزرو بایت در .bss buffer resb 64
resq رزرو qword در .bss arr resq 5
equ تعریف ثابت len equ $ - msg
times تکرار times 5 db 0
align تراز آدرس align 16

۴.۶ آدرس‌دهی حافظه

فرمول کلی:

[base + index*scale + displacement]

مثال:

mov rax, [rbx]              ; فقط base
mov rax, [rbx + 8]          ; base + offset
mov rax, [rbx + rcx*4]      ; base + index*scale
mov rax, [rbx + rcx*4 + 16] ; کاملترین فرم
  • scale فقط ۱، ۲، ۴ یا ۸ می‌تواند باشد.
  • rsp نمی‌تواند به‌عنوان index استفاده شود.

۴.۷ فلگ‌ها

CPU یک رجیستر به نام rflags دارد که بعد از بسیاری از دستورها به‌روز می‌شود:

فلگ معنی
CF Carry Flag — بیت نقلی
ZF Zero Flag — نتیجه صفر
SF Sign Flag — بیت علامت
OF Overflow Flag — سرریز علامت‌دار
PF Parity Flag — زوج بودن تعداد بیت‌های ۱
AF Auxiliary Carry — نقلی در BCD

۵. مثال‌های کد ساده

۵.۱ خروج با کد دلخواه

section .text
    global _start

_start:
    mov rdi, 7
    mov rax, 60
    syscall

اجرا:

nasm -f elf64 exit.asm -o exit.o
ld exit.o -o exit
./exit
echo $?

خروجی:

7

۵.۲ جمع دو عدد و خروج با نتیجه

section .text
    global _start

_start:
    mov rax, 20
    add rax, 22

    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

42

۵.۳ حلقه ساده از ۵ به ۱

section .text
    global _start

_start:
    mov rcx, 5

.loop:
    dec rcx
    jnz .loop

    xor rdi, rdi
    mov rax, 60
    syscall

۵.۴ شرط و پرش

section .text
    global _start

_start:
    mov rax, 10
    cmp rax, 10
    je .equal

    mov rdi, 1
    jmp .done

.equal:
    xor rdi, rdi

.done:
    mov rax, 60
    syscall

خروجی:

0

۵.۵ تابع ساده با call و ret

section .text
    global _start

_start:
    call add_three
    mov rdi, rax
    mov rax, 60
    syscall

add_three:
    mov rax, 2
    add rax, 3
    ret

خروجی:

5

۵.۶ جمع اعضای آرایه

section .data
    nums dq 1, 2, 3, 4, 5
    len equ 5

section .text
    global _start

_start:
    xor rax, rax
    xor rcx, rcx

.loop:
    add rax, [nums + rcx*8]
    inc rcx
    cmp rcx, len
    jl .loop

    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

15

۶. مثال واقعی و کاربردی

پروژه: محاسبه فاکتوریل ۵ و چاپ نتیجه

در این پروژه عدد ۵ را فاکتوریل می‌کنیم و عدد ۱۲۰ را به‌صورت رشته در خروجی چاپ می‌کنیم.

section .data
    msg db "Factorial of 5 is: "
    msg_len equ $ - msg
    newline db 10

section .bss
    num_buf resb 32

section .text
    global _start

print_number:
    ; ورودی: rax = عدد
    ; خروجی: عدد به‌صورت متن روی stdout
    mov rdi, num_buf
    add rdi, 31
    mov byte [rdi], 0
    mov rbx, 10
    xor rcx, rcx

.reverse:
    xor rdx, rdx
    div rbx
    add dl, '0'
    dec rdi
    mov [rdi], dl
    inc rcx
    test rax, rax
    jnz .reverse

    mov rdx, rcx
    mov rsi, rdi
    mov rax, 1
    mov rdi, 1
    syscall
    ret

_start:
    ; محاسبه ۵! = ۱۲۰
    mov rax, 1
    mov rcx, 1

.factorial_loop:
    imul rax, rcx
    inc rcx
    cmp rcx, 5
    jle .factorial_loop

    ; چاپ پیام
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, msg_len
    syscall

    ; چاپ عدد
    call print_number

    ; چاپ خط جدید
    mov rax, 1
    mov rdi, 1
    mov rsi, newline
    mov rdx, 1
    syscall

    ; خروج
    mov rax, 60
    xor rdi, rdi
    syscall

اجرا:

nasm -f elf64 factorial.asm -o factorial.o
ld factorial.o -o factorial
./factorial

خروجی:

Factorial of 5 is: 120

۷. مباحث پیشرفته

۷.۱ Calling Convention در x86-64 System V

وقتی از C یا زبانی دیگر با اسمبلی ارتباط می‌گیری، این قرارداد را رعایت کن:

مورد رجیستر
آرگومان اول rdi
آرگومان دوم rsi
آرگومان سوم rdx
آرگومان چهارم rcx
آرگومان پنجم r8
آرگومان ششم r9
مقدار بازگشتی rax
آرگومان‌های بیشتر روی پشته
callee-saved rbx، rbp، r12-r15
caller-saved rax، rcx، rdx، rsi، rdi، r8-r11

۷.۲ Stack Frame استاندارد

my_function:
    push rbp
    mov rbp, rsp
    sub rsp, 32          ; فضای متغیرهای محلی

    mov [rbp-8], rax     ; متغیر محلی

    ; ...

    leave                ; mov rsp, rbp + pop rbp
    ret

۷.۳ ماکروها در NASM

%macro sys_write 2
    mov rax, 1
    mov rdi, 1
    mov rsi, %1
    mov rdx, %2
    syscall
%endmacro

section .data
    msg db "Hello", 5

section .text
    global _start
_start:
    sys_write msg, 5
    mov rax, 60
    xor rdi, rdi
    syscall

۷.۴ اتصال اسمبلی و C

فایل add.asm:

global add_nums

section .text
add_nums:
    lea rax, [rdi + rsi]
    ret

فایل main.c:

#include <stdio.h>

extern long add_nums(long, long);

int main(void) {
    printf("%ld\n", add_nums(3, 4));
    return 0;
}

کامپایل:

nasm -f elf64 add.asm -o add.o
gcc -no-pie main.c add.o -o program
./program

خروجی:

7

۷.۵ دیباگ با GDB

nasm -f elf64 -g -F dwarf hello.asm -o hello.o
ld hello.o -o hello
gdb ./hello

در gdb:

break _start
run
info registers
layout asm
layout regs
stepi
nexti
x/10gx $rsp
disassemble /r _start

۷.۶ نگاهی به SIMD

x86-64 رجیسترهای ۱۲۸/۲۵۶ بیتی xmm0-xmm15 و ymm0-ymm15 دارد:

movdqa xmm0, [source]
paddd xmm0, xmm1

این دستورها چند داده را همزمان پردازش می‌کنند.

۸. اشتباهات رایج

۸.۱ فراموش کردن خروج از برنامه

; ❌ اشتباه
_start:
    mov rax, 1
    mov rdi, 1
    syscall

; ✅ درست
_start:
    mov rax, 1
    mov rdi, 1
    syscall

    mov rax, 60
    xor rdi, rdi
    syscall

۸.۲ انتقال حافظه به حافظه

; ❌ اشتباه
mov [a], [b]

; ✅ درست
mov rax, [b]
mov [a], rax

۸.۳ ناسازگاری اندازه

; ❌ اشتباه
mov rax, [small_byte]

; ✅ درست
mov al, [small_byte]
; یا
movzx rax, byte [small_byte]

۸.۴ فراموش کردن صفر کردن rdx قبل از تقسیم

; ❌ اشتباه
mov rax, 17
mov rcx, 5
div rcx

; ✅ درست
mov rax, 17
xor rdx, rdx
mov rcx, 5
div rcx

۸.۵ استفاده از پرش علامت‌دار به‌جای بدون‌علامت

; وقتی اعداد بدون‌علامت هستند
; ❌ استفاده از jg
cmp rax, rbx
jg .label

; ✅ استفاده از ja
cmp rax, rbx
ja .label

۸.۶ فرض صفر بودن رجیسترها در شروع

رجیسترها در شروع برنامه یا بعد از syscall مقدار نامعلوم دارند. همیشه مقداردهی صریح کن.

۸.۷ بهم‌ریختن پشته

; ❌ push بدون pop
foo:
    push rax
    ret

; ✅ متعادل
foo:
    push rax
    pop rax
    ret

۸.۸ فراموش کردن global _start

بدون global _start لینک‌کننده نقطه شروع پیدا نمی‌کند.

۹. بهترین روش‌ها (Best Practices)

۹.۱ صفر کردن رجیستر

; ❌ کندتر و طولانی‌تر
mov rax, 0

; ✅ سریع‌تر و بهینه‌تر
xor rax, rax

۹.۲ استفاده از equ برای ثابت‌ها

STDOUT equ 1
SYS_EXIT equ 60

۹.۳ استفاده از label های محلی

.loop:
    dec rcx
    jnz .loop

۹.۴ توضیح‌گذاری منطقی

    mov rsi, msg        ; آرگومان دوم: اشاره‌گر به متن
    mov rdx, len        ; آرگومان سوم: طول متن

۹.۵ استفاده از lea برای محاسبه آدرس

; به‌جای
mov rax, rbx
add rax, rcx
shl rax, 2

; استفاده کن از
lea rax, [rbx + rcx*4]

۹.۶ رعایت قرارداد توابع

در توابعی که قرار است با C link شوند، رجیسترهای rbx, rbp, r12-r15 را حفظ کن.

۹.۷ جدول syscall کنار دستت باشد

شماره‌های مهم:

syscall شماره
read 0
write 1
open 2
close 3
mmap 9
exit 60

۹.۸ از دیباگر استفاده کن

نه فقط برای رفع خطا، بلکه برای دیدن واقعی رفتار CPU.

۱۰. منابع و ادامه مسیر

کتاب‌ها

  • Programming from the Ground Up — Jonathan Bartlett
  • Assembly Language Step-by-Step — Jeff Duntemann
  • The Art of 64-bit Assembly — Randall Hyde

سایت‌ها و مستندات

  • Intel SDM: مستندات رسمی پردازنده‌های اینتل
  • AMD Manuals: مستندات رسمی AMD
  • syscall.sh: جدول syscall لینوکس
  • Compiler Explorer (godbolt.org): مشاهده خروجی اسمبلی کامپایلرها
  • OSDev Wiki: آموزش توسعه سیستم‌عامل و اسمبلی سطح پایین

ابزارهای سطح بعد

  • gdb + pwndbg: دیباگ امنیتی و اکسپلویت
  • Ghidra / IDA: مهندسی معکوس
  • radare2 / rizin: تحلیل باینری
  • objdump و readelf: بررسی فایل‌های ELF
  • strace: ردیابی syscallهای برنامه

مسیرهای ادامه

  • لینک کردن اسمبلی با C/C++
  • نوشتن bootloader
  • یادگیری SIMD و AVX
  • مهندسی معکوس و اکسپلویت‌نویسی
  • توسعه کرنل و درایور
  • بهینه‌سازی حلقه‌های حساس با اسمبلی

۱۱. مرجع کامل توابع و متدها (API Deep Dive)

در اسمبلی مفهوم متد نداریم؛ اما هر دستور مثل یک تابع کوچک CPU است. برای درک دقیق، مهم‌ترین دستورها را با ساختار متد بررسی می‌کنیم.

📌 نام متد: mov()

امضای متد (Signature):

mov destination, source

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
destination register یا memory بله محل مقصد rax, [rbx]
source register یا immediate یا memory بله مقدار منبع 0x10, rcx, [var]

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: فقط مقدار منبع را در مقصد می‌نویسد
  • فلگ‌ها را تغییر نمی‌دهد

کاری که انجام می‌ده (گام به گام):

۱. ترکیب عملوندها را اعتبارسنجی می‌کند.
۲. مقدار منبع را می‌خواند.
۳. اگر منبع رجیستر/حافظه باشد، مقدار آن را می‌گیرد.
۴. مقدار را در مقصد می‌نویسد.
۵. به دستور بعدی می‌رود.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    mov rax, 42
    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

42

مثال واقعی و کاربردی:

section .data
    status dq 5

section .text
    global _start
_start:
    mov rax, [status]   ; خواندن وضعیت از حافظه
    mov rdi, rax
    mov rax, 60
    syscall

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#PF آدرس حافظه نامعتبر اشاره‌گر را بررسی کن
#GP ترکیب عملوند نامعتبر مثل mov [a], [b] از رجیستر واسط استفاده کن
#UD کد ماشین نامعتبر سینتکس را تصحیح کن

Overloadها:

mov rax, rbx              ;; register -> register
mov rax, 0x1234           ;; immediate -> register
mov rax, [var]            ;; memory -> register
mov [var], rax            ;; register -> memory
mov byte [var], 0x12      ;; immediate -> memory با ذکر اندازه
mov rax, qword [var]      ;; explicit size

اشتباهات رایج:

  • ❌ mov [a], [b] → ✅ mov rax, [b] + mov [a], rax
  • ❌ mov rax, byte_var بدون hematching size → ✅ mov al, [byte_var]

متدهای مرتبط:

  • lea — محاسبه آدرس بدون دسترسی به حافظه
  • movzx — انتقال با توسعه صفر
  • movsx — انتقال با توسعه علامت

📌 نام متد: add()

امضای متد (Signature):

add destination, source

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
destination register یا memory بله عدد مقصد که با منبع جمع می‌شود rax, [counter]
source register یا immediate یا memory بله عدد منبع 5, rbx

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: نتیجه جمع در مقصد ذخیره می‌شود
  • فلگ‌های CF, ZF, SF, OF, PF, AF به‌روز می‌شوند

کاری که انجام می‌ده (گام به گام):

۱. مقدار منبع را می‌خواند.
۲. مقدار مقصد را می‌خواند.
۳. جمع می‌کند.
۴. نتیجه را در مقصد می‌نویسد.
۵. فلگ‌ها را تنظیم می‌کند.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    mov rax, 20
    add rax, 22
    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

42

مثال واقعی و کاربردی:

    add rax, [rcx + rdi*4] ; جمع عضو آرایه با رجیستر accumulator

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#PF دسترسی به حافظه نامعتبر بررسی آدرس
#GP سایز عملوند نامعتبر تعیین اندازه عملوند

Overloadها:

add rax, rbx             ;; reg <- reg
add rax, 10              ;; reg <- imm
add rax, [var]           ;; reg <- mem
add [var], rax           ;; mem <- reg
add byte [var], 1        ;; mem <- imm

اشتباهات رایج:

  • ❌ add [a], [b] → ✅ انتقال یک طرف به رجیستر

متدهای مرتبط:

  • sub — تفریق
  • inc — افزایش یک واحدی
  • adc — جمع با بیت نقلی

📌 نام متد: sub()

امضای متد (Signature):

sub destination, source

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
destination register یا memory بله عددی که از آن کم می‌شود rbx
source register یا immediate یا memory بله مقدار کسرشونده 10

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: نتیجه destination = destination - source
  • فلگ‌های CF, ZF, SF, OF, PF, AF به‌روز می‌شوند

کاری که انجام می‌ده (گام به گام):

۱. مقدار منبع را می‌خواند.
۲. مقدار مقصد را می‌خواند.
۳. تفریق می‌کند.
۴. نتیجه را در مقصد می‌نویسد.
۵. فلگ‌ها را تنظیم می‌کند.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    mov rax, 50
    sub rax, 8
    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

42

مثال واقعی و کاربردی:

    sub rcx, 1          ; شمارنده را کم کن
    jnz .loop

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#PF آدرس حافظه نامعتبر بررسی اشاره‌گر
#GP ترکیب عملوند نامعتبر اصلاح سایز/ترکیب

Overloadها:

sub rax, rbx
sub rax, 10
sub rax, [var]
sub [var], rax
sub word [var], 2

اشتباهات رایج:

  • ❌ sub [a], [b] → ✅ از رجیستر واسط استفاده کن

متدهای مرتبط:

  • add — جمع
  • dec — کاهش یک واحدی
  • sbb — تفریق با بیت نقلی

📌 نام متد: cmp()

امضای متد (Signature):

cmp left, right

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
left register بله عملوند سمت چپ rax
right register یا immediate یا memory بله عملوند سمت راست 10

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: نتیجه نوشته نمی‌شود؛ فقط فلگ‌ها تنظیم می‌شوند
  • محاسبه left - right بدون ذخیره نتیجه

کاری که انجام می‌ده (گام به گام):

۱. مقدار راست را از چپ کم می‌کند.
۲. حاصل را دور می‌ریزد.
۳. فلگ‌های CF, ZF, SF, OF, PF, AF را به‌روز می‌کند.
۴. دستور بعدی معمولاً یک پرش شرطی است.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    mov rax, 10
    cmp rax, 10
    je .equal
    mov rdi, 1
    jmp .done
.equal:
    xor rdi, rdi
.done:
    mov rax, 60
    syscall

خروجی echo $?:

0

مثال واقعی و کاربردی:

    cmp byte [input], 'q'
    je .quit

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#PF آدرس حافظه نامعتبر بررسی اشاره‌گر

Overloadها:

cmp rax, rbx
cmp rax, 10
cmp rax, [var]
cmp [var], rax
cmp byte [var], 0

اشتباهات رایج:

  • ❌ استفاده از cmp بدون پرش بعدی و انتظار تغییر مقصد
  • ❌ فراموش کردن اینکه cmp عملوندها را تغییر نمی‌دهد

متدهای مرتبط:

  • test — بررسی بیتی بدون ذخیره نتیجه
  • sub — تفریق واقعی
  • jcc — پرش بر اساس فلگ‌ها

📌 نام متد: Jcc()

امضای متد (Signature):

jcc target

که cc یکی از condition codeها است: e، ne، g، ge، l، le، a، ae، b، be، z، nz، s، ns، o، no.

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
condition code بخشی از mnemonic بله شرط پرش je, jg
target label بله مقصد پرش .loop

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: اگر شرط برقرار باشد، RIP به مقصد تغییر می‌کند؛ وگرنه اجرا ادامه می‌یابد

کاری که انجام می‌ده (گام به گام):

۱. فلگ‌های rflags را بررسی می‌کند.
۲. شرط cc را با جدول شرایط مقایسه می‌کند.
۳. اگر درست بود، آدرس دستور بعدی را با مقصد جایگزین می‌کند.
۴. اگر نادرست بود، هیچ تغییری در جریان اجرا نمی‌دهد.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    mov rax, 5
    cmp rax, 5
    je .same
    mov rdi, 1
    jmp .done
.same:
    xor rdi, rdi
.done:
    mov rax, 60
    syscall

خروجی echo $?:

0

مثال واقعی و کاربردی:

    cmp rcx, len
    jl .loop

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#GP مقصد خارج از محدوده پرش از label نزدیک استفاده کن

Overloadها / جدول شرط‌ها:

دستور معنی شرط فلگ
je / jz مساوی / صفر ZF=1
jne / jnz نامساوی / غیرصفر ZF=0
jg بزرگ‌تر علامت‌دار ZF=0 and SF=OF
jge بزرگ‌تر یا مساوی علامت‌دار SF=OF
jl کوچک‌تر علامت‌دار SF!=OF
jle کوچک‌تر یا مساوی علامت‌دار ZF=1 or SF!=OF
ja بزرگ‌تر بدون‌علامت CF=0 and ZF=0
jb کوچک‌تر بدون‌علامت CF=1
js منفی SF=1
jns غیرمنفی SF=0
jo سرریز OF=1

اشتباهات رایج:

  • ❌ استفاده از jg برای اعداد بدون‌علامت → ✅ ja
  • ❌ استفاده از je بعد از add به‌جای cmp بدون توجه به فلگ

متدهای مرتبط:

  • cmp — تنظیم فلگ برای پرش
  • jmp — پرش بدون شرط
  • test — تنظیم فلگ با AND بیتی

📌 نام متد: call()

امضای متد (Signature):

call target

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
target label/register/memory بله آدرس تابع یا label my_func, rax, [func_ptr]

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: آدرس بازگشت روی پشته push می‌شود و RIP به تابع مقصد می‌رود

کاری که انجام می‌ده (گام به گام):

۱. آدرس دستور بعدی را محاسبه می‌کند.
۲. آن آدرس را روی پشته push می‌کند.
۳. آدرس مقصد را در RIP می‌گذارد.
۴. اجرا در تابع مقصد ادامه می‌یابد.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    call foo
    mov rdi, rax
    mov rax, 60
    syscall

foo:
    mov rax, 7
    ret

خروجی echo $?:

7

مثال واقعی و کاربردی:

    call compute_total
    mov [total], rax

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#SS پشته پر یا آدرس نامعتبر تنظیم stack
#PF مقصد نامعتبر بررسی آدرس تابع

Overloadها:

call my_function          ;; پرش نسبی به label
call rax                  ;; فراخوانی غیرمستقیم از رجیستر
call [function_pointer]   ;; فراخوانی از حافظه

اشتباهات رایج:

  • ❌ فراخوانی تابعی که ret ندارد
  • ❌ بهم‌ریختن alignment پشته در تعامل با C

متدهای مرتبط:

  • ret — بازگشت از تابع
  • jmp — پرش بدون ذخیره آدرس بازگشت
  • push / pop — مدیریت پشته

📌 نام متد: ret()

امضای متد (Signature):

ret
ret imm16

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
immediate 16 بیتی immediate خیر تعداد بایت‌های پاک‌شونده از پشته پس از بازگشت ret 16

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: آدرس بازگشت از پشته pop و به RIP منتقل می‌شود

کاری که انجام می‌ده (گام به گام):

۱. مقدار بالای پشته را pop می‌کند.
۲. آن را در RIP قرار می‌دهد.
۳. اگر عملوند داشته باشد، مقدار آن را به RSP اضافه می‌کند.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    call get_number
    mov rdi, rax
    mov rax, 60
    syscall

get_number:
    mov rax, 9
    ret

خروجی echo $?:

9

مثال واقعی و کاربردی:

    ret 16      ; بازگشت و پاک‌سازی ۱۶ بایت آرگومان از پشته

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#SS پشته نامعتبر بررسی RSP
#PF آدرس بازگشت نامعتبر بررسی call متعادل

Overloadها:

ret
ret 16

اشتباهات رایج:

  • ❌ ret بدون call قبلی → پریدن به آدرس نامعتبر
  • ❌ عدم پاک‌سازی آرگومان‌های پشته در توابع stdcall-like

متدهای مرتبط:

  • call — فراخوانی تابع
  • push — ذخیره آدرس بازگشت
  • pop — بازیابی آدرس

📌 نام متد: push()

امضای متد (Signature):

push source

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
source register64 / memory64 / immediate32 بله مقداری که روی پشته می‌رود rax, qword [var], 42

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: RSP را ۸ واحد کم می‌کند و مقدار را در آن آدرس می‌نویسد

کاری که انجام می‌ده (گام به گام):

۱. RSP = RSP - 8
۲. مقدار منبع را در [RSP] می‌نویسد.
۳. در x86-64، اندازه عملوند ۶۴ بیتی است.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    push 7
    pop rdi
    mov rax, 60
    syscall

خروجی echo $?:

7

مثال واقعی و کاربردی:

    push rax        ; ذخیره موقت رجیستر قبل از call
    push rbx
    call function
    pop rbx
    pop rax

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#SS سرریز پشته محدودیت stack را بررسی کن
#PF دسترسی غیرمجاز به صفحه پشته آرایه‌های بزرگ روی heap ببر

Overloadها:

push rax
push qword [var]
push 10          ;; imm32 sign-extended به 64 بیت

اشتباهات رایج:

  • ❌ push eax در حالت ۶۴ بیتی → ✅ push rax
  • ❌ push/pop نامتعادل

متدهای مرتبط:

  • pop — بازیابی از پشته
  • call — push آدرس بازگشت
  • ret — pop آدرس بازگشت

📌 نام متد: pop()

امضای متد (Signature):

pop destination

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
destination register64 یا memory64 بله محل ذخیره مقدار بالای پشته rbx, [var]

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: مقدار بالای پشته را در مقصد می‌نویسد و RSP را ۸ واحد زیاد می‌کند

کاری که انجام می‌ده (گام به گام):

۱. مقدار [RSP] را می‌خواند.
۲. آن را در مقصد می‌نویسد.
۳. RSP = RSP + 8

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    push 42
    pop rax
    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

42

مثال واقعی و کاربردی:

    pop rbx            ; بازیابی مقدار ذخیره‌شده

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#SS pop از پشته خالی push/pop را متعادل کن
#PF آدرس پشته نامعتبر بررسی RSP

Overloadها:

pop rax
pop qword [var]

اشتباهات رایج:

  • ❌ pop بدون push قبلی
  • ❌ چیدن نادرست ترتیب pop نسبت به push

متدهای مرتبط:

  • push — ذخیره روی پشته
  • call / ret

📌 نام متد: lea()

امضای متد (Signature):

lea destination, [address_expression]

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
destination register بله رجیستری که آدرس محاسبه‌شده را می‌گیرد rax
address_expression memory expression بله عبارتی که آدرس‌اش محاسبه می‌شود [rbx + rcx*4 + 8]

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: آدرس مؤثر بدون دسترسی به حافظه در مقصد قرار می‌گیرد

کاری که انجام می‌ده (گام به گام):

۱. آدرس مؤثر عبارت inside brackets را محاسبه می‌کند.
۲. فقط آدرس محاسبه‌شده را در مقصد می‌نویسد.
۳. هیچ‌گونه dereference انجام نمی‌شود.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    mov rsi, 42
    lea rax, [rsi + 8]
    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

50

مثال واقعی و کاربردی:

    lea rax, [arr + rcx*8]   ; آدرس عنصر rcx ام آرایه را بگیر
    mov rdi, [rax]

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#GP ترکیب نامعتبر در آدرس‌دهی بررسی scale/index

Overloadها:

lea rax, [rbx]
lea rax, [rbx + 8]
lea rax, [rbx + rcx*4]
lea rax, [rbx + rcx*4 + 16]

اشتباهات رایج:

  • ❌ فکر کردن اینکه lea مقدار حافظه را می‌خواند
  • ❌ استفاده از mov برای محاسبه آدرس و تحمل چند دستور اضافی

متدهای مرتبط:

  • mov — انتقال مقدار حافظه یا رجیستر
  • add — محاسبه آدرس دست‌ساز
  • shl — ضرب با توان دو

📌 نام متد: syscall()

امضای متد (Signature):

syscall

ورودی‌ها (Parameters):

نام پارامتر رجیستر نوع اجباری؟ توضیح دقیق مثال مقدار
syscall number rax integer بله شماره سرویس کرنل 60
arg1 rdi integer/pointer بستگی به سرویس آرگومان اول 1
arg2 rsi integer/pointer بستگی به سرویس آرگومان دوم msg
arg3 rdx integer/pointer بستگی به سرویس آرگومان سوم len
arg4 r10 integer/pointer بستگی به سرویس آرگومان چهارم 0
arg5 r8 integer/pointer بستگی به سرویس آرگومان پنجم 0
arg6 r9 integer/pointer بستگی به سرویس آرگومان ششم 0

مقدار برگشتی (Return Value):

  • نوع: integer/pointer در rax
  • توضیح: مقدار موفق یا -errno منفی در خطا
  • rcx و r11 خراب می‌شوند

کاری که انجام می‌ده (گام به گام):

۱. CPU وارد حالت کرنل می‌شود.
۲. کرنل شماره syscall را از rax می‌خواند.
۳. آرگومان‌ها را از رجیسترها می‌گیرد.
۴. سرویس را اجرا می‌کند.
۵. نتیجه را در rax می‌گذارد.
۶. به user mode برمی‌گردد.

مثال ساده و قابل اجرا:

section .data
    msg db "Hello", 10
    len equ $ - msg

section .text
    global _start
_start:
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, len
    syscall

    mov rax, 60
    xor rdi, rdi
    syscall

خروجی:

Hello

مثال واقعی و کاربردی:

    ; خواندن از stdin و چاپ همان داده
    mov rax, 0
    mov rdi, 0
    mov rsi, buffer
    mov rdx, 64
    syscall

    mov rdx, rax
    mov rax, 1
    mov rdi, 1
    syscall

خطاها و Exceptions احتمالی:

خطا/Exception زمان رخ دادن راه‌حل
EFAULT اشاره‌گر نامعتبر به کرنل آدرس را بررسی کن
EINVAL آرگومان نامعتبر syscall و آرگومان جدول را چک کن
EBADF file descriptor نامعتبر fd را چک کن
#PF آدرس حافظه کاربر نامعتبر به rsi/rdi اشاره‌گر درست بده

Overloadها:

syscall        ;; اجرای syscall بر اساس rax
int 0x80       ;; روش قدیمی ۳۲ بیتی در لینوکس

اشتباهات رایج:

  • ❌ فراموش کردن تنظیم rax قبل از syscall
  • ❌ جابه‌جا گذاشتن r10 به‌جای rdx برای آرگومان چهارم
  • ❌ فراموش کردن اینکه syscall بعضی رجیسترها را خراب می‌کند

متدهای مرتبط:

  • sysret — بازگشت از syscall در سطح کرنل
  • int 0x80 — فراخوانی سیستمی ۳۲ بیتی
  • cpuid — دسترسی به اطلاعات CPU

📌 نام متد: imul()

امضای متد (Signature):

imul reg, r/m
imul reg, r/m, imm32
; یا فرم یکعملوندی
imul r/m

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
destination register بله در فرم دو/سهعملوندی رجیستر مقصد ضرب rax
source register/memory بله عملوند دوم ضرب rbx
immediate immediate بله در فرم سهعملوندی ضریب ثابت 10

مقدار برگشتی (Return Value):

  • نوع: integer
  • توضیح: حاصل‌ضرب علامت‌دار در مقصد ذخیره می‌شود
  • CF و OF در صورت سرریز شدن از مقصد یک می‌شوند

کاری که انجام می‌ده (گام به گام):

۱. مقدار منبع را می‌خواند.
۲. در مقصد ضرب می‌کند.
۳. اگر فرم سه‌عملوندی است، مقصد = منبع × عدد ثابت.
۴. نتیجه را می‌نویسد.
۵. فلگ‌های سرریز را تنظیم می‌کند.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    mov rax, 6
    mov rbx, 7
    imul rax, rbx
    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

42

مثال واقعی و کاربردی:

    imul rax, [quantity]   ; rax = rax * quantity
    imul rax, rbx, 10      ; rax = rbx * 10

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#PF منبع حافظه نامعتبر بررسی اشاره‌گر

Overloadها:

imul rax, rbx              ; rax = rax * rbx
imul rax, rbx, 10          ; rax = rbx * 10
imul rbx                   ; rdx:rax = rax * rbx (فرم یک‌عملوندی)
mul rbx                    ; ضرب بدون‌علامت

اشتباهات رایج:

  • ❌ استفاده از mul برای عدد علامت‌دار
  • ❌ فراموش کردن اینکه imul تک‌عملوندی نتیجه را در rdx:rax می‌گذارد

متدهای مرتبط:

  • mul — ضرب بدون‌علامت
  • div / idiv — تقسیم
  • shl — ضرب سریع در توان دو

📌 نام متد: idiv() و div()

امضای متد (Signature):

idiv r/m64
div r/m64

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
divisor register/memory بله مقسوم‌علیه rcx, [divisor]
dividend (ضمنی) rdx:rax بله مقسوم ۱۲۸ بیتی high=rdx، low=rax

مقدار برگشتی (Return Value):

  • نوع: integer
  • توضیح: خارج‌قسمت در rax، باقیمانده در rdx
  • فلگ‌ها: وضعیت فلگ‌ها undefined است

کاری که انجام می‌ده (گام به گام):

۱. مقدار rdx:rax را به‌عنوان مقسوم می‌گیرد.
۲. آن را بر divisor تقسیم می‌کند.
۳. خارج‌قسمت را در rax می‌نویسد.
۴. باقیمانده را در rdx می‌نویسد.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    mov rax, 17
    xor rdx, rdx
    mov rcx, 5
    div rcx
    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

3

مثال واقعی و کاربردی:

    ; تبدیل عدد به رشته با تقسیم مکرر بر ۱۰
.reverse:
    xor rdx, rdx
    div rbx
    add dl, '0'
    dec rdi
    mov [rdi], dl
    inc rcx
    test rax, rax
    jnz .reverse

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#DE مقسوم‌علیه صفر یا خارج‌قسمت بیرون از محدوده divisor را چک کن، rdx را صفر/cqo کن

Overloadها:

div rcx        ; بدون‌علامت
idiv rcx       ; با علامت
idiv qword [var]
div r8b        ; تقسیم بایتی
div r16        ; تقسیم ۱۶ بیتی

اشتباهات رایج:

  • ❌ صفر نکردن rdx قبل از تقسیم بدون‌علامت
  • ❌ استفاده از div برای اعداد علامت‌دار
  • ❌ فراموش کردن cqo برای idiv وقتی مقسوم علامت‌دار ۶۴ بیتی است

متدهای مرتبط:

  • cqo — sign-extend مقدار rax به rdx:rax
  • mul — ضرب بدون‌علامت
  • imul — ضرب علامت‌دار

📌 نام متد: xor()

امضای متد (Signature):

xor destination, source

ورودی‌ها (Parameters):

نام پارامتر نوع اجباری؟ توضیح دقیق مثال مقدار
destination register یا memory بله محل نتیجه XOR rax
source register یا immediate یا memory بله مقدار ماسک 0xFF

مقدار برگشتی (Return Value):

  • نوع: ندارد
  • توضیح: نتیجه destination XOR source در مقصد نوشته می‌شود
  • CF و OF صفر می‌شوند؛ SF, ZF, PF به‌روز می‌شوند

کاری که انجام می‌ده (گام به گام):

۱. مقدار منبع و مقصد را می‌خواند.
۲. XOR بیتی محاسبه می‌کند.
۳. نتیجه را در مقصد می‌نویسد.
۴. فلگ‌ها را تنظیم می‌کند.

مثال ساده و قابل اجرا:

section .text
    global _start
_start:
    mov rax, 0b1100
    xor rax, 0b1010
    mov rdi, rax
    mov rax, 60
    syscall

خروجی echo $?:

6

مثال واقعی و کاربردی:

    xor rax, rax        ; سریع‌ترین راه صفر کردن rax
    xor rcx, rcx        ; پاک کردن شمارنده

خطاها و Exceptions احتمالی:

Exception زمان رخ دادن راه‌حل
#PF آدرس حافظه نامعتبر بررسی اشاره‌گر

Overloadها:

xor rax, rbx
xor rax, 0xFFFF
xor rax, [var]
xor [var], rax
xor byte [var], 1

اشتباهات رایج:

  • ❌ فرض اینکه xor فقط برای صفر کردن است
  • ❌ فراموش کردن اینکه xor rax, rax بالای ۶۴ بیت را هم صفر می‌کند ولی xor al, al فقط al را صفر می‌کند

متدهای مرتبط:

  • and — AND بیتی
  • or — OR بیتی
  • not — NOT بیتی

۱۲. مقایسه کلاس‌ها/توابع مشابه

۱۲.۱ mov در مقابل lea

ویژگی mov rax, [rbx+8] lea rax, [rbx+8]
دسترسی به حافظه بله خیر
نتیجه مقدار داخل آن آدرس خود آدرس
سرعت کندتر، به حافظه می‌رود سریع‌تر، فقط محاسبه
کاربرد خواندن داده ساخت اشاره‌گر
mov rax, [rbx+8]    ; rax = مقدار داخل حافظه rbx+8
lea rax, [rbx+8]    ; rax = rbx+8

۱۲.۲ sub در مقابل cmp

ویژگی sub cmp
نتیجه در مقصد ذخیره می‌شود ذخیره نمی‌شود
فلگ‌ها بله بله
کاربرد اصلی تغییر عدد فقط مقایسه برای پرش
sub rax, 5      ; rax واقعاً کم می‌شود
cmp rax, 5      ; rax ثابت می‌ماند

۱۲.۳ call در مقابل jmp

ویژگی call jmp
ذخیره آدرس بازگشت بله خیر
استفاده فراخوانی تابع شاخه‌دادن بدون بازگشت
call my_func     ; بعد از my_func به اینجا برمی‌گردد
jmp my_func      ; دیگر برنمی‌گردد

۱۲.۴ shr در مقابل sar

ویژگی shr sar
معنی shift به راست منطقی shift به راست حسابی
بیت علامت صفر می‌شود حفظ می‌شود
mov rax, -16
sar rax, 2      ; منفی می‌ماند
mov rax, 0xF0
shr rax, 4      ; بیت‌های خالی صفر می‌شوند

۱۲.۵ mul در مقابل imul

ویژگی mul imul
نوع بدون‌علامت علامت‌دار
کاربرد اعداد مثبت اعداد مثبت/منفی
mul rbx     ; unsigned multiply
imul rbx    ; signed multiply

۱۲.۶ div در مقابل idiv

ویژگی div idiv
نوع بدون‌علامت علامت‌دار
آماده‌سازی rdx xor rdx, rdx cqo
mov rax, 100
xor rdx, rdx
mov rcx, 7
div rcx          ; unsigned

mov rax, -100
cqo
mov rcx, 7
idiv rcx         ; signed

۱۲.۷ test در مقابل cmp

ویژگی test cmp
عملیات AND بیتی تفریق
کاربرد بررسی صفر بودن/بیت خاص مقایسه عددی
test rax, rax      ; آیا rax صفر است؟
cmp rax, 10        ; آیا rax برابر ۱۰ است؟

۱۲.۸ je در مقابل jg در مقابل ja

دستور معنی عدد
je برابر هر دو
jg بزرگ‌تر علامت‌دار signed
ja بزرگ‌تر بدون‌علامت unsigned
cmp rax, rbx
jg .greater_signed
cmp rax, rbx
ja .greater_unsigned

۱۳. سناریوهای واقعی (Real-World Scenarios)

۱۳.۱ پیاده‌سازی strlen در اسمبلی

section .data
    msg db "Hello", 0

section .text
    global _start
_start:
    mov rdi, msg
    call strlen
    mov rdi, rax
    mov rax, 60
    syscall

strlen:
    xor eax, eax
.loop:
    cmp byte [rdi+rax], 0
    je .done
    inc rax
    jmp .loop
.done:
    ret

خروجی echo $?:

5

۱۳.۲ دریافت Vendor ID پردازنده با CPUID

section .bss
    vendor resb 13

section .text
    global _start
_start:
    mov eax, 0
    cpuid

    ; vendor string در ebx, edx, ecx است
    mov [vendor], ebx
    mov [vendor+4], edx
    mov [vendor+8], ecx
    mov byte [vendor+12], 0

    ; اکنون vendor حاوی "GenuineIntel" یا "AuthenticAMD" است
    ; ...

۱۳.۳ استفاده از اسمبلی در پروژه C

این روش در پروژه‌های واقعی برای بهینه‌سازی توابع حساس استفاده می‌شود.

math_asm.asm:

global multiply

section .text
multiply:
    mov rax, rdi
    imul rax, rsi
    ret

main.c:

#include <stdio.h>

extern long multiply(long, long);

int main(void) {
    printf("%ld\n", multiply(6, 7));
    return 0;
}

کامپایل:

nasm -f elf64 math_asm.asm -o math_asm.o
gcc -no-pie main.c math_asm.o -o program
./program

خروجی:

42

۱۳.۴ تحلیل باینری با objdump

objdump -d ./hello

نمونه خروجی:

0000000000401000 <_start>:
  401000: b8 01 00 00 00        mov    eax,0x1
  401005: bf 01 00 00 00        mov    edi,0x1
  40100a: 48 be 00 20 40 00 00  movabs rsi,0x402000
  401011: 00 00 00
  401014: ba 0e 00 00 00        mov    edx,0xe
  401019: 0f 05                 syscall

۱۴. کارایی و Performance

۱۴.۱ از رجیسترها به‌جای حافظه استفاده کن

رجیسترها صدها برابر سریع‌تر از حافظه اصلی هستند.

; کندتر
mov rax, [counter]
add rax, 1
mov [counter], rax

; سریع‌تر
mov rcx, [counter]
inc rcx
; نگهداشتن در رجیستر تا وقتی ممکن است

۱۴.۲ صفر کردن با xor

xor rax, rax   ; کوتاه‌تر و سریع‌تر
mov rax, 0     ; طولانی‌تر

۱۴.۳ استفاده از lea برای آدرس‌دهی

; سه دستور
mov rax, rbx
add rax, rcx
shl rax, 2

; یک دستور
lea rax, [rbx + rcx*4]

۱۴.۴ ضرب در توان دو با Shift

; ضرب در ۸
shl rax, 3

۱۴.۵ پرهیز از تقسیم

تقسیم یکی از کندترین دستورهای CPU است. وقتی ممکن است، از shift، ضریب معکوس یا LEA استفاده کن.

; تقسیم بر ۸ با shift
shr rax, 3

۱۴.۶ تراز داده‌ها

section .data
    align 16
    array dq 1, 2, 3, 4

۱۴.۷ کاهش پرش‌ها و استفاده از پیش‌بینی شاخه

  • حلقه‌های کوچک را مرتب نگه دار.
  • شاخه‌های غیرقابل پیش‌بینی را کاهش بده.
  • در صورت امکان از cmov استفاده کن.

۱۴.۸ استفاده از SIMD

به‌جای پردازش یک عدد در هر دستور:

movdqu xmm0, [src]
paddd xmm0, xmm1
movdqu [dst], xmm0

۱۵. چک‌لیست یادگیری

سطح مبتدی

  • می‌توانی رجیسترهای اصلی را نام ببری.
  • مفهوم mov, add, sub را می‌دانی.
  • یک برنامه Hello World می‌نویسی.
  • syscall خروج را فراموش نمی‌کنی.
  • حلقه و پرش شرطی را می‌فهمی.
  • تفاوت .data و .bss را می‌دانی.

سطح متوسط

  • با call و ret تابع می‌نویسی.
  • پشته و push/pop را درست مدیریت می‌کنی.
  • آدرس‌دهی حافظه با base+index*scale+offset را روان استفاده می‌کنی.
  • cmp و جدول jcc را خوب می‌فهمی.
  • یک برنامه مثل فاکتوریل را کامل می‌نویسی.
  • با gdb فلگ‌ها و رجیسترها را بررسی می‌کنی.

سطح پیشرفته

  • Calling Convention را رعایت می‌کنی.
  • اسمبلی را با C link می‌کنی.
  • مفاهیم signed/unsigned را در mul/div/jcc درست اعمال می‌کنی.
  • macro می‌نویسی.
  • از objdump برای دیس‌اسمبل کردن باینری استفاده می‌کنی.
  • یک تابع رشته‌ای مثل strlen یا strcpy را از صفر می‌نویسی.
  • آماده یادگیری SIMD یا مهندسی معکوس هستی.

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.