Hello, World

    อย่างที่เราทราบกันว่า โปรแกรมที่เขียนขึ้นจากภาษาต่างๆ บน .NET นั้นจะถูกคอมไพล์เป็นภาษา Assembly แต่ภาษา Assembly ตัวนั้นนั้นเป็นอิสระต่อ Hardware กล่าวคือ ไม่ว่าคอมไพล์บน OS ตัวใด ก็จะได้ Code แบบเดียวกันหมด ภาษาดังกล่าว เราเรียกว่า Intermediate Language (IL) ในเมื่อ Microsoft เอาแนวคิดนี้มาใช้ Microsoft ก็สร้างภาษา IL ขึ้นมาดั้งชื่อว่า MSIL  ที่จริงถ้าเรียก MSIL ว่าเป็นภาษา Assembly ก็อาจจะไม่ถูกนัก แต่ผมถือว่า โปรแกรมที่เขียนอยู่บน .NET Framework ทำงานบน Virtual Machine หรือเครื่องคอมพิวเตอร์จำลอง ที่มี CPU จำลอง และ MSIL ก็เป็นภาษาของ CPU ตัวนั้น ผมจึงเรียกมันว่าเป็น Assembly ครับ

    โดยปกติแล้วถ้าเราไม่ได้ลงรายละเอียดมาก เราก็เรียกภาษา IL ของ Microsoft ว่า MSIL แต่ถ้าเรามาดูละเอียดขึ้นหน่อย เราจะสามารถแยกออกเป็น 2 ภาษา นั่นคือ CIL ซึ่งเป็นภาษา เลขรหัสที่ .NET นำเอาไปใช้งานได้ ถ้าเทียบก็น่าจะเทียบได้กับ Machine Code ส่วนอีกภาษาหนึ่ง นั่นก็คือ MSIL ซึ่งเป็นภาษาที่มีการแปลงเลขรหัสให้อยู่ในรูปของคำพูดที่มนุษย์อ่านแล้วเข้าใจได้ง่ายกว่า แต่ก็นั่นและครับ ถ้ามันดีต่อมนุษย์ มันก็ไม่ดีต่อคอมพิวเตอร์ MSIL ต้องถูกแปลงเป็น CIL ก่อนที่ .NET จะนำเอาไปใช้ได้

    เมื่อเราได้ Code ของ CIL มา เครื่องคอมพิวเตอร์ไม่ก็สามารถเข้าใจได้ในทันที เพราะเครื่องคอมพิวเตอร์ต่างๆ นั้น จะเข้าใจภาษา Machine Code ที่ทางบริษัทสร้าง CPU กำหนดไว้เท่านั้น ไม่สามารถเข้าใจ CIL ของ Microsoft ได้ ภาษาที่ CPU เข้าใจได้ทันที เราเรียกว่า Native Language (ภาษาแม่) เท่านั้น

    ดังนั้นภาษา CIL จะต้องถูกแปลงเป็น Native Language ก่อนจึงจะทำงานได้ ถ้าเรามองอีกมุมหนึ่ง คือ เรามีอิสระในการเขียนโปรแกรม ตราบใดที่เราสร้าง CIL ได้ เราสามารถนำไปใช้งานได้เกือบทุกเครื่อง เครื่องใดก็ตามที่มีตัวแปล CIL เป็น Native Langauge ก็จะนำไปใช้ได้ นั่นก็คือเครื่องคอมพิวเตอร์นั้นได้มี Software ที่ปรับสภาพแวดล้อมให้รัน CIL ได้ มันเหมือนกันเรามี OS ย่อยซ้อนอยู่ใน OS ใหญ่ บางทีเราก็เรียกว่า Embedded OS หรือถ้าเรามองในแง่ของเครื่อง เราเหมือนว่าสามารถจำลองเครื่องคอมพิวเตอร์ใหม่ขึ้นมาได้ (Virtual Machine)

 

