1 คะแนน โดย GN⁺ 2023-07-10 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

-.NET Framework 4.x โดยใช้ไฟล์ปฏิบัติการที่พิมพ์เพียง "Hello World" เป็นเป้าหมาย ได้ลดผลลัพธ์จากการคอมไพล์ C# ปกติขนาด 4.6KB เหลือ 834 ไบต์ ด้วยการประกอบ PE ด้วยมือ

  • การทดลองกำหนดเงื่อนไขว่า ต้องใช้ managed entry point, เป็นไฟล์เดี่ยวแบบ Windows executable, ใช้ได้เฉพาะ BCL หรือไลบรารีที่มีอยู่ใน Windows ปกติเท่านั้น และ ไม่นับ 0 ไบต์ท้ายไฟล์
  • การลดขนาดทำโดยตัด nullable reference type annotations และ metadata ที่ไม่จำเป็นออก แล้วเปลี่ยนเป็น 64-bit PE เพื่อลบ imports และ base relocations
  • แทนที่จะใช้ Console.WriteLine มีการเรียก ucrtbase!puts ผ่าน P/Invoke เพื่อตัดสตรีม UTF-16 #US ออก และย้ายสตริง ASCII ไปไว้ใน พื้นที่ padding ระหว่าง PE header กับเซกชันแรก
  • ไฟล์ปฏิบัติการสุดท้ายมีขนาด 834B (0x342) เมื่อตัด trailing zero ออก และเมื่อบีบอัด ZIP เหลือ 476B แสดงให้เห็นขีดจำกัดขององค์ประกอบขั้นต่ำใน .NET PE และ CLR metadata

เงื่อนไขการทดลองและค่าตั้งต้น

  • เป้าหมายคือใส่เฉพาะไบต์ขั้นต่ำที่จำเป็นในไฟล์ปฏิบัติการ .NET เพื่อให้ CLR พิมพ์ "Hello World" ออกทาง standard output
  • กติกาของการทดลองมีดังนี้
    • แอปพลิเคชันต้องรัน managed entry point ที่เขียนด้วย C# หรือ CIL
    • รันไทม์เป้าหมายคือ .NET Framework 4.x.x
    • ห้ามมี dependency ของ third-party โดยอนุญาตเฉพาะ BCL อย่าง mscorlib หรือไลบรารีที่มีอยู่ใน Windows ปกติเท่านั้น
    • เนื่องจากข้อจำกัดด้านการจัดแนวของไฟล์ PE และ CLR ไฟล์ .NET PE ขั้นต่ำตามทฤษฎีที่รันได้บน Windows 10 ขึ้นไปจึงเล็กกว่า 1KB ไม่ได้ แต่ trailing zero bytes ท้ายไฟล์จะไม่นำมาคิดในขนาด
  • หากบิลด์โปรแกรม Hello World แบบ C# ปกติด้วย net472, C# 10 และเปิด nullable ไว้ ไฟล์ปฏิบัติการจะมีขนาด 4.6KB
  • ซอร์สโค้ดสุดท้ายทั้งหมดอยู่ที่ Full Source Code

ส่วนที่ลดได้จากผลลัพธ์การคอมไพล์ C#

  • nullable reference types ของ C# 8.0 จะถูกฝังแบบ static ลงในไฟล์ปฏิบัติการในรูปของ custom attributes และ attribute เหล่านี้เพิ่มขนาดไฟล์อย่างมาก
  • หากปิดการตรวจ nullable reference types ด้วย <Nullable>disable</Nullable> ใน .csproj attribute เหล่านี้จะหายไป แต่ด้วยข้อจำกัดการจัดแนวของไฟล์ PE ขนาดรวมยังคงเป็น 4.6KB
  • จากผลการ decompile พบว่าแม้จะปิด nullable แล้ว C# compiler ก็ยังสร้าง metadata ที่ไม่จำเป็นต่อไป
    • assembly attributes อย่าง file version หรือข้อมูลลิขสิทธิ์
    • ชนิด <Module> แบบซ่อนที่อยู่นอกเหนือจากคลาส Program
  • แทนที่จะไล่หาการตั้งค่าเพิ่มใน C# compiler เพื่อบีบให้เล็กสุด จึงเลือกสร้างไฟล์ปฏิบัติการ .NET โดยตรงด้วย AsmResolver
  • โมดูลที่สร้างเองนี้ใส่ฟังก์ชัน main ไว้ในชนิด <Module> และมี CIL body เพียง Ldstr "Hello World", Console.WriteLine, Ret
  • วิธีนี้ทำให้ขนาดไฟล์ลดลงเหลือประมาณครึ่งหนึ่งของเดิม

