Çıplak metalde C standart kütüphaneler


24

Çoğunlukla Linux'u taşıyan aygıtlar üzerinde geliştirme yapıyorum, bu nedenle standart C kütüphanesi, standartlaştırılmış davranışa sahip sistem çağrılarını uygulayarak işlevselliklerinin çoğunu sağlıyor.

Ancak, çıplak metal için, temel bir işletim sistemi yoktur. Ac kütüphanesinin nasıl uygulanması gerektiğiyle ilgili bir standart var mı veya farklı bir BSP sağlayan yeni bir panele geçtiğinizde bir kütüphane uygulamalarının özelliğini yeniden öğrenmek zorunda mısınız?


4
Sorunuz için yanlış site.
ott--

8
Stack Overflow'a ait olduğu için bu soruyu konu dışı kapatmak için oy kullanıyorum .
uint128_t

1
Genelde onsuz yaparsınız. Bunları desteklemek için işletim sistemi olmadan neden böyle şeylere ihtiyacınız var? memcpy ve elbette. Örneğin, fopen, close, vb. Uygulanmasına rağmen, dosya sistemleri mutlaka ram'e karşı önemsizdir. printf () çok çok çok ağır, ton ve tonlarca kod gerekli, yapmadan yapın. herhangi bir G / Ç, değiştirmeden veya yapmadan. newlib oldukça aşırıdır, ancak yapmadan yapamazsanız, ama sistemi yine de arka uçta uygulamanız gerekiyorsa, fazladan katmana ihtiyacınız var mı?
old_timer

12
Bu soru yazılımla ilgili olsa da, genellikle SO tarafından reddedilen gömülü programlamaya çok özeldir. Burada zaten bazı iyi cevaplarımız olduğundan, göç uygun değildir.
Dave Tweed

1
Bir cevapta newlib'den bahsedilse de, newlib-nano'yu faydalı bulabilirsiniz - kaynak kısıtlamalı gömülü sistemlerde kullanım için soyulmuş bir sürüm olması amaçlanmıştır. Cortex M0 MCU'lardaki projelerde kullanıyorum. Bir dizi derleyici (Atollic TrueSTUDIO bir tanedir), newlib veya newlib-nano kullanmak için bir seçenek sunar.
jjmilburn

Yanıtlar:


20

Evet, bir standart var, C standart kütüphanesi . Kütüphane fonksiyonları "tam gelişmiş" bir işletim sistemi veya hiç bir işletim sistemi gerektirmez ve orada "çıplak metal" koduna uyarlanmış bir dizi uygulama vardır, Newlib belki de en iyisidir.

Örnek olarak Newlib'i ele almak için, temelde sisteminizde dosya ve bellek tahsisinin nasıl işlendiğini gösteren küçük bir çekirdek fonksiyonlar alt dizisi yazmanız gerekir. Ortak bir hedef platform kullanıyorsanız, birileri bu işi sizin için zaten yapmış olabilir.

Linux kullanıyorsanız (muhtemelen ayrıca OSX ve hatta cygwin / msys?) Yazıp yazdıysanız , uygulamanın belirli bir standarda uygun olduğunu söyleyebilecek man strlenbir adı verilen bir bölüm olmalıdır CONFORMING TO. Bu şekilde, kullandığınız bir şeyin standart bir işlev olup olmadığını veya belirli bir işletim sistemine bağlı olup olmadığını anlayabilirsiniz.


1
İşletim sistemine bağımlı olmadan nasıl stdlibuygulandığını merak ediyorum stdio. gibi fopen(), fclose(), fread(), fwrite(), putc()ve getc()? ve malloc()OS ile konuşmadan nasıl çalışır?
robert bristow-johnson

4
Newlib ile, altında platformunuz için birkaç düzine işlev içeren (veya yazdığınız) "libgloss" adında bir katman vardır. Örneğin, a getcharve putcharhangi donanımınızın UART hakkında bilmek; Sonra Newlib printfbunların üzerine katlanır . Dosya I / O benzer şekilde birkaç ilkel üzerinde güvenecektir.
Brian Drummond

evet, Pipe'ın 2. paragrafını dikkatlice okumadım. ile uğraşan yanında stdinve stdoutve stderr (hangi ilgilenir putchar()ve getchar()o zaman da bunun için yazma tutkal zorunda senin platformu flaşlı gibi, dosya depolama varsa, bir UART / / den O'yu I yönlendiren olan). ve araçlara sahip zorunda malloc()ve free(). Bu sorunların çaresine bakarsanız, katıştırılmış hedefinizde taşınabilir C'yi hemen hemen çalıştırabilirsiniz (hayır argvya da değil argc).
robert bristow-johnson

2
Newlib ayrıca , 1 veya 2kB kod alanına sahip MCU'larla ilgileniyorsanız ... çok büyük ...
Brian Drummond

