12-bo‘lim

Assembler tili

Assembler nima va nima uchun kerak, haqiqiy NASM dasturi, tizim chaqiruvlari, halqa va bayroqlar hamda assemblerni qachon o'qish kerak.

🕑 8 daqiqa o‘qish 📄 868 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Birinchi dastur
  2. Halqa va bayroqlar
  3. Assemblerni qachon yozish kerak?
  4. Xulosa

Assembler - mashina kodining odam o'qiy oladigan shakli. Har assembler qatori odatda bitta komandaga to'g'ri keladi.

Bu bo'limda haqiqiy dastur yozamiz - nasm bilan yig'ib, Linux da ishga tushiramiz.

Birinchi dastur #

Assembler dasturining yo'li salom.asm matn, odam yozgan nasm salom.o mashina kodi ld salom bajariluvchi fayl protsessor bajaradi Bu dasturda kutubxona YO'Q printf ham, C ish vaqti muhiti ham ishlatilmaydi - faqat syscall Shuning uchun u hech narsaga bog'liq emas va juda kichik
Ikki buyruq - va matn bajariluvchi faylga aylanadi
Natija
section .data
    xabar:   db "Salom, arxitektura!", 10
    uzunlik: equ $ - xabar

section .text
    global _start

_start:
    ; write(1, xabar, uzunlik) tizim chaqiruvi
    mov rax, 1          ; chaqiruv raqami: write
    mov rdi, 1          ; birinchi argument: stdout
    mov rsi, xabar      ; ikkinchi argument: matn manzili
    mov rdx, uzunlik    ; uchinchi argument: uzunlik
    syscall

    ; exit(0)
    mov rax, 60         ; chaqiruv raqami: exit
    xor rdi, rdi        ; qaytish kodi 0
    syscall

Uni yig'ib ishga tushirish uchun ikki buyruq yetarli:

Terminal
nasm -f elf64 salom.asm -o salom.o
ld salom.o -o salom
./salom

Natija:

Natija
Salom, arxitektura!

Chiqqan faylning hajmi 10 KB dan kichik - va bu butun dastur: sarlavhasi, kodi va ma'lumoti bilan.

Bu dasturda kutubxona yo'q. printf ham, C ish vaqti muhiti ham yo'q. Faqat protsessor komandalari va operatsion tizimga bitta murojaat.

syscall - dastur va yadro chegarasi

syscall komandasi boshqaruvni operatsion tizim yadrosiga o'tkazadi.

Bu "Operatsion tizimlar" darsligining 2-bo'limida batafsil ko'rilgan. Bu yerdagi qism shu:

RegistrVazifasi
raxChaqiruv raqami (1 = write, 60 = exit)
rdi1-argument
rsi2-argument
rdx3-argument

Bu chaqiruv kelishuvi (calling convention) - qaysi argument qaysi registrda kelishi haqidagi shartnoma.

Har operatsion tizim va arxitektura uchun u boshqacha. Shuning uchun assembler dasturi ko'chma emas: Linux uchun yozilgani Windows da ishlamaydi, garchi protsessor bir xil bo'lsa ham.

Dasturdagi belgilarni o'qib chiqamiz:

ElementMa'nosi
section .dataO'zgaruvchilar bo'limi
section .textKod bo'limi
dbdefine byte - baytlar e'lon qilish
equDoimiy e'lon qilish
$Joriy manzil
$ - xabarJoriy manzil ayirib - ya'ni uzunlik
_start:Nishon (label) - manzilga nom berish
;Izoh
global _startBu nomni bog'lovchiga ko'rsatish

Halqa va bayroqlar #

Endi 10-bo'limdagi halqani haqiqiy protsessorda quramiz:

Natija
section .text
    global _start

_start:
    mov rax, 0          ; yig'indi
    mov rcx, 10         ; hisoblagich

halqa:
    add rax, rcx        ; yig'indi += hisoblagich
    dec rcx             ; hisoblagich--
    jnz halqa           ; nol bo'lmasa - halqaga qayt

    mov rdi, rax        ; natijani qaytish kodiga
    mov rax, 60         ; exit
    syscall

Bu dastur 1 dan 10 gacha sonlarni qo'shadi. Ishga tushirib, qaytish kodini so'rasak:

Terminal
nasm -f elf64 halqa.asm -o halqa.o && ld halqa.o -o halqa
./halqa; echo $?

Chiqadi: 55 - aynan 1+2+...+10.

Butun halqa uch komanda. Diqqat qiling: dec komandasi bayroq qo'yadi, jnz esa shu bayroqqa qaraydi - ular alohida komandalar.

Bu 9 va 10-bo'limlarda qurgan modelimizning haqiqiy temirda tasdiqlanishi.

Qaytish kodi 0 dan 255 gacha

Yuqoridagi misolda natija 55 edi va u qaytish kodiga sig'di.

