C perpustakaan standar pada bare metal

24

Saya sebagian besar melakukan pengembangan pada perangkat yang telah mem-porting Linux sehingga pustaka C standar menyediakan banyak fungsionalitas melalui penerapan panggilan sistem yang memiliki perilaku standar.

Namun untuk bare metal, tidak ada OS yang mendasarinya. Apakah ada standar terkait dengan bagaimana perpustakaan ac harus diimplementasikan atau apakah Anda harus mempelajari kembali kekhasan implementasi perpustakaan ketika Anda beralih ke papan baru yang menyediakan BSP yang berbeda?

TheMeaningfulEngineer
sumber
4
Situs yang salah untuk pertanyaan Anda.
ott--
8
Saya memberikan suara untuk menutup pertanyaan ini sebagai di luar topik karena itu milik Stack Overflow .
uint128_t
1
Umumnya Anda melakukannya tanpa. Mengapa Anda memerlukan hal-hal seperti itu tanpa sistem operasi untuk mendukungnya? memcpy dan tentu saja. Sistem file, tidak harus, meskipun diimplementasikan fopen, close, dll sepele terhadap ram misalnya. printf () sangat sangat sangat berat, banyak sekali kode yang diperlukan, lakukan tanpa. I / O ganti atau lakukan tanpa. newlib cukup ekstrim, tetapi apakah membantu jika Anda tidak dapat melakukannya tanpa, tetapi Anda harus menerapkan sistem pada backend, jadi apakah Anda memerlukan lapisan tambahan?
old_timer
12
Meskipun pertanyaan ini tentang perangkat lunak, ini sangat spesifik untuk pemrograman tertanam, yang umumnya ditolak oleh SO. Karena kami sudah memiliki jawaban yang bagus di sini, migrasi tidak tepat.
Dave Tweed
1
Sementara newlib disebutkan di bawah dalam sebuah jawaban, Anda juga mungkin menemukan newlib-nano berguna - yang dimaksudkan sebagai versi stripped-back untuk digunakan dalam sistem embedded sumber daya terbatas. Saya menggunakannya dalam proyek-proyek pada MCU Cortex M0. Sejumlah kompiler (Atollic TrueSTUDIO menjadi satu) akan memberikan opsi untuk menggunakan newlib atau newlib-nano.
jjmilburn

Jawaban:

20

Ya, ada standar, hanya C library standar . Fungsi pustaka tidak memerlukan OS "full blown", atau OS apa pun, dan ada sejumlah implementasi di luar sana yang disesuaikan dengan kode "bare metal", Newlib mungkin yang paling terkenal.

Mengambil Newlib sebagai contoh, ini mengharuskan Anda untuk menulis sebagian kecil fungsi inti, terutama bagaimana file dan alokasi memori ditangani di sistem Anda. Jika Anda menggunakan platform target umum, kemungkinan seseorang telah melakukan pekerjaan ini untuk Anda.

Jika Anda menggunakan linux (mungkin juga OSX dan mungkin bahkan cygwin / msys?) Dan ketik man strlen, itu harus memiliki bagian bernama sesuatu CONFORMING TO, yang akan memberi tahu Anda bahwa implementasinya sesuai dengan standar tertentu. Dengan cara ini Anda dapat mengetahui apakah sesuatu yang Anda gunakan adalah fungsi standar atau apakah itu tergantung pada OS tertentu.

pipa
sumber
1
Saya ingin tahu bagaimana stdlibmengimplementasikan stdiotanpa tergantung pada OS. seperti fopen(), fclose(), fread(), fwrite(), putc()dan getc()? dan bagaimana cara malloc()kerjanya tanpa berbicara dengan OS?
robert bristow-johnson
4
Dengan Newlib, ada lapisan di bawahnya yang disebut "libgloss" yang berisi (atau Anda menulis) beberapa lusin fungsi untuk platform Anda. Misalnya, getchardan putcharyang tahu tentang UART perangkat keras Anda; kemudian layer Newlib printfdi atas ini. File I / O juga akan bergantung pada beberapa primitif.
Brian Drummond
ya, saya tidak membaca paragraf ke-2 pipa dengan hati-hati. selain berurusan dengan stdindan stdoutdan stderr (yang menanganiputchar() dan getchar()) yang mengarahkan I / O dari / ke UART, jika platform Anda memiliki penyimpanan file, seperti dengan flash, maka Anda harus menulis lem untuk itu juga. dan Anda harus memiliki sarana untuk malloc()dan free(). Saya pikir jika Anda menangani masalah-masalah itu, Anda dapat menjalankan banyak C portabel di target tertanam Anda (tidak argvatau tidak argc).
robert bristow-johnson
2
Newlib juga besar jika Anda berurusan dengan MCU dengan 1 atau 2kB ruang kode ...
Brian Drummond
2
@dwelch Anda tidak membuat OS sendiri, Anda membuat perpustakaan C. Jika Anda tidak menginginkannya, maka ya, itu tidak perlu besar.
pipa
8