2
@dwelch Kendi işletim sisteminizi yapmıyorsunuz, C kütüphanesini yapıyorsunuz. Bunu istemiyorsan, evet, gereksiz büyüklükte.
pipo

8

Ac kütüphanesinin nasıl uygulanması gerektiğiyle ilgili bir standart var mı veya farklı bir BSP sağlayan yeni bir panele geçtiğinizde bir kütüphane uygulamalarının özelliğini yeniden öğrenmek zorunda mısınız?

Öncelikle, C standardı, "barındırılan" bir uygulamanın tersine "dayanaksız" bir uygulama olarak adlandırılan bir şey tanımlar (bu, çoğumuzun aşina olduğu şey, temel işletim sisteminin desteklediği tüm C fonksiyonlarını içerir).

Bir uygulama gereksinimlerini "ayaklı", yani, o C kütüphanesi başlıkları sadece bir alt kümesini tanımlamak için değil destek veya fonksiyonları da tanımı (bunlar sadece yapılacak gerektiren #defines ve typedefs):

  • <float.h>
  • <iso646.h>
  • <limits.h>
  • <stdalign.h>
  • <stdarg.h>
  • <stdbool.h>
  • <stddef.h>
  • <stdint.h>
  • <stdnoreturn.h>

Barındırılan bir uygulamaya doğru bir sonraki adımı attığınızda, kütüphanenin geri kalanının bu “ilkellerin üzerine uygulanabilmesi” ile “sistemi” herhangi bir şekilde gerçekten birbirine bağlamak için gereken çok az sayıda işlev olduğunu göreceksiniz. ". PDCLib'in uygulanmasında, lib'i yeni bir platforma taşırken kolay tanımlama için onları ayrı bir alt dizinde izole etmek için biraz çaba sarf ettim (parantezdeki Linux portu örnekleri):

  • getenv()( extern char * * environ)
  • system()( fork()/ execve()/ wait())
  • malloc()ve free()( brk()/ sbrk())
  • _Exit()( _exit())
  • time() (henüz uygulanmadı)

Ve <stdio.h>(belki de C99 başlıklarının en çok işletim sistemi ile ilgilenenleri):

  • bir dosyayı açmak için bir yol ( open())
  • kapatmak için bir yol ( close())
  • kaldırmak için bir yol ( unlink())
  • yeniden adlandırmanın bir yolu ( link()/ unlink())
  • ona yazmanın bir yolu ( write())
  • ondan okumak için bir yol ( read())
  • içinde yeniden konumlandırmanın bir yolu ( lseek())

Kütüphanenin belirli detayları isteğe bağlıdır ve standart sadece standart bir şekilde uygulanmasını teklif eder, ancak böyle bir uygulamayı bir zorunluluk haline getirmez.

  • time()Fonksiyon yasal sadece döndürebilir (time_t)-1hiçbir zaman tutma mekanizması mevcut olup olmadığını.

  • Açıklanan sinyal işleyicileri, <signal.h>çağrı dışında başka bir şey tarafından çağrılmaya ihtiyaç duymaz raise(), sistemin uygulamaya uygulamaya benzer bir şey göndermesine gerek yoktur SIGSEGV.

  • İşletim sistemine çok bağlı <threads.h>olan (açık nedenlerden dolayı) C11 başlığının , uygulamanın tanımladığı durumlarda ...__STDC_NO_THREADS__

Daha çok örnek var, ama şu anda elimde değil.

Kütüphanenin geri kalanı, çevreden herhangi bir yardım almadan uygulanabilir. (*)


(*) Caveat: PDCLib uygulaması henüz tamamlanmadı, o yüzden bir ya da iki şeyi gözden kaçırmış olabilirim. ;-)


4

Standart C aslında çalışma ortamından ayrı tanımlanmıştır. Bir ana bilgisayar işletim sisteminin mevcut olduğu hakkında bir varsayım yapılmaz ve ana bilgisayara bağımlı olan kısımlar bu şekilde tanımlanır.

Yani, C Standardı zaten oldukça çıplak metaldir.

Elbette, çok sevdiğimiz dil bölümleri, kütüphaneler, çoğu zaman ana dilin belirli şeylere ev sahipliği yaptığı yerlerdir. Bu nedenle, birçok "çıplak metal platform" aracı için bulunan tipik "xxx-lib" çapraz derleyici malzemesi.


3

Newlib minimal çalıştırılabilir örnek

Burada , QEMU’da eylemde newlib’i gösteren oldukça otomatik ve belgelenmiş bir örnek veriyorum .

Newlib ile, kendi platform çağrılarınızı Baremetal platformunuz için uygularsınız.

Örneğin, yukarıdaki örnekte, bir örnek programımız var exit.c:

#include <stdio.h>
#include <stdlib.h>

