ESP32 ve Rust: gömülü sistemlerde bellek güvenliğine ilk adım
Gömülü sistemlerde projeler büyüdükçe bellek yönetimi hataları ayıklanması en zor sorunlar haline gelir. Özellikle ESP32 gibi çift çekirdekli ve yüksek performanslı mikrodenetleyicilerde, karmaşık thread yapıları ve interrupt servis rutinleri içinde pointer hataları ile karşılaşmak yaygındır. Geleneksel olarak C veya C++ tercih edilse de, rust lang dünyasının getirdiği ownership ve borrowing kuralları, çalışma zamanındaki bellek hatalarının birçoğunu derleme aşamasında yakalayabilmenizi sağlar.
Bellek güvenliği neden kritik
Gömülü sistemler genellikle kaynak kısıtlıdır. Dinamik bellek yönetimi yaparken yapılan küçük bir hata (dangling pointer ya da buffer overflow) sistemin çökmesine veya güvenlik açıklarına yol açar. C dilinde bu hataları önlemek tamamen yazılımcının disiplinine bağlıdır. Derleyici, bellek adreslerinin doğruluğunu kontrol etmez.
Rust, bu noktada sahiplik (ownership) prensibini devreye sokar. Her değişkenin bir sahibi vardır ve veri yaşam döngüsü derleme zamanında belirlenir. embedded systems projelerinde bu durum, bellek sızıntılarının (memory leak) ve race condition hatalarının önemli ölçüde azalması anlamına gelir.
ESP32 üzerinde Rust kurulumu
ESP32 üzerinde Rust kullanmak için esp-rs ekosisteminden faydalanmak gerekir. Standart Rust kütüphaneleri (std), donanıma doğrudan erişim için her zaman yeterli olmayabilir. Bu nedenle no_std ortamında, yani standart kütüphane bağımlılığı olmadan geliştirme yapmanız gerekebilir.
Öncelikle gerekli araç zincirini kurmak için aşağıdaki komutları kullanabilirsiniz. Rust kurulumunuzun olduğundan emin olun ve esp-rs donanım soyutlama katmanlarını yükleyin:
cargo install espup
espup install
source /home/$USER/export-esp.sh
Bu komutlar, hem derleyiciyi hem de ESP32 hedefi için gerekli tüm kütüphaneleri sisteminize yapılandırır.
Basit bir örnek: blinky
Donanımın çalışıp çalışmadığını anlamak için GPIO pinine bağlı bir LED’i yakıp söndürmek, Rust ile yazılmış bir embedded sistemin temelidir. Aşağıdaki örnekte, esp-hal kütüphanesi kullanılarak bir pinin nasıl yapılandırıldığı gösterilmektedir:
#![no_std]
#![no_main]
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
prelude::*,
Delay,
};
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut led = io.pins.gpio2.into_push_pull_output();
let mut delay = Delay::new(&clocks);
loop {
led.toggle();
delay.delay_ms(500u32);
}
}
Burada #![no_std] ifadesi, standart kütüphaneyi devre dışı bırakır. Böylece işletim sistemi bulunmayan ortamlarda doğrudan donanım register’larına erişim sağlarsınız. ! dönüş tipi, bu fonksiyonun asla sonlanmayacağını, yani gömülü sistemin sonsuz döngüde çalışacağını ifade eder.
Rust kullanmanın getirdiği zorluklar
Rust, derleme aşamasında çok katı kurallara sahiptir. Bu durum başlangıçta öğrenme eğrisini dikleştirir. Özellikle C’den gelen bir yazılımcı için, borç alma (borrow checker) kuralları ile sürekli "kavga etmek" sinir bozucu olabilir. Ancak bu kurallar, uygulamanızın üretim aşamasında beklenmedik şekilde çökmesini engeller.
Ekosistem gelişmeye devam ediyor. Raspberry Pi Pico veya benzeri kartlarla karşılaştırıldığında, ESP32 ve Rust uyumu oldukça ileri seviyededir. Yine de kütüphane desteği C/C++ kadar geniş değildir. Karmaşık bir sürücüye ihtiyacınız olduğunda, kendi sürücünüzü Rust ile yazmanız veya C sürücülerini FFI (Foreign Function Interface) ile bağlamanız gerekebilir.
Bağlam ve sonuç
Embedded systems alanında güvenlik, sadece yazılımın çalışması değil, çalışmaya devam etmesidir. ESP32 gibi internete bağlı ve IoT dünyasında kritik görevler üstlenen bir kart için bellek güvenliği bir tercih değil, ihtiyaçtır. Rust, sistemin güvenliğini derleme anına taşıyarak geliştiricinin üzerindeki yükü azaltır.
Yeni bir projeye başlarken mevcut C/C++ kod tabanınızı bir anda Rust’a çevirmek yerine, belirli modülleri Rust ile yazarak sisteme entegre etmek daha güvenli bir yöntemdir. Rust, bellek hatalarını tamamen yok etmese de, en azından bu hataları geliştirme masasında yakalamanıza izin verir.