Apakah ada standar terkait dengan bagaimana perpustakaan ac harus diimplementasikan atau apakah Anda harus mempelajari kembali kekhasan implementasi perpustakaan ketika Anda beralih ke papan baru yang menyediakan BSP yang berbeda?

Pertama, standar C mendefinisikan sesuatu yang disebut implementasi "berdiri bebas", sebagai lawan dari implementasi "host" (yang kita kenal dengan baik, rangkaian penuh fungsi C yang didukung oleh OS yang mendasarinya).

Implementasi "berdiri bebas" perlu mendefinisikan hanya sebagian dari header perpustakaan C, yaitu yang tidak memerlukan dukungan, atau bahkan definisi fungsi (mereka hanya melakukan #defines dan typedefs):

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

Ketika Anda mengambil langkah berikutnya menuju implementasi yang di-host, Anda akan menemukan bahwa hanya ada sedikit fungsi yang benar-benar perlu untuk menghubungkan "sistem" dengan cara apa pun, dengan sisa perpustakaan dapat diimplementasikan di atas "primitif" ". Dalam mengimplementasikan PDCLib , saya berusaha mengisolasinya dalam subdirektori terpisah untuk memudahkan identifikasi ketika port lib ke platform baru (contoh untuk port Linux dalam tanda kurung):

  • getenv()( extern char * * environ)
  • system()( fork()/ execve()/ wait())
  • malloc()dan free()( brk()/ sbrk())
  • _Exit()( _exit())
  • time() (belum diimplementasikan)

Dan untuk <stdio.h> (bisa dibilang yang paling "terlibat-OS" dari header C99):

  • beberapa cara untuk membuka file ( open())
  • beberapa cara untuk menutupnya ( close())
  • beberapa cara untuk menghapusnya (unlink() )
  • beberapa cara untuk mengganti nama itu (link() / unlink())
  • beberapa cara untuk menulisnya (write() )
  • beberapa cara untuk membacanyaread() )
  • beberapa cara untuk memposisikan ulang di dalamnya (lseek() )

Detail tertentu dari perpustakaan bersifat opsional, dengan standar yang hanya menawarkan untuk diimplementasikan dengan cara standar tetapi tidak menjadikan implementasi seperti itu suatu persyaratan.

  • The time()Fungsi mungkin secara hukum hanya kembali(time_t)-1 jika tidak ada mekanika waktu-menjaga tersedia.

  • Penangan sinyal yang dideskripsikan untuk <signal.h>tidak perlu dipanggil oleh selain panggilan untuk raise(), tidak ada persyaratan bahwa sistem benar-benar mengirim sesuatu seperti SIGSEGVke aplikasi.

  • Header C11 <threads.h>, yang (karena alasan yang jelas) sangat tergantung pada OS, tidak perlu disediakan sama sekali jika implementasinya menentukan __STDC_NO_THREADS__...

Ada lebih banyak contoh, tetapi saya tidak memilikinya saat ini.

Sisa perpustakaan dapat diimplementasikan tanpa bantuan dari lingkungan. (*)


(*) Peringatan: Implementasi PDCLib belum lengkap, jadi saya mungkin mengabaikan satu atau dua hal. ;-)

DevSolar
sumber
4

Standar C sebenarnya didefinisikan terpisah dari lingkungan operasi. Tidak ada asumsi tentang OS host yang hadir, dan bagian-bagian yang bergantung pada host didefinisikan sebagai demikian.

Artinya, Standar C sudah cukup logam telanjang.

Tentu saja, bagian-bagian bahasa yang sangat kita cintai, perpustakaan, sering kali merupakan tempat bahasa inti mendorong hal-hal tertentu menjadi tuan rumah. Oleh karena itu, hal-hal kompiler silang "xxx-lib" tipikal ditemukan untuk banyak alat platform logam kosong.


sumber
3

Newlib contoh runnable minimal

Di sini saya memberikan contoh yang sangat otomatis dan terdokumentasi yang menunjukkan tindakan newlib dalam QEMU .

Dengan newlib, Anda menerapkan panggilan sistem Anda sendiri untuk platform baremetal Anda.