void main(void) {
    exit(0);
}

ve ayrı bir C dosyasında common.c, ARM semihostingexit ile uygularız :

void _exit(int status) {
    __asm__ __volatile__ ("mov r0, #0x18; ldr r1, =#0x20026; svc 0x00123456");
}

Uygulayacağınız diğer tipik sistemler:

  • writesonuçları ana bilgisayara vermek için. Bu, ya ile yapılabilir:

    • daha fazla yarı gölgelenme
    • bir UART donanımı
  • brkiçin malloc.

    Baremetal için kolay, çünkü disk belleği ile ilgilenmek zorunda değiliz!

TODO Ben merak bunun tam gaz girmeden önleyici çizelgeleme syscalls yürütülmesine ulaşmak için gerçekçi olup olmadığını RTOS gibi Zephyr veya freertos .

Newlib ile ilgili en güzel şey, string.hsizin gibi işletim sistemi dışındaki tüm özel şeyleri uygulamanız ve sadece işletim sistemi taslaklarını uygulamanıza izin vermesidir.

Ayrıca, tüm taslakları uygulamak zorunda değilsiniz, sadece ihtiyacınız olacak olanları uygulamak zorundasınız. Örneğin, programınız yalnızca ihtiyaç duyuyorsa exit, o zaman bir sağlamak zorunda değilsiniz print.

Newlib kaynak ağacında, altında bir ARM yarı-gölgeleme uygulaması da dahil olmak üzere bazı uygulamalar var newlib/libc/sys/arm, ancak çoğu zaman kendinizinkini uygulamanız gerekiyor. Bununla birlikte, görev için sağlam bir temel sağlar.

Newlib'i kurmanın en kolay yolu, crosstool-NG ile kendi derleyicinizi kurarak, Newlib'i C kütüphanesi olarak kullanmak istediğinizi söylemelisiniz. Kurulumum, şu anda mevcut olan newlib yapılandırmalarını kullanan bu komut dosyasıyla sizin için otomatik olarak işler crosstool_ng_config.

C ++ 'ın da işe yarayacağını düşünüyorum, ancak TODO bunu test ediyor.


3
@ downvoters: lütfen açıkla ki bilgileri öğrenip geliştireyim. Umarım gelecek okuyucular sadece :-) çalıştığını internet üzerinde mevcut sadece tanıtım Newlib kurulum değerini görebilirsiniz
Ciro Santilli新疆改造中心法轮功六四事件

2

Baremetal kullandığınızda, uygulanmayan bazı bağımlılıklar keşfedersiniz ve bunları ele almalısınız. Bütün bu bağımlılıklar, dahili sistemlerin kişiliğinize göre ayarlanması ile ilgilidir. Örneğin, içinde malloc () kullanan sprintf () kullanmaya çalıştığımda. Malloc, donanım kısıtlamalarını zorlamak için kullanıcı tarafından uygulanacak kodlu bir kanca olarak "t_sbrk" işlev sembolüne sahiptir. Burada, sadece sprintf'i değil, esas olarak diğer kullanımlar için gömülü donanım için daha iyisini yapabileceğime inanıyorsam, bunu uygulayabilir veya kendi malloc'umu () yapabilirim.


Sprintf neden malloc'a ihtiyaç duymalı?
Supercat

Bilmiyorum. Sanırım amacın zaten sahip olduğu tampon, değil mi? Ama matbaanın bile malloğa ihtiyacı olmamalı. İstenen çıktının hesaplanması istiflenmiş tahsisat öngörüsünden daha ağır olduğunda, belki bazı iç değişkenleri dinamik olarak tahsis etmek (fonksiyonun dinamik değişkenleri)? Sprintf'in malloc gerektirdiğinden eminim (arm-none-eabi-newlib). Şimdi basit bir programın bilgisayarda sprintf (glibc) kullandığını denedim. Asla malloc denmedi. Daha sonra printf kullanılır. Malloc denir. Malloc sahte, her zaman 0 döndürüyordu. Ama iyi çalıştı. Bir dizge ve ondalık bir değişken yazdıracaklardı. @supercat
Ayhan

Uygulamalarımın kullandığı formatları desteklemek için özelleştirilmiş birkaç printf veya benzer yöntem sürümü kendim yaptım. Ondalık çıktı, mümkün olan en uzun sayıyı tutacak kadar uzun bir arabellek gerektirir, ancak aksi takdirde temel yordam, ilk üyesi çıktılanacak verilerle birlikte bu yapıya bir işaretçi kabul eden bir çıktı işlevi olan bir yapıyı kabul eder. Böyle bir tasarım, lanet tarzı konsollara, soketlere vb. Çıktı veren printf varyantlarını eklemeyi mümkün kılar. Böyle bir şeyde "malloc" a asla ihtiyaç duymadım.
supercat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.