ลบ imports และ base relocations ด้วย 64-bit PE

  • ไฟล์ปฏิบัติการที่สร้างขึ้นมีสองเซกชันคือ .text และ .reloc โดย data directory ของ Imports และ Base Relocations กินพื้นที่ค่อนข้างมาก
  • ไฟล์ปฏิบัติการ .NET แบบ AnyCPU หรือ 32 บิต ต้องมี unmanaged entry point ที่เรียก mscoree!_CorExeMain จึงจำเป็นต้องมี imports directory
  • ไฟล์ปฏิบัติการ .NET ปกติมักรองรับการ relocate ได้ จึงต้องมี base relocation สำหรับการเรียก imported function นี้ด้วย
  • base relocation โดยทั่วไปจะอยู่ในเซกชันแยก และแต่ละเซกชันต้องจัดแนวอย่างน้อยทีละ 0x200 ไบต์ ทำให้ขนาดไฟล์พองเป็นอย่างน้อย 1KB
  • ไฟล์ปฏิบัติการ .NET แบบ 64 บิตไม่ต้องมี unmanaged entry point จึงลบทั้งสอง directory และเซกชัน .reloc ได้ด้วยการตั้งค่าดังนี้
    • module.PEKind = OptionalHeaderMagic.PE64
    • module.MachineType = MachineType.Amd64
  • ขั้นตอนนี้ทำให้ไปถึงขนาดขั้นต่ำตามทฤษฎีของไฟล์ .NET PE ที่ใช้งานได้ คือ 1KB

ลบชื่อ metadata, GUID และ public key token

  • หลังจากนั้น การวัดขนาดจะไม่ดูจากขนาดไฟล์ใน Windows Explorer แต่ดูจาก ตำแหน่งถัดจาก non-zero byte ตัวสุดท้าย ใน hex editor
  • ไฟล์ PE ขนาด 1KB ในเกณฑ์นี้ลดลงมาอยู่ที่ 991 ไบต์ (0x3DF) แล้ว
  • heap #Strings เป็น metadata stream ที่มีขนาดใหญ่เป็นอันดับสองในไบนารี .NET และเก็บชื่อ type กับ method ที่ tables stream #~ ใช้งาน
  • สามารถตั้งชื่อที่ไม่สำคัญต่อรันไทม์เป็น null ได้โดยที่โปรแกรมยังทำงานปกติ และลดไปได้ 32 ไบต์
  • สตรีม #GUID เก็บ GUID ที่ Mvid ในตาราง Module อ้างอิง แต่ในการทดลองนี้ไม่ต้องใช้ตัวระบุเวอร์ชัน จึงลบออกได้
    • ลบ Mvid ขนาด 16 ไบต์
    • ลบทั้งสตรีม #GUID ที่ว่างเปล่าและ header 16 ไบต์ของมัน
    • รวมแล้วลดได้ 32 ไบต์
  • mscorlib ที่ถูกอ้างอิงเพื่อเรียก Console::WriteLine โดยทั่วไปจะมี public key token ขนาด 8 ไบต์ติดมาด้วย
  • หากไม่มี public key token, CLR จะไม่ตรวจสอบความถูกต้องของ assembly token นี้ และในการทดลองนี้จึงลบมันออก
  • หลังขั้นตอนนี้ ขนาดไฟล์เหลือ 918 ไบต์

