Bu çok uzun bir yolculuğun ilk adımı. Fakat önce şunu izah etmek istiyorum. Bu projeyi Apple Internals’i daha iyi anlamak için FreeBSD kaynak kodundan yararlanarak başladığım işletim sisteminin nasıl ve neden geliştirdiğimi anlatan bir eğitim serisi olacak.
Apple Internals’e Giden Yol
2009 yılından bu yana Apple ekosistemi içindeyim, XCode, LLVM ve sistem tarafıyla mecburen çok fazla muhattap olmak durumunda kaldım. Bunların bir kaç sebebi vardı, anlatırsam uzar gider. Başınızı ağrıtmaya gerek yok.
Apple Internals her zaman ilgimi çekti, çünkü Linux bana toplama bir işletim sistemi geliyordu. Her zaman bir olmamışlık hissi beni çok rahatsız ediyordu. Ama FreeBSD bir sanatçının ustalık eseri olarak, zümrüt gibi orada parlıyordu. Ve bu BSD üzerine kurulmuş, dünyayı sarsan ve bir çok saçmalığı da olsa, yerini kimsenin dolduramadığı bir işletim sistemi Apple vardı. Ve bu işletim sistemine hakim olamamak, ayağımı bastığım yeri sağlam hissedememek beni rahatsız ediyordu. Bu sebeple bir çok kaynak ve kitap okudum. Ayrıca Apple’ın open source kaynak kodlarını uzun uzun inceledim. Ve sonucunda bir çok kavram kafamda oturmaya başladı.
Bu şunu getirdi; Darwin, XNU, Mach (bunların hepsini Apple Internals eğitim serisinde anlatacağım inşallah) seviyesine inip anlamaya başlayınca, Apple internals ile uğraşmanın ödülü geliyor:
- EXC_BAD_ACCESS (SIGSEGV) logunda, backtrace’te objc_release mi, swift_retain mi, CFArrayGetValueAtIndex mi patladı, artık daha iyi görmeye başlıyorsun.
- mach_exception kodlarını 0x8 = EXC_BAD_INSTRUCTION gibi çözüp, crash’in pointer mı, alignment mı, illegal instruction mı olduğunu ayırmaya başlıyorsun.
- Xcode’un kendi crash’lerinde bile “burada NSMutableArray out of bounds, bunu debug etmeden 20 senedir nasıl devam edebiliyorlar” diyebiliyorsun.
Ayrıca başka başka faydaları da var, öncelikle niş bir alan. Apple Internals ile ilgilenen developer sayısı çok çok azdır. O yüzden söz sahibi olma şansı da doğuyor her neyse :D
Bazen Apple’da çalışmak dışarıdan çalışmak çok havalı gözüküyor ama içeride mühendisler muhtemelen, dyld_shared_cache dump edip, objc_methname section’da string arıyor, sonra mach_header offsetiyle uğraşıyor, crashlog çözüp malloc_zone_t pointer leak’lerini kovalamakla günü geçiyor. Fen’de çok ilerledik bir yerde durmamız gerekiyor :D
Apple’a ara sıra Eşşek Apple dememin sebebi aslında buralar. Dışarıdan boyalı içerisi böcük dolu, hani böyle bir taşı kaldırırsın altında bir sürü böcük sağa sola kaçışır ya :D İşte Apple O. Ama normal ya. Her neyse Apple magazini sonraya bırakalım, orada anlatılacak çok eğlenceli yerler var biz şimdi sıkıcı kısma geçelim :D
boot.S - Başlangıç Noktası
// boot.S - ARM64 bootloader
.section .text.boot
.global _start
// Exception Vector Table
.align 11
exception_vector_table:
.rept 16
.align 7
b hang
.endr
_start:
// Boot entry point
// CPU initialization will follow...
boot.S Nedir? Neden Var?
boot.S, TAI-OS çekirdeğinin ilk çalışan (entry-stage) kodudur. Bu dosya:
- CPU’yu tanımlı bir başlangıç durumuna getirir (interrupt maskeleri, istisna vektör tablosu vb.),
- Mimariye özel ARM64 donanım kayıtlarını ayarlar,
- Sonraki aşamada C koduna kernel güvenle geçişe zemin hazırlar.
Bu seviyede C çalışma zamanı henüz hazır değil. (stack, .bss temizliği, global init vs. yapılmamıştır). Bu yüzden boot aşamasında assembly tercih edilir. boot.S ayrıca linker script ile yakından ilişkilidir: kodun hangi bellek bölümüne yerleşeceğini, vektör tablosunun hizalamasını ve giriş sembolünü _start linker belirler.
Kısaca CPU’yu deterministik hale getir, minimum gereklileri kur, sonra C’ye bırak.
Önemli Notlar
- Dosya uzantısının .S (büyük S) olması GNU as’ın C-önişlemcisini de cpp çalıştırmasına izin verir ki böylelikle macro ve #define önişlemcileri kullanabilelim
- ARM64 için aarch64-none-elf- veya aarch64-linux-gnu- toolchain’ler yaygındır.
- Linker, ENTRY(_start) ile giriş noktasını _start sembolüne bağlar;
Normal de tüm boot.S’i anlatacaktım ama bu kısma olanı anlatacağım ki, çok sıkıcı olmasın ki zaten yeterince sıkıcı oldu :D
Boot Entry’ye Kadar, Satır Satır Açıklama
1) Dosya üst bilgisi
// boot.S - ARM64 bootloader
- Yalnızca bilgilendirme amaçlı bir yorum.
2) Özel kod bölümü seçimi
.section .text.boot
Bu direktif, derleyiciye ve linker’e bu kodun .text.boot
isimli ayrı bir kod bölümüne konulacağını söyler.
Peki neden ayrı bir bölüm? Cevap: Linker script’te genelde şöyle bir blok olur:
.text.boot : {
KEEP(*(.text.boot))
. = ALIGN(4096);
} > RAM
3) Giriş sembolünü dışa açma
.global _start
_start
etiketini global görünür yapar.- Linker,
ENTRY(_start)
ile program girişini bu sembole bağlar.
4) Exception Vektör Tablosu Başlığı
// Exception Vector Table
.align 11
exception_vector_table:
- Amaç: ARM64’te istisna (exception) vektör tablosu, 2048 bayt hizalı bir adreste olmalıdır.
exception_vector_table:
etiketi, tablonun başlangıç adresini belirler.
Not: Bazı platformlarda .align 2^n
hizalama iken bazılarında n
bayt hizalama davranabilir. ARM64 tarafında 2^n
olarak çalışır; en güvenlisi .balign 2048
kullanmaktır. Eğitim metninde .align 11
yeterli, ama üretimde: .balign 2048
olmalı.
Bu tabloyu .vectors gibi ayrı bir bölüme koyup linker’da
.vectors ALIGN(2048) : { KEEP(*(.vectors)) }
ile çöp toplayıcıdan korunmuş ve zorunlu hizalanmış hale getirmek iyi pratiktir. Bu örnekte tablo .text.boot
içindedir; yine de hizalama garantili olduğu sürece sorun yok.
5) 16 Adet Vektör Slotu Üretme
.rept 16
.align 7
b hang
.endr
Bu blok, 16 adet vektör girişini minimal bir “iskele” ile üretir:
.rept 16, .endr: İçerideki talimatları 16 kez tekrarlar. ARMv8-A, AArch64 vektör tablosunun 16 slotu vardır:
Slot | Exception Type | Source |
---|---|---|
0-3 | Current EL with SP_EL0 | Sync, IRQ, FIQ, SError |
4-7 | Current EL with SP_ELx | Sync, IRQ, FIQ, SError |
8-11 | Lower EL (AArch64) | Sync, IRQ, FIQ, SError |
12-15 | Lower EL (AArch32) | Sync, IRQ, FIQ, SError |
.align 7 → 2^7 = 128 bayt hizalama: ARM64’te her vektör girişi 128 baytlık bir slot kabul edilir. Burada her tekrarın başında hizalama ile bir sonraki 128 bayt sınırına atlanır.
b hang: Her slotun ilk talimatı, şimdilik basitçe hang fonksiyonuna dalan bir branch. Bu minimalist yaklaşım şunları garanti eder:
- Her istisna, geçici olarak aynı “bekleme” döngüsüne yönlendirilir (sistem donmaz, kontrol sizde kalır).
- Slotların geri kalan padding alanı,
.align
sayesinde otomatik doldurulur; böylece bir sonraki slot tam 128 bayt sınırında başlar
Not: “128 bayt slot = 128 bayt kod yazmak zorundasın” demek değildir. İlk komut (branch) fiilen birkaç bayt; kalan alan hizalama dolgusu. Donanım, slot başlangıcındaki kodu yürütür; içeride daha sonra ister ayrıntılı handler, ister kayıt dökümü koyabilirsiniz.
Bu tarz doldurmalar genelde kriptografide de vardır ama konumuz bu değil. Konu bu değil olm, konu bu değil :D
Bu Noktada Ne Oldu?
- Vektör tablosu 2048B hizayla belleğe yerleştirildi.
- İçinde 16 adet, 128B hizalı slot üretildi.
- Tüm slotlar, şimdilik güvenli bir yere (sonsuz bekleme döngüsü hang) branch ediyor.
- Henüz VBAR_EL1, EL2, EL3 gibi kayıtlar ayarlanmadı (bu, Boot Entry’den sonra yapılacak iş). Yani tabloyu oluşturduk, ama CPU’ya “vektör tabanın bu” demedik. O kısım
_start
sonrasındaki init aşamasında.
Devamı Gelecek…
Gördüğünüz gibi, BOOT ENTRY kısmına anca gelebildik. Ama burada duralım onu diğer makaleye bırakalım. Eğer ikinci makaleye geçerseniz, bu işi sevdiniz demektir. Bırakırsanız da çok normal, çünkü çok sıkıcı :D
Boot Entry kısmı da şu şekilde gözükecek en azından fikir olması açısından:
_start:
// Set exception level and stack pointer
msr daifset, #0xF // Disable all interrupts
// Set up temporary stack
adr x0, stack_top
mov sp, x0
// Clear BSS section
bl clear_bss
// Jump to C kernel
bl kernel_main
// Should never reach here
b hang
hang:
wfe
b hang
Bu serinin devamında CPU initialization, memory management, ve C runtime setup’ını detaylı olarak inceleyeceğiz. ARM64’ün güzelliklerini ve Apple Internals’in derinliklerini birlikte keşfedeceğiz.
Sonraki bölümde: Exception Level management, Stack pointer setup, ve BSS section clearing işlemlerini göreceğiz.
Kaynaklar
- ARM Architecture Reference Manual
- TAIOS GitHub Repository
- FreeBSD Source Code
- Apple Darwin/XNU Open Source
Etiketler
#ARM64
#OperatingSystems
#Assembly
#AppleInternals
#SystemsProgramming
#TAIOS
#FreeBSD
#Darwin
Tags
Uğur Toprakdeviren
Cryptographer, security researcher, and systems engineer with over two decades of experience building secure systems. Currently focused on Apple internals, decentralized messaging protocols, ARM64 architectures, and the philosophical implications of digital privacy.
Learn more about me