OS के बिना `printf` इम्प्लीमेंट करना - Bare Metal वातावरण में C standard library का उपयोग
(popovicu.com)- Newlib library का उपयोग करके operating system के बिना भी
printfसहित C standard functions का उपयोग संभव बनाने की implementation method का परिचय - RISC-V architecture आधारित Bare Metal environment में UART driver और memory allocation functions को सीधे implement करके Newlib से जोड़ा गया
_write,_sbrk,_closeजैसी न्यूनतम system call functions की implementation मात्र सेprintfजैसे advanced features का उपयोग संभव- Newlib-आधारित toolchain बनाने के लिए RISC-V GCC toolchain के साथ automatic build और linker script लिखने का तरीका बताया गया
- परिणामस्वरूप UART output,
scanfinput और dynamic memory allocation तक काम करने वालाprintfenvironment सफलतापूर्वक बनाया गया
Software abstractions and C standard library
- सामान्य OS में
printfcall करने पर kernel system call, terminal layer, font rendering जैसी कई abstraction layers काम करती हैं - Bare Metal environment में operating system के बिना सीधे input/output control की ज़रूरत होती है, और इसके लिए driver को सीधे implement करना पड़ता है
- Newlib पूरी C standard library के बजाय केवल न्यूनतम features implement करके extendable configuration प्रदान करता है
Newlib concept
printfअंदरूनी रूप से_writeजैसे सरल primitive functions के आधार पर implement होता है- Newlib में शुरुआत में सभी functions dummy form में defined होते हैं, और ज़रूरी हिस्से implement करने पर बाकी में default behavior इस्तेमाल किया जा सकता है
- developer केवल आवश्यक functions implement करके लचीले तरीके से C library features का उपयोग कर सकता है
Cross-compilation toolchain
- x86_64/Linux → RISC-V cross-compilation के लिए GCC source से सीधे build की आवश्यकता होती है
- Newlib को default C library के रूप में सेट किए गए toolchain को बनाकर RISC-V binaries build करने योग्य configuration तैयार की जाती है
Toolchain details
- toolchain build करते समय
--prefix,--enable-multilib,--disable-gdb,--with-cmodel=medanyoptions का उपयोग किया गया medanyRISC-V में high-address memory region तक access संभव बनाने वाली setting है- build पूरा होने के बाद
/opt/riscv-newlibpath पर cross-compiler और Newlib library उपलब्ध हो जाते हैं
Implementing the memory and UART building blocks
- QEMU environment के 16550A UART hardware address को सीधे access करके character send/receive implement किया गया
_write,_sbrk,_closeजैसी system call replacement functions implement करके Newlib से जोड़ा गया_sbrkheap memory को_endpoint से_stack_bottomतक extend करने के तरीके से काम करता है
Application example: input and output
mainfunction मेंprintf,scanfका उपयोग संभव है, और input values भी सही तरह process होती हैं- echo support नहीं है, लेकिन
scanfके जरिए string input लेकर output किया जा सकता है - अलग runtime implement करके stack initialization और BSS section zero-fill के बाद
mainको call किया जाता है
Linker script
- execution start address
0x80000000है, और runtime code को उसी location पर रखा गया है - memory layout
.text,.rodata,.data,.bssक्रम में रखा जाता है, और heap को_endसे stack से ठीक पहले तक सेट किया गया है - stack 64KB fixed size का है, और सबसे ऊपरी address
0x80000000 + 64MBहै ASSERTstatement के माध्यम से heap और stack के टकराव को रोका गया है
The ‘gotcha’ moment
- toolchain configure करते समय
--with-cmodel=medanyका उपयोग करना ज़रूरी है ताकि0x80000000से ऊपर के addresses को संभाल सकने वाले machine instructions generate किए जा सकें - यदि C library और application code का address model अलग हो, तो link error होता है
Running the app
- Makefile के जरिए cross-compile और QEMU execution को automate किया जा सकता है
-specs=nosys.specs,-nostartfiles,-T link.ldoptions से Newlib की minimal configuration और custom runtime का उपयोग किया गयाmake debugचलाने पर QEMU console में UART के जरिए input और output सही तरह काम करते हैंqemu_debug.logके जरिए वास्तविक instruction trace देखा जा सकता है
Conclusion
- operating system के बिना भी
printf,scanf,mallocआदि का उपयोग संभव बनाने वाली संरचना Newlib से implement की गई - Newlib की building-block आधारित संरचना का उपयोग करते हुए, ज़रूरी features को ही न्यूनतम रूप में implement करना मुख्य रणनीति है
- आगे file system, memory management जैसी अतिरिक्त features भी implement की जा सकती हैं, और library compatibility बनाए रखते हुए Bare Metal में भी reuse संभव है
- पूरे project का output लगभग 220KB है, जो अपेक्षाकृत छोटा और efficient स्तर है
GitHub source: popovicu/bare-metal-cstdlib
अभी कोई टिप्पणी नहीं है.