- SectorC ที่เขียนด้วยแอสเซมบลี x86-16 เป็นคอมไพเลอร์ C ขนาดจิ๋วมากที่ใส่ได้ภายใน บูตเซกเตอร์ (512 ไบต์) ของเครื่อง x86 และรองรับ ส่วนย่อยของภาษา C มากพอสำหรับเขียนโปรแกรมที่ทำงานได้จริง
- รองรับ ตัวแปรโกลบอล, ฟังก์ชัน, คำสั่ง if/while, โอเปอเรเตอร์, การ dereference พอยน์เตอร์, คอมเมนต์, อินไลน์แอสเซมบลี เป็นต้น ทำให้แม้มีโครงสร้างขั้นต่ำก็ยังสามารถรันโปรแกรมที่สมบูรณ์ได้
- เพื่อทำให้ตัว tokenizer เรียบง่าย จึงออกแบบภาษา Barely C ที่ใช้ การแยกโทเค็นตามช่องว่าง และแฮชด้วย
atoi() โดยยังคงไวยากรณ์ C เดิมไว้พร้อมกับลดขนาดได้อย่างสุดขีด
- ในกระบวนการปรับแต่งโค้ด ได้ใช้เทคนิคบีบอัดระดับแอสเซมบลีหลากหลายแบบ เช่น การตัด jump, การรวม call, การใช้ออฟเซ็ต 8 บิต, การใช้
stosw/lodsw จนลดขนาดจาก 468 ไบต์เหลือ 303 ไบต์
- ผลลัพธ์คือการสร้างคอมไพเลอร์ C ที่สมบูรณ์ภายใน 512 ไบต์ โดยมีทั้ง tokenizer, parser, code generator และ runtime ครบถ้วน แสดงให้เห็น ตัวอย่างสุดขั้วของการทำซอฟต์แวร์ให้เล็กที่สุด
ภาพรวมของ SectorC
- SectorC เป็นคอมไพเลอร์ C ที่เขียนด้วย แอสเซมบลี x86-16 และใส่ได้ครบถ้วนภายใน บูตเซกเตอร์ขนาด 512 ไบต์
- ที่เก็บโค้ด GitHub คือ xorvoid/sectorc
- ภาษาที่รองรับคือส่วนย่อยของ C ในระดับที่สามารถเขียนโปรแกรมใช้งานจริงได้
- ความสามารถที่รองรับประกอบด้วย ตัวแปรโกลบอล, ฟังก์ชัน, คำสั่งควบคุม (if/while), โอเปอเรเตอร์หลายแบบ, การ dereference พอยน์เตอร์, อินไลน์แอสเซมบลี, คอมเมนต์
- มีการยกตัวอย่างโปรแกรม โค้ดที่วาดแอนิเมชันคลื่นไซน์ในโหมด VGA
ที่มาของการออกแบบและแนวทาง
- เนื่องจาก tokenizer ของภาษา C แบบเดิมมีขนาดใหญ่เกินกว่าจะใส่ใน 512 ไบต์ได้ จึงต้อง ทำให้โครงสร้างภาษาง่ายลงตั้งแต่ต้น
- Big Insight #1: นำโครงสร้างโทเค็นที่ คั่นด้วยช่องว่าง แบบภาษา Forth มาใช้ และออกแบบภาษาแปลงรูปชื่อ “Barely C”
- ตัวอย่าง: ไวยากรณ์อย่าง
int(main)(){while(!done){ ถูกจัดการเป็น “เมกาโทเค็น” เดียว
- และยังคงถูกมองว่าเป็นโค้ด C ที่ถูกต้องโดยคอมไพเลอร์ C ปกติ
- Big Insight #2: ใช้ฟังก์ชัน
atoi() เสมือนเป็น ฟังก์ชันแฮช เพื่อแปลงโทเค็นเป็นตัวเลข
- ทั้งลิเทอรัลจำนวนเต็ม, คีย์เวิร์ด และ identifier ล้วนถูกจัดการผ่านผลลัพธ์ของ
atoi()
- ส่วน identifier เข้าถึงผ่านดัชนีของอาร์เรย์ขนาด 64K
การทำ Barely C ให้ใช้งานได้จริง
- เวอร์ชันแรกมีขนาด 468 ไบต์ ใช้โครงสร้าง recursive descent parser ที่อิงโทเค็นแบบ
atoi
- ไม่ใช้ symbol table แต่เข้าถึงเซกเมนต์ 64K โดยตรงผ่านค่าแฮช
- การสร้างโค้ดใช้แนวทางแบบ OTCC โดยใช้รีจิสเตอร์
ax เป็นที่เก็บผลลัพธ์
- ต่อมามีการทดลองใช้ byte-threaded code เพื่อทำโครงสร้างแบบ Forth แต่พบว่าในข้อจำกัด 512 ไบต์กลับไม่มีประสิทธิภาพ จึงยกเลิกแนวทางนี้
เทคนิคการย่อโค้ด
- กลับไปใช้โครงสร้างแบบตรงไปตรงมาและลดขนาดจาก 468 ไบต์ → 303 ไบต์
- ใช้เทคนิคอย่าง การตัด jump (fall-through), tail-call, การรวมการเรียกใช้ (call fusion), การใช้
stosw/lodsw, และ การคงออฟเซ็ต jump แบบ 8 บิต
- ทำให้มีพื้นที่ว่างเพิ่มขึ้น 207 ไบต์สำหรับใส่ความสามารถเพิ่มเติม
ขยายสู่ความสามารถ C ที่สมบูรณ์
- ใช้อีก 200 ไบต์เพื่อรองรับ ไวยากรณ์ C ที่สมบูรณ์ยิ่งขึ้น
- บล็อก
if/while แบบซ้อนกัน, โอเปอเรเตอร์แบบไบนารี หลากหลาย (+, -, *, &, |, ^, <<, >>, ==, !=, <, >, <=, >=)
- รองรับ การประกาศฟังก์ชันและการเรียกแบบรีเคอร์ซีฟ, อินไลน์แอสเซมบลี (
asm), และ คอมเมนต์แบบบรรทัดเดียว/หลายบรรทัด
- ผ่านตารางโอเปอเรเตอร์ (
binary_oper_tbl) ที่นิยามโอเปอเรเตอร์แต่ละตัวด้วย 4 ไบต์ ทำให้รองรับโอเปอเรเตอร์ 14 ตัวใน 56 ไบต์
โครงสร้างไวยากรณ์
- ไวยากรณ์ทั้งหมดประกอบด้วย
program, var_decl, func_decl, statement, expr เป็นต้น
- รองรับคอมเมนต์ทั้ง
// และ /* */
- ตัวข้อความนิยามไวยากรณ์เองมีขนาด 704 ไบต์ ซึ่งใหญ่กว่าตัวอิมพลีเมนเทชันจริงเสียอีก
อินไลน์แอสเซมบลีและรันไทม์
- สามารถแทรก machine code ของ x86-16 ได้โดยตรง ผ่านคำสั่ง
asm
- เป็นความสามารถที่จำเป็นสำหรับการจัดการ I/O
- รันไทม์ (
rt/) ประกอบด้วยสองไฟล์ที่เขียนด้วย C
rt/lib.c: ไลบรารีรูทีนที่อิงอินไลน์แอสเซมบลี
rt/_start.c: จุดเริ่มต้นโปรแกรม _start()
โปรแกรมตัวอย่าง
examples/hello.c: แสดงข้อความโดยเขียนลงหน่วยความจำ 0xB8000 โดยตรง
examples/sinwave.c: แสดงแอนิเมชันคลื่นไซน์ในโหมด VGA 0x13
examples/twinkle.c: เล่นเพลง “Twinkle Twinkle Little Star” ผ่านลำโพง PC (มีคำเตือนเรื่องเสียง)
บทสรุป
- SectorC คือ คอมไพเลอร์ C ขนาดจิ๋วที่ทำเป้าหมายซึ่งดูเป็นไปไม่ได้ให้เกิดขึ้นจริง
และแสดงให้เห็น ตัวอย่างสุดขั้วของการย่อซอฟต์แวร์และการออกแบบภาษาอย่างสร้างสรรค์
- ตอนท้ายของบทความปิดด้วยตัวเลือกเชิงขำขันในหัวข้อ “เราเรียนรู้อะไร”
เพื่อเสียดสีและเน้นย้ำ ทัศนคติของการท้าทายสิ่งที่เป็นไปไม่ได้และคุณค่าของการทำซอฟต์แวร์ให้เรียบง่าย
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News