ลบ Console.WriteLine และใช้สตริง ASCII

  • "Hello World" ถูกเก็บไว้ใน metadata stream #US ของ .NET โดยอยู่ในรูป อาร์เรย์ตัวอักษร 16 บิต ที่มี length prefix และมี 0 ไบต์เพิ่มท้าย
  • อักขระทุกตัวในสตริงที่จะพิมพ์มี code point ต่ำกว่า 0xFF จึงแทนเป็น ASCII แบบ 1 ไบต์ได้ แต่ไม่มีวิธีให้ CLR ตีความสตริงใน #US stream เป็น ASCII
  • จึงเรียก unmanaged function ucrtbase!puts ผ่าน P/Invoke แทน Console::WriteLine
    • รูปแบบประกาศใน C# คือ [DllImport("ucrtbase")] static extern int puts(nint str);
    • puts รับพอยน์เตอร์ไปยังสตริง ASCII ที่ลงท้ายด้วยศูนย์
  • เพื่อให้รู้ runtime address ของสตริงตั้งแต่ตอนคอมไพล์ จึงปิดแฟลก DynamicBase ใน DllCharacteristics ของ PE optional header
    • ตั้ง image base แบบคงที่
    • วางสตริง ASCII ไว้ในเซกชัน .text
    • คำนวณ runtime address เป็น module_base_address + rva_ascii_string
  • เพื่อให้ CLR เคารพแฟลกนี้ จึงปิดแฟลก ILOnly ใน .NET data directory ด้วย
  • การเปลี่ยนนี้ทำให้ลบ wide-character string, สตรีม #US และการอ้างอิง System.Console::WriteLine ออก แล้วแทนด้วย definition ของ puts และ metadata สำหรับ P/Invoke
  • ผลลัพธ์คือขนาดเหลือ 889 ไบต์ (0x379)

micro-optimization ขั้นสุดท้าย

  • definition มาตรฐานของ puts จะคืนค่าจำนวนอักขระที่พิมพ์เป็น int32 แต่โปรแกรมนี้ไม่ได้ใช้ค่าดังกล่าว
  • ใน 64-bit PE ตาม x64 calling convention ของ Microsoft ค่าที่คืนมาจะอยู่ในรีจิสเตอร์ RAX ไม่ได้อยู่บน .NET evaluation stack
  • หากเปลี่ยน P/Invoke definition ให้คืนค่าเป็น void ก็จะลบคำสั่ง pop ที่ใช้ทิ้งค่าคืนในเมธอด main ได้
  • ขนาด PE header เล็กกว่า 0x200 จึงเกิด padding data ระหว่าง header กับเซกชันแรก
  • Windows PE Loader จะ map PE header เข้าหน่วยความจำแบบอ่านได้ และช่วงนี้รวม padding data ด้วย
  • หากย้ายสตริง ASCII ไปไว้ใน พื้นที่ padding นี้ จะลดขนาดไฟล์ได้อีก 13 ไบต์
  • เนื่องจากไม่อ้างอิง Console::WriteLine อีกต่อไป จึงลบการอ้างอิง mscorlib ออกได้ด้วย
    • มีตารางหนึ่งใน tables stream #~ ที่ลดลง
    • ชื่อ mscorlib ก็ถูกลบออกจากสตรีม #Strings ด้วย
  • VersionString ใน .NET metadata directory โดยปกติเป็น "v4.0.30319" และมี padding ให้เป็นจำนวนเท่าของ 4 ไบต์ รวมเป็น 12 ไบต์
  • หากย่อสตริงนี้เหลือแค่ v4.0. ก็ยังบูต CLR 4.0 และรันโปรแกรมได้ ทำให้ลดได้อีก 4 ไบต์ หลังรวม padding
  • จุด . ท้ายสตริงดูเหมือนจำเป็น เพราะหากตัดให้สั้นกว่านี้ โปรแกรมจะบูตไม่สำเร็จ