Sebagai contoh, pada contoh di atas, kami memiliki contoh program exit.c:

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

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

dan dalam file C yang terpisah common.c, kami menerapkan exitdengan semihosting ARM :

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

Syscalls khas lainnya yang akan Anda terapkan adalah:

  • writeuntuk menampilkan hasil ke host. Ini dapat dilakukan dengan:

    • lebih semihosting
    • perangkat keras UART
  • brk untuk malloc .

    Mudah digunakan di baremetal, karena kita tidak perlu peduli tentang paging!

TODO Saya bertanya-tanya apakah realistis untuk mencapai eksekusi syscalls penjadwalan preemptive tanpa pergi ke RTOS penuh sesak seperti Zephyr atau FreeRTOS .

Hal keren tentang Newlib, adalah mengimplementasikan semua hal non-OS spesifik seperti string.h untuk Anda, dan memungkinkan Anda menerapkan hanya OS bertopik.

Juga, Anda tidak harus menerapkan semua bertopik, tetapi hanya yang Anda butuhkan. Misalnya, jika program Anda hanya perlu exit, maka Anda tidak perlu menyediakanprint .

Pohon sumber Newlib memang sudah memiliki beberapa implementasi, termasuk implementasi semihosting ARM di bawah newlib/libc/sys/arm , tetapi sebagian besar Anda harus mengimplementasikan sendiri. Namun itu memberikan dasar yang kuat untuk tugas tersebut.

Cara termudah untuk men-setup Newlib adalah dengan membangun compiler Anda sendiri dengan crosstool-NG, Anda hanya perlu mengatakan bahwa Anda ingin menggunakan Newlib sebagai pustaka C. Setup saya menangani itu secara otomatis untuk Anda dengan skrip ini , yang menggunakan konfigurasi lib baru hadir dicrosstool_ng_config .

Saya pikir C ++ juga akan berfungsi, tetapi TODO mengujinya.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
sumber
3
@ downvoters: tolong jelaskan agar saya dapat mempelajari dan meningkatkan info. Semoga pembaca di masa mendatang dapat melihat nilai dari satu-satunya pengaturan pengantar Newlib yang tersedia di web yang hanya berfungsi :-)
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
2

Ketika Anda menggunakannya, Anda menemukan beberapa dependensi yang tidak diterapkan dan harus menanganinya. Semua dependensi ini adalah tentang menyetel internal sesuai dengan kepribadian sistem Anda. Misalnya ketika saya mencoba menggunakan sprintf () yang menggunakan malloc () di dalamnya. Malloc memiliki simbol fungsi "t_sbrk" sebagai kode kait, yang harus diimplementasikan oleh pengguna untuk menegakkan perangkat keras yang terlatih. Di sini saya dapat mengimplementasikannya, atau membuat malloc saya sendiri () jika saya percaya saya bisa melakukan yang lebih baik untuk perangkat keras yang tertanam, terutama untuk penggunaan lain, tidak hanya sprintf.

Ayhan
sumber
Mengapa sprintf perlu malloc ()?
supercat
Saya tidak tahu Saya pikir poin Anda adalah buffer yang sudah ada, bukan? Tetapi bahkan printf seharusnya tidak perlu malloc. Mungkin untuk secara dinamis mengalokasikan beberapa variabel internal, ketika perhitungan output yang diminta lebih berat daripada tinjauan ke depan alokasi yang ditumpuk (variabel fungsi dinamis)? Saya yakin sprintf diperlukan malloc (arm-none-eabi-newlib). Sekarang saya bereksperimen dengan program sederhana menggunakan sprintf di komputer (glibc). Itu tidak pernah disebut malloc. Kemudian digunakan printf. Itu disebut malloc. Malloc palsu, selalu mengembalikan 0. Tapi itu berfungsi dengan baik. Mereka mencetak string dan variabel desimal. @supercat
Ayhan
Saya sendiri telah membuat beberapa versi printf atau metode serupa, yang disesuaikan untuk mendukung format aplikasi yang saya gunakan. Output desimal membutuhkan buffer yang cukup lama untuk menampung angka terpanjang yang mungkin, tetapi jika tidak, rutin basis menerima struktur yang anggota pertamanya adalah fungsi output yang menerima pointer ke struktur itu bersama dengan data yang akan dikeluarkan. Desain seperti itu memungkinkan untuk menambahkan varian printf yang dihasilkan oleh konsol, soket, dan gaya kutukan, dll. Saya tidak pernah membutuhkan "malloc" dalam hal semacam itu.
supercat