Overview CIL

    ภาษา CIL นั้นเป็นภาษาเครื่องแบบหนึ่งที่เราเรียกว่า Stack-based Language ซึ่งการใช้งานนั้นทุกอย่างจะกระทำกับ Stack ซึ่งแตกต่างจาก Machine Language ของ CPU ต่างที่เป็นแบบ Register-based Language คือการทำงานทุกอย่างจะกระทำกับ Register โดยเฉพาะอย่างยิ่ง Accumulator จะใช้มากเป็นพิเศษในการคำนวณ

    มีคำถามว่าทำไม CIL ไม่ใช้ Register-based Language เวลาแปลเป็น Machine Language จะได้ค่อนข้างตรงไปตรงมา เรื่องนี้ตอบไม่ยากครับ เพราะการใช้ Stack-Based นั้นยืดหยุ่นกว่า มันเป็นอิสระกับ CPU และที่สำคัญ เราสามารถ Optimize ความเร็วได้ดีกว่ามากครับ ขณะนั้นภาษา CIL นั้นได้มาตรฐานของ ECMA เป็นที่เรียบร้อยแล้ว ในอนาคตอันใกล้ก็คงจะได้มาตรฐานโลก ISO อย่างแน่นอน คงต้องบอกว่า CIL วันนี้หลุดพ้นจากความเป็นเจ้าของของ Microsoft แล้ว Microsoft ไม่มีสิทธิโดยตรงที่จะแก้ไขเนื้อหาใดๆ ของ CIL (แต่อาจจะทำผ่าน ECMA เพราะ Microsoft เป็นส่วนหนึ่งในทีมสร้างมาตรฐาน CIL ใน ECMA)

    มีคนเขียนถามผมมาว่า Microsoft จะแหกกฎ โดยการเพิ่มความสามารถต่างๆ ให้กับ CIL ใน .NET Framework หรือไม่ เหมือนกับที่เคยมีประวัติไม่ดีในอดีต ผมว่าโลกมันเปลี่ยนไปแล้ว ถ้า Microsoft ทำอย่างนั้นจริง ก็เหมือนกับเขียนด้วยมือแต่ลบด้วยเท้า พยายามแทบตายจะสร้างมาตรฐานแข่งกับ JAVA แต่สุดท้ายก็มาทำลายเสียเอง ผมว่าคงไม่ครับ สิ่งที่ Microsoft หวงที่สุดคือ Source Code แต่วันนี้ก็เปลี่ยนไป มีการเปิดเผย Source Code ออกมาในรูป Shared Source (จะเลียนแบบ Open Source ก็ดูไม่สง่า เลยคิดกติกาเองใหม่ดีกว่า)

Hello, World

hello.il

.assembly supoj {}
.
method static void Start()
{
   .entrypoint
   ldstr "Hello, World"
   call void [mscorlib]System.Console::WriteLine(class System.String)
   ret
}

    ลองมาดูรายละเอียดกันครับ โปรแกรม Hello, World ตัวนี้ อยู่ใน assembly supoj Code จะอยู่ใน Method ที่ชื่อว่า Start() ซึ่ง Syntax ก็คล้ายๆ กับ C# อยู่เหมือนกัน แต่สิ่งที่น่าสังเกต มีอยู่ 2 อย่างในเบื้องต้นครับ คือ

 

    จากนั้นเราก็ทำการ push string คำว่า "Hello, World" ลงบน Stack แล้วก็ทำการ Call Method WriteLine ที่อยู่ใน mscorlib.dll ภายใต้ NameSpace System.Console  สังเกตตัวคั่นต่างๆ เองนะครับ จำเอาไปใช้ ผมคงไม่อธิบายที่ละเครื่องหมาย (จริงๆ แล้วมันคล้ายกับ C++ ครับ) ที่น่าสังเกตก็คือ เราต้องระบุลายเซ็นให้ชัดเจนครับ ว่าจะเรียก WriteLine() ตัวไหน ในที่นี้ก็เป็น WriteLine ตัวที่รับ 1 พารามิเตอร์ เป็น String ซึ่ง String นั้น รออยู่บน Stack เป็นที่เรียบร้อยแล้ว รอ WriteLine() pop เอาไปใช้เท่านั้นครับ ถ้าใครคุ้นเคยกับภาษา Assembly ทั่วไป จะเห็นได้ว่าแตกต่างกับตัวอื่นคือไม่มีการใช้ Register เลย จากนั้นก็ ret กลับออกไปครับ

    เรามาดูวิธีการคอมไพล์กันเลยครับ

DOS Prompt

D:\msil>ilasm hello.il

Microsoft (R) .NET Framework IL Assembler. Version 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
Assembling 'hello.il' , no listing file, to EXE --> 'hello.EXE'
Source file is ANSI

Assembled global method Start
Creating PE file

Emitting members:
Global Methods: 1;
Writing PE file
Operation completed successfully

D:\msil>hello
Hello, World

D:\msil> _

    ถ้าเราอยากรู้ว่า หน้าตาของ CIL มันเป็นอย่างไร ก็ลอง /listing ใน ilasm ดังนี้ครับ

DOS Prompt

D:\msil>ilasm /listing hello

Microsoft (R) .NET Framework IL Assembler. Version 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
Assembling 'hello.IL' , with listing file, to EXE --> 'hello.EXE'
Source file is ANSI

Assembled global method Start
Creating PE file

Emitting members:
Global Methods: 1; Method 'Start'

PC (hex) Opcodes and data (hex) Label Instruction
-------- -------------------------------- --------------- ----------------
00000000 72|01000070 ldstr 1879048193
00000005 28|0100000a call
0000000a 2a| ret
----------------------------------------------------------------------


Writing PE file
Operation completed successfully

D:\msil>

 

ผลลัพธ์จริงๆของ CIL ที่ได้คือ     72 01 00 00 70 28 01 00 00 0a 2a   ครับ

29-Mar-02