Lekin qaytish kodi bitta bayt. 1 dan 100 gacha yig'indi (5050) qaytarilsa, siz 5050 & 0xFF = 186 ni ko'rasiz.

Bu 3-bo'limdagi aylanib ketishning aynan o'zi.

Shuning uchun haqiqiy dasturlar natijani qaytish kodi bilan emas, chiqish oqimi orqali beradi. Qaytish kodi faqat "muvaffaqiyatlimi" degan savol uchun.

Assemblerni qachon yozish kerak? #

Rostini aytganda - deyarli hech qachon.

VazifaAssembler kerakmi
Oddiy dasturYo'q
Tezlikni oshirishDeyarli har doim yo'q - kompilyator yaxshiroq
Yadro va yuklovchiHa, kichik qismlarda
DrayverlarBa'zan
KriptografiyaBa'zan - vaqt bo'yicha barqarorlik uchun
SIMD optimallashtirishKo'pincha ichki funksiyalar yetarli

Zamonaviy kompilyator registrlarni taqsimlash, komandalarni qayta tartiblash va konveyerni hisobga olishda odamdan ancha yaxshi.

Yozmaslik kerak, lekin O'QIY bilish kerak

Assembler yozish kamdan-kam kerak bo'ladi. Lekin uni o'qish juda foydali:

QachonNima beradi
Nosozlik qidirishdaXato aynan qayerda ekanini ko'rasiz
ProfillashdaQaysi qator qimmatga tushayotganini bilasiz
Kompilyatorni tekshirishdaOptimallashtirish ishladimi yoki yo'q
Xavfsizlik tahlilidaKod haqiqatan nima qilayotganini

godbolt.org (Compiler Explorer) sayti aynan shu uchun mashhur: yozgan kodingiz qaysi komandalarga aylanishini darhol ko'rsatadi.

19-bo'limda biz ham xuddi shunday qilamiz - C kodini assemblerga aylantirib, natijani o'qiymiz.

Assembler xotirani tekshirmaydi

Yuqori darajali tillarda massiv chegarasidan chiqsangiz, xato olasiz. Assemblerda esa hech qanday tekshiruv yo'q.

Nima qilsangizNima bo'ladi
Chegaradan tashqariga yozishBoshqa ma'lumot buziladi
Noto'g'ri manzilni o'qishAxlat qiymat yoki qulash
Stekni buzishDastur boshqa joyga sakraydi

Uchinchisi - stekni to'ldirish hujumining asosi: agar dastur foydalanuvchi bergan ma'lumotni tekshirmasdan stekka yozsa, hujumchi qaytish manzilini almashtirib qo'yishi mumkin.

Himoya choralari 1-bo'limda aytilgan edi: NX, ASLR va stek kanareykalari. Bu mavzu "Kiberxavfsizlik asoslari" darsligida batafsil ko'rilgan.

Bu yerdagi xulosa: assembler hech narsani kechirmaydi. Shuning uchun uni faqat zarur bo'lganda va juda ehtiyot bilan yozing.

Amaliy topshiriq
  1. Birinchi dasturni ishga tushiring.
  2. Xabar matnini o'zgartiring va uzunlik avtomatik moslashishini ko'ring.
  3. exit kodini 42 ga o'zgartiring va echo $? bilan tekshiring.
  4. Halqa misolini ishga tushiring.
  5. Halqani 1 dan 100 gacha qiling - natija nima uchun 5050 emas?
  6. dec o'rniga sub rcx, 1 yozing - natija o'zgardimi?
  7. jnz ni jz ga almashtiring va nima bo'lishini oldindan ayting.
  8. Ikki sonni ko'paytiradigan dastur yozing.
  9. objdump -d bilan o'z dasturingizni disassembler qiling.
  10. Assemblerni qachon yozish kerakligi haqida uch qator yozing.

Xulosa #

  • Assembler - mashina kodining odam o'qiy oladigan shakli.
  • Har qator odatda bitta komandaga to'g'ri keladi.
  • nasm yig'adi, ld bog'laydi - natijada bajariluvchi fayl chiqadi.
  • syscall boshqaruvni yadroga o'tkazadi; argumentlar registrlarda uzatiladi.
  • Chaqiruv kelishuvi har OT va arxitektura uchun boshqacha.
  • Shuning uchun assembler dasturi ko'chma emas.
  • Halqa uch komandadan iborat: ish, kamaytirish, shartli o'tish.
  • dec bayroq qo'yadi, jnz shu bayroqqa qaraydi - ular alohida komandalar.
  • Qaytish kodi bitta bayt - katta natija aylanib ketadi.
  • Assembler yozish kamdan-kam kerak, lekin uni o'qish juda foydali.

Keyingi bo'limda o'z virtual protsessorimizni quramiz - komandalar to'plami, bajaruvchi va dasturlar bilan.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.