- x86-16 assembly में लिखा गया SectorC एक अति-लघु C compiler है जो x86 मशीन के boot sector (512 bytes) के भीतर समा जाता है, और C language के एक subset को इस स्तर तक सपोर्ट करता है कि उससे वास्तव में चलने वाले प्रोग्राम लिखे जा सकते हैं
- इसमें global variables, functions, if/while statements, operators, pointer dereference, comments, inline assembly आदि शामिल हैं, इसलिए न्यूनतम संरचना के साथ भी पूरा प्रोग्राम चलाया जा सकता है
- tokenizer को सरल बनाने के लिए whitespace-based tokenization और
atoi() hash का उपयोग करते हुए Barely C language डिज़ाइन की गई, जिसने मौजूदा C syntax को बनाए रखते हुए आकार को चरम स्तर तक घटा दिया
- code optimization प्रक्रिया में jump removal, call fusion, 8-bit offset का उपयोग,
stosw/lodsw का इस्तेमाल जैसी कई assembly-स्तर की compression techniques लागू की गईं, जिससे आकार 468 bytes से घटकर 303 bytes हो गया
- नतीजतन, 512 bytes के भीतर tokenizer, parser, code generator, runtime सभी को समेटने वाला एक पूर्ण C compiler तैयार किया गया, जो software minimization का एक चरम उदाहरण दिखाता है
SectorC का अवलोकन
- SectorC एक x86-16 assembly में लिखा गया C compiler है, जो पूरी तरह 512-byte boot sector के भीतर फिट हो जाता है
- GitHub repository: xorvoid/sectorc
- समर्थित भाषा C का ऐसा subset है जिसमें वास्तविक प्रोग्राम लिखे जा सकते हैं
- समर्थित features में global variables, functions, control statements (if/while), कई operators, pointer dereference, inline assembly, comments शामिल हैं
- उदाहरण के तौर पर VGA mode में sine-wave animation ड्रॉ करने वाला code दिया गया है
डिज़ाइन पृष्ठभूमि और approach
- पारंपरिक C tokenizer इतना बड़ा होता है कि उसे 512 bytes में समाना लगभग असंभव है, इसलिए language structure को ही सरल बनाना पड़ा
- Big Insight #1: Forth language की तरह spaces से अलग किए गए token structure को अपनाकर “Barely C” नाम की एक variant language डिज़ाइन की गई
- उदाहरण:
int(main)(){while(!done){ जैसे syntax को एक ही “mega token” की तरह प्रोसेस किया जाता है
- फिर भी मौजूदा C compilers इसे वैध C code के रूप में पहचान सकते हैं
- Big Insight #2:
atoi() function को hash function की तरह इस्तेमाल कर tokens को numbers में बदला गया
- integer literals, keywords, identifiers सभी को
atoi() के परिणाम के रूप में संभाला जाता है
- identifiers तक 64K array के index के जरिए पहुंचा जाता है
Barely C implementation
- पहला implementation 468 bytes का था, जिसमें
atoi-आधारित tokens के साथ recursive descent parser संरचना अपनाई गई
- symbol table के बिना 64K segment तक hash values के जरिए सीधे पहुंच बनाई गई
- code generation में OTCC शैली के अनुसार
ax register को result storage के रूप में इस्तेमाल किया गया
- बाद में byte-threaded code प्रयोग के जरिए Forth-जैसी संरचना आज़माई गई, लेकिन 512 bytes के भीतर यह उल्टा अधिक अप्रभावी साबित हुई और इसे छोड़ दिया गया
code minimization techniques
- फिर सीधी संरचना पर लौटकर आकार 468 bytes → 303 bytes तक घटाया गया
- jump removal (fall-through), tail-call, call fusion,
stosw/lodsw का उपयोग, 8-bit jump offset बनाए रखना जैसी techniques इस्तेमाल की गईं
- इससे 207 bytes की खाली जगह मिली, जिसमें अतिरिक्त features जोड़े गए
पूर्ण C feature विस्तार
- अतिरिक्त 200 bytes के साथ पूर्ण C syntax support हासिल किया गया
- nested
if/while blocks, कई तरह के *binary operators (+, -, , &, |, ^, <<, >>, ==, !=, <, >, <=, >=)
- function definitions और recursive calls, inline assembly (
asm), single-line और multi-line comments का support
- operator table (
binary_oper_tbl) के जरिए हर operator को 4 bytes में परिभाषित किया गया, और 14 operators को 56 bytes में संभाला गया
grammar संरचना
- पूरी grammar
program, var_decl, func_decl, statement, expr आदि से बनी है
// और /* */ comments दोनों का support है
- grammar definition का टेक्स्ट स्वयं 704 bytes का है, जो वास्तविक implementation से भी बड़ा है
inline assembly और runtime
asm syntax के जरिए x86-16 machine code को सीधे insert किया जा सकता है
- I/O processing के लिए यह एक आवश्यक feature है
- runtime (
rt/) C में लिखी गई दो files से बना है
rt/lib.c: inline assembly-आधारित library routines
rt/_start.c: program entry point _start()
उदाहरण प्रोग्राम
examples/hello.c: टेक्स्ट को सीधे 0xB8000 memory में output करता है
examples/sinwave.c: VGA mode 0x13 में sine-wave animation दिखाता है
examples/twinkle.c: PC speaker पर “Twinkle Twinkle Little Star” बजाता है (sound warning सहित)
निष्कर्ष
- SectorC एक अति-लघु C compiler है जिसने असंभव लगने वाले लक्ष्य को सच कर दिखाया,
और यह software minimization तथा रचनात्मक language design का एक चरम उदाहरण पेश करता है
- लेख का अंत मज़ाकिया “हमने क्या सीखा” विकल्पों के साथ होता है,
जो असंभव को चुनौती देने की मानसिकता और software simplification के मूल्य को व्यंग्यात्मक ढंग से रेखांकित करता है
1 टिप्पणियां
Hacker News प्रतिक्रियाएँ
2000 के दशक के optimizing compilers शायद ऐसे token को बस no-op मानकर optimize कर देते 😉
boot sector game बनाना सच में nostalgia जगाने वाला जादुई अनुभव है. उन दिनों की याद आ जाती है जब programming सच में मज़ेदार लगती थी
अफ़सोस है कि आज के AI दौर में ऐसे projects की बहुत कम क़द्र होती है
मेरे project का link
तुम्हारे project में शायद boot sector के लिए code generate करने का option है.
दोनों दिलचस्प हैं, लेकिन समानता बस ‘boot sector’, ‘C’, और ‘compiler’ तक ही है
इसलिए कभी-कभी लगता है कि अब मैं ख़ास नहीं रहा
हम abstraction पर abstraction चढ़ाते जा रहे हैं, यहाँ तक कि “Hello World” चलाने के लिए भी 200MB के node_modules चाहिए
और दूसरी तरफ़ कोई 512 bytes में C compiler ठूँस देता है
यह ज़रूरी नहीं कि सबको boot sector code लिखना चाहिए, लेकिन ऐसे projects पढ़ना सच में विनम्र बना देने वाला अनुभव है. इसका शैक्षिक मूल्य भी बहुत बड़ा है
यह project अच्छी तरह दिखाता है कि C की मुख्य संरचना कितनी सरल है.
यह भी रोचक है कि C, B language से विकसित हुई, और B खुद Fortran के एक संक्षिप्त रूप से निकली थी
आख़िर assembly में अंततः jmp ही तो होता है.
और “choose your own adventure” नहीं, “chose your own adventure” होना चाहिए :)
मुझे minimalism बहुत पसंद है
यानी किसी बहुत छोटे platform-specific binary से शुरू करके धीरे-धीरे ज़्यादा जटिल tools और compilers बनाए जाएँ
उदाहरण के लिए mishmashvm और tcc_bootstrap_alt projects देखे जा सकते हैं
उस समय की चर्चा यहाँ हुई थी
SectorC: A C Compiler in 512 bytes - link - मई 2023 (80 comments) जैसा व्यवस्थित किया जा सकता है
जबकि यह project C का सिर्फ़ एक हिस्सा ही संभाल सकता है
यानी यह पूर्ण C compiler से ज़्यादा C के subset के लिए compiler है.
इस compiler से compile होने वाला code असली C compiler से भी compile हो जाएगा, लेकिन उल्टा सही नहीं है
उम्मीद है कि मैंने इतने symbol इस्तेमाल नहीं किए होंगे कि 32-bit collision हो जाए
वैसे 0x01e0~0x01fd के बीच 21 bytes की खाली जगह बची हुई है. शायद उसमें कुछ और डाला जा सकता है ;)
लेकिन मेरी याद के अनुसार atoi() को invalid input पर 0 लौटाने के लिए define किया गया था
Linux पर चलाते समय qemu invocation में coreaudio की जगह alsa कर देना चाहिए
इसके लिए मैंने GitHub पर एक pull request डाला है. अगर लेखक को मेरी verbose shell script style ठीक लगी, तो शायद merge हो जाए
अब शायद उसमें एक C compiler जोड़ने का समय आ गया है
मेरे OS project का link