Skip to content

Latest commit

 

History

History
111 lines (106 loc) · 3.39 KB

5.md

File metadata and controls

111 lines (106 loc) · 3.39 KB

X86_64 Assembly'e merhaba deyin [bölüm 5]

Bu X86_64 Assembly'a merhaba deyin 'in beşinci bölümü ve burada makrolara bakacağız.X86_64 ile ilgili blog yazısı olmayacak, özellikle de nasm assembler ve preprocessor ile ilgili olacak. Eğer ilginizi çekiyor ise okumaya devam edin.

Macros

NASM iki makro türünü destekler:

    tek-satır
    çoksatır

Tüm tek satırlı makrolar % tanım yönergesiyle başlamalıdır.Form aşağıdaki gibidir:

%define makro_adi(parametre) değer

Nasm makrosunun davranışı ve görünümü C'dekine çok benzerdir. Örneğin, aşağıdaki tek satırlı makroyu oluşturabiliriz:

%define argc rsp + 8
%define cliArg1 rsp + 24

ve kod için de kullanımı:

; argc, rsp + 8 değerine genişletilecek
mov rax, [argc]
cmp rax, 3
jne .mustBe3args

Multiline makro,%macro nasm yönergesiyle başlar ve %endmacro ile biter. Bu genel form aşağıdaki gibidir:

%macro parametre_sayısı
    komut
    komut
    komut
%endmacro

Örneğin:

%macro bootstrap 1
    push ebp
    mov ebp,esp
%endmacro

Ve onu kullanabiliriz:

_start:
    bootstrap

Örneğin, PRINT makrosuna bakalım:

%macro PRINT 1
    pusha
    pushf
    jmp %%astr
    %%str db %1, 0
    %%strln equ $-%%str
    %%astr: _syscall_write %%str, %%strln
    popf
    popa
%endmacro

%macro _syscall_write 2
    mov rax, 1
    mov rdi, 1
    mov rsi, %%str
    mov rdx, %%strln
    syscall
%endmacro

Makro inceleyelim ve nasıl çalıştığını anlayalım: İlk satırda PRINT makrosunu bir parametre ile tanımladık.Daha sonra tüm genel registerları (pusha komutuyla ) ve flag registerları (pushf komutuyla) pushlayalım.Bundan sonra %% astr etiketine atladık.Makroda tanımlanan tüm etiketlerin %% ile başlaması gerektiğine dikkat edin.Şimdi 2 parametreyle __syscall __  makrosuna geçiyoruz. __syscall_write uygulamasına bakalım. Stdout'a stringi yazdırmak için önceki yazılarda write system call kullandığımızı hatırlayabilirsiniz. Şöyle görünüyor:

; write syscall sayısı
mov rax, 1
; file descriptor(dosya tanıtıcı), standard output(çıkış)
mov rdi, 1
; mesaj adresi
mov rsi, msg
; mesajın uzunluğu
mov rdx, 14
; write syscall'u çağır
syscall

__ syscall_write makromuzda, rax (write system call numarası) ve rdi (stdout file descriptor) 1'i koymak için ilk iki komutu tanımlarız.Daha sonra %% str değerini rsi registerına koyarız (pointer to string), burada %% str, PRINT makrosunun ilk parametresi olan local labeldir. (makro parametresinin $ parameter_number ile erişimine dikkat edin) ve 0 ile bitirin. (her string sıfır ile bitmelidir).Ve string'in uzunluğunu hesaplayan %% strlen. Bundan sonra sistem çağrısını sistem çağrısı komutu olarak adlandırıyoruz ve hepsi bu kadar.
Şimdi kullanabiliriz:

label: PRINT "Hello World!"

Faydalı standart makrolar

NASM, aşağıdaki standart makroları desteklemektedir:

STRUC

Veri yapısı tanımı için STRUC ve END STRUC kullanabilirsiniz. Örneğin:

struc person
   name: resb 10
   age:  resb 1
endstruc

Ve şimdi yapımızın örneğini yapabiliriz:

section .data
    p: istruc person
      at name db "name"
      at age  db 25
    iend

section .text
_start:
    mov rax, [p + person.name]

%include

Diğer assembly dosyalarını ekleyebilir ve oraya atlayabilir veya % include direktifiyle fonksiyonları çağırabiliriz.