ผลลัพธ์สุดท้าย

  • ไบนารีสุดท้ายมีขนาด 834 ไบต์ (0x342) เมื่อตัด trailing zero ออก
  • เมื่อบีบอัด ZIP จะเหลือ 476 ไบต์ ซึ่งเล็กกว่ากรณีที่ยังไม่ได้ทำ optimization เพิ่มหลังแตะขีดจำกัด 1KB ซึ่งอยู่ที่ 582 ไบต์
  • การทดลองนี้เริ่มจาก Hello World ขนาด 4.6KB ที่ C# compiler สร้าง และลดลงจนเหลือไฟล์ PE ที่ประกอบเองขนาด 834B
  • โปรแกรมสุดท้ายยังคงพิมพ์ "Hello World" ได้ตามปกติ
  • งานนี้ใกล้เคียงกับการทดลองเพื่อสำรวจ ขีดจำกัดขององค์ประกอบขั้นต่ำ ของรูปแบบไฟล์โมดูล .NET และ CLR metadata มากกว่าการใช้งานจริง

1 ความคิดเห็น

 
GN⁺ 2023-07-10
ความเห็นจาก Hacker News
  • ชอบการทดลองแนว โปรแกรมที่เล็กที่สุดที่ยังรันได้จริง แบบนี้มาก
    Michal Strehovský เคยใช้เฟรมเวิร์กที่ตอนนี้รู้จักกันในชื่อ .NET สร้างเกม Snake ที่มีขนาดไม่ถึง 8KB โดยไม่ต้องพึ่ง .NET runtime ภายนอก
    Medium ไม่ค่อยโอเค และตอนนี้ Twitter ก็ไม่ค่อยมีประโยชน์ แต่จำได้คร่าว ๆ ว่า "hello world" ตัวนั้นรองรับถึง Windows 3.11 ด้วย
    https://medium.com/@MStrehovsky/building-a-self-contained-ga... [https://web.archive.org/web/20200103110836/https://medium.co... | https://archive.ph/b6qXE]
    https://news.ycombinator.com/item?id=22010159 (2020)
    https://news.ycombinator.com/item?id=22104734
    งานล่าสุดและช่องทางสนับสนุนดูได้ที่ https://flattened.net: "bflat - C# as you know it but with Go-inspired tooling"

    • พูดต่อจากประเด็น C# แบบ "Go-inspired" ใน .NET มี System.Threading.Channels อยู่
      https://learn.microsoft.com/en-us/dotnet/core/extensions/cha...
    • ถ้าแอป C# เล็กลงจนผู้ใช้รู้สึกว่าเวลาโหลดแทบจะเป็นศูนย์ ก็สงสัยว่าจะช่วยทำให้ C# WebAssembly ใช้งานได้จริงมากขึ้นหรือไม่
      จำได้ว่าขนาดดาวน์โหลดส่วนใหญ่เป็นตัวไลบรารีของ .NET เอง
      และก็สงสัยว่ามี เฟรมเวิร์ก/เอนจินเกม 2D ที่ทำไบนารีขนาดเล็กได้ โดยเจาะเป้าเบราว์เซอร์และใช้ C# หรือไม่
    • ต้องยกความดีความชอบให้ Michal และทีม CoreRT ที่ทำให้กลับมามอง C# ใหม่ และถ้าวันนี้ไม่มี NativeAOT ก็คงไม่คิดจะพิจารณา C# เลย โดยเฉพาะเมื่อมี Go อยู่แล้ว
  • โพสต์นี้อาจทำให้สับสนได้ ไฟล์ executable นี้ต้องใช้ runtime ที่ติดตั้งอยู่ในระบบ และจริง ๆ แล้วในปี 2023 ก็ยังใช้ .NET Framework 4.7.2
    ถ้าจะเทียบวิธีนี้อย่างยุติธรรม อาจควรเทียบกับไฟล์ .jar หรือ .py มากกว่า
    ถ้าเอาเกณฑ์เป็นไฟล์ executable จริง ๆ Native AOT binary ที่รันได้บน Windows, Linux, macOS น่าจะเหมาะกว่า
    แต่ก็เป็นธรรมดาที่มันจะใหญ่กว่ามาก เพราะต้องรวมโค้ดช่วยเหลืออย่าง GC, ThreadPool, Console เข้าไปด้วย

    • ไม่เชิงนะ exe ที่ได้จริงแทบไม่ได้ใช้ .NET Framework เลยนอกจากเรียก main
      ลอจิกที่พิมพ์ไบต์ออกคอนโซลทำผ่านการเรียก pinvoke ไปยัง unmanaged code ที่ ucrt.dll เปิดให้ใช้
      บทความลดขนาด Snake ที่แชร์ในคอมเมนต์อื่นก็ทำสิ่งเดียวกันบน .NET Core ซึ่งเป็น .NET รุ่นใหม่ที่ไม่ได้ bundle มากับ Windows และได้ไบนารีที่ไม่ใช่ .NET ออกมาจริง ๆ
      [0]: https://medium.com/@MStrehovsky/building-a-self-contained-ga...
    • การเอา native binary ที่ลิงก์แบบ static ทั้งหมดไปเทียบกับไบนารีที่โหลดไลบรารีบางส่วนหรือทั้งหมดแบบ dynamic ก็ไม่ค่อยยุติธรรมเหมือนกัน
      การเทียบ container image น่าจะเป็นจุดเริ่มต้นที่ดี ใช้ base image ที่เล็กที่สุดเท่าที่ทำได้ หรือถ้าเป็นไปได้ก็ใช้ "FROM scratch" แต่ต้องเทียบกันในสถาปัตยกรรมเดียวกันเท่านั้น
      ถ้าจะตัดตัวแปรอย่างการรัน 32 บิตบน 64 บิต หรือ pointer compression ออกไป ก็น่าจะเลือก 32 บิต
      จากนั้นอาจเทียบขนาด export tar แบบไม่บีบอัด ถึงจะไม่ยุติธรรมสมบูรณ์แต่ก็ช่วยลดตัวแปรที่ชัดเจนได้
      คิดไปคิดมา การเทียบ ขนาด image หลังบีบอัดสูงสุด อาจยุติธรรมกว่าด้วยซ้ำ ถ้าต้องการนับผลจากการบีบอัดภายในคอนเทนเนอร์ด้วย แน่นอนว่าต้องใช้อัลกอริทึมและพารามิเตอร์เดียวกัน หรือไม่ก็เหมือน benchmark การบีบอัดที่ต้องบวกขนาดตัวถอดบีบอัดเข้าไปในผลลัพธ์สุดท้ายด้วย
    • hello world ของฉันต้องใช้เฟรมเวิร์ก "bash" และมีขนาด 0 ไบต์
      เรียกแบบนี้ได้เลย: echo "hello world"
    • .NET Framework ถูกฝังมากับ Windows และอย่างน้อยตั้งแต่ Vista เป็นต้นมาก็เป็นองค์ประกอบที่ต้องมี
      โดยเฉพาะ .NET Framework 4.7.2 ก็น่าจะมีมาให้เป็นค่าเริ่มต้นใน Windows เวอร์ชันที่ยังรองรับอยู่
    • ไม่แน่ใจว่าสิ่งที่เราควรสนใจคือ "ความยุติธรรม" หรือ "ความเป็นจริง"
      บน Windows ติดตั้งใหม่ในปัจจุบันแทบเป็นไปไม่ได้ที่จะไม่มี .NET แต่บน Linux และ macOS ไม่มีมาให้โดยปริยาย การเอาเรื่องนั้นมาตั้งเป็นเกณฑ์ความยุติธรรมก็ดูแปลก ๆ
  • เสริมอีกนิด สงสัยว่ามีใครสังเกตเห็นไหมว่าผู้เขียนอยู่ที่ McMurdo Station, Antarctica
    ไม่คิดเลยว่าจะมีคนที่ใช้เทคสแต็กแบบนี้อยู่ที่ฐานนั้นด้วย: https://usscar.org/directory?combine=&field_usscar_nsf_progr...
    น่าจะเป็นเรื่องที่น่าสนใจทีเดียว

    • ผมเคยไป McMurdo ระหว่างทริปวิจัยครั้งหนึ่ง
      สิ่งที่คนนอกมักแปลกใจคือ คนส่วนใหญ่ที่นั่นเป็นบุคลากรสนับสนุน ส่วนนักวิทยาศาสตร์มีสัดส่วนเล็กน้อย น่าจะราว ๆ 20% เท่านั้น
      บุคลากรสนับสนุนมาจากแทบทุกสายอาชีพที่จำเป็นต่อการขับเคลื่อนเมืองสมัยใหม่ เช่น นักดับเพลิง ช่างไม้ พ่อครัว ช่างซ่อมบำรุง ฯลฯ
      อาจเป็นเพราะกระบวนการคัดเลือก คนแทบทั้งหมดจึงเก่งมากและอยู่ระดับแนวหน้าของสายงานตัวเอง มีคนแบบ Swiss Army knife ที่มีทักษะกว้างขวางอยู่มากจนน่าทึ่ง
      ความยากลำบากอันเป็นเอกลักษณ์ของการใช้ชีวิตและทำงานที่นั่นดึงดูดคนที่มีแรงขับสูงและมีความเป็นเอกลักษณ์เข้ามาเหมือนแมลงเข้าหาแสงไฟ และหลายคนก็กลับไปทุกปี เป็นชุมชนที่ยอดเยี่ยม
    • ในกรณีนี้ผมไม่เข้าใจประโยคที่ว่า "ใช้วันเสาร์ไปอย่างโง่ ๆ"
      อยู่ที่นั่นแล้วจะไปทำอะไรอย่างอื่นได้อีกล่ะ?
    • ลองดู https://brr.fyi/
    • สงสัยว่าหาเจอได้ยังไง
      ในเมตาดาต้า .NET หรือ about ก็ไม่เห็นมี
  • มีคนบอกว่ามันทำให้ไฟล์บวมขึ้นอย่างน้อยเท่านั้น เพราะทุกเซกชันต้องจัดแนวตามค่าการจัดแนวเซกชันขั้นต่ำที่เป็นไปได้คือ 0x200 ไบต์ แต่ 0x200 คือ 512 ไบต์ หรือ 0.5KB
    ผมเคยทำ optimization ขนาด PE ระดับนี้มานานมากแล้ว แต่จำได้ว่า Windows 9x มีขั้นต่ำที่ 512 ส่วน NT รับค่าการจัดแนวที่เล็กได้ถึง 1
    และผมก็ไม่เห็นทริกสมัยก่อนที่เคยล้ำที่สุดอย่างการซ้อนทับ DOS MZ กับ PE header: http://www.phreedom.org/research/tinype/
    แล้วยังทำให้นึกได้ว่าใน demoscene เขาทำสิ่งนี้กันใน 1KB binary ได้ด้วย:
    https://www.pouet.net/prodlist.php?type%5B%5D=1k&platform%5B...

  • นี่ไม่ใช่การเสียเวลาแบบโง่ ๆ เลย
    การเจาะลึกลงไปในรายละเอียดของไบนารีทำให้ได้ความเข้าใจลึกซึ้งว่ามันถูกสร้างขึ้นอย่างไร และแนวคิดที่เรียนรู้จากตรงนั้นก็ช่วยเพิ่มพูนความรู้ได้มาก
    ถ้ามันน่าสนใจและทำให้ได้เรียนรู้อะไรสักอย่าง มันก็คุ้มค่ากับเวลาและความพยายามเสมอ

  • อันนี้เกี่ยวข้องและน่าสนใจกว่ามาก: https://twitter.com/MStrehovsky/status/1669502394827419648
    ใจความคือ "C# Hello World แบบ native compile ที่ self-contained สมบูรณ์รวมทุกอย่างแม้แต่ GC สามารถย่อเหลือประมาณ 440KB ได้"
    .NET classic framework เป็นมรดกเก่าของ Windows ที่ไม่แนะนำให้ใช้อีกต่อไปแล้ว และไม่ควรเอาไปเป็นฐานสำหรับแอปใหม่

    • exe ที่ได้เพียงแค่พึ่งพารายละเอียดการ implement ของไลบรารี ucrt.dll ชั้นล่างที่เปิดให้เรียกผ่าน pinvoke แบบ unmanaged เท่านั้น ไม่ได้ "ใช้" framework จริง ๆ
    • ถ้าคุณกำลังทำแอปที่พึ่งพา Office/COM API ก็อาจเป็นข้อยกเว้น
  • ผมหวังว่าจะเป็นเรื่องของไบนารี "ของจริง" คือไฟล์รัน .NET ที่ native compile แล้วแบบ .NET AOT
    https://learn.microsoft.com/en-us/dotnet/core/deploying/nati...

    • ตอนนี้ทำตัวอย่าง .NET AOT ขนาดหลาย MB ได้แล้ว
      บิลด์ AOT ที่ลดขนาดได้มากที่สุดดูเหมือนใกล้จะทะลุกำแพง 1MB เร็ว ๆ นี้:
      https://github.com/AustinWise/SmallestDotnetHelloWorlds
  • ยินดีด้วย คุณเพิ่งตัดการรองรับ Unicode ทิ้ง แล้วสร้าง C call ไปที่ puts
    แบบนี้ใช้ C compiler คอมไพล์ตรง ๆ เลยจะไม่ง่ายกว่าหรือ?
    thats_just_c_with_extra_steps.jpg

    • การข้ามขั้นตอนคอมไพล์ไปแทบทั้งหมดแบบนี้มันแอบหมดสนุกนิด ๆ
  • ผมเพิ่งลองใน Oberon+ IDE แล้วได้ Hello.dll ขนาด 2048 ไบต์ จากโมดูลนี้
    module Hello
    begin
    println("hello world")
    end Hello
    ใช้ตัวสร้างแอสเซมบลี https://github.com/rochus-keller/Pelib

    • Nicklaus Wirth คิดถูก
      ผมรู้สึกแบบนั้นตั้งแต่ครั้งแรกที่ใช้ Lazarus/FreePascal และยิ่งอ่านงานเขียนของเขามากขึ้นก็ยิ่งรู้สึกว่าใช่
      ช่วงหลังผมก็คิดว่าทางออกจาก "การเวียนว่าย" ของแนวคิดแบบนี้อาจเป็น WASM แต่ผมยังปล่อยมือจากฮาร์ดแวร์แบบนั้นไม่ได้
      ผมมันดิบเกินกว่าจะยอมรับเครื่องจักรทางจิตวิญญาณที่คุณเอาค้อนบนโต๊ะมาทุบไม่ได้
      คอมพิวเตอร์ส่วนกลางระดับโลกแบบ ทำลายไม่ได้ อย่าง Ethereum ที่รันอยู่บนฮาร์ดแวร์ของคนอื่น ใช้เวลาคำนวณมูลค่าหลายพันดอลลาร์ และยังช้ากว่า RPi ให้ความรู้สึกเหมือนเป็นของต้องห้ามสำหรับผมในระดับพื้นฐานบางอย่าง
      ผมยังอยากทำเสื้อยืดที่มีหน้า Wirth พร้อมคำว่า "Wirth was right"
    • ถ้าเป็น Oberon+ มันน่าจะ self-hosting ไม่ใช่เหรอ
      มีเศษซากของ ecosystem C++ เยอะเกินไป
      มันทำให้นึกถึงโปรเจกต์ forge สำหรับโฮสต์ซอฟต์แวร์โอเพนซอร์สที่ชอบโปรโมตตัวเองว่าเป็นทางเลือกแทน GitHub กับ GitLab แต่พอจะไป clone โค้ดหรือรายงานบั๊กจริง ๆ กลับอยู่บน GitHub กันหมด
    • สงสัยว่าท้ายไฟล์ถูกเติมด้วยศูนย์หรือเปล่า
      น่าจะมีออปชันสำหรับปิดสิ่งนี้
  • เนื้อหาที่ทำให้มุมมองเปิดกว้างคือการที่สามารถลดขนาด .exe ให้ต่ำกว่า 1KB ได้
    ถ้าใครสามารถลดขนาด Hello World .exe ของ Flutter ลงมาเหลือ 1MB ได้ก็คงสุดยอดมาก

    • ขั้นแรกน่าจะเป็นการโน้มน้าวให้ Microsoft ใส่ Flutter มาใน Windows
    • สงสัยว่าถ้าคอมไพล์แค่ "Hello world" ด้วย Dart จะนับว่าใช้ได้ไหม