อ่าน 7 นาที
ภาษากลางทั่วไป
ภาษาตัวกลางทั่วไป ( CIL ) ซึ่งเดิมเรียกว่า ภาษาตัวกลางของ Microsoft ( MSIL ) หรือ ภาษาตัวกลาง ( IL ) [ 1 ] คือชุดคำสั่งไบนารีของ ภาษาตัวกลาง ที่กำหนดไว้ในข้อกำหนด...
ภาษากลางทั่วไป
ภาษาตัวกลางทั่วไป ( CIL ) ซึ่งเดิมเรียกว่าภาษาตัวกลางของ Microsoft ( MSIL ) หรือภาษาตัวกลาง ( IL ) [ 1 ]คือชุดคำสั่งไบนารีของภาษาตัวกลาง ที่กำหนดไว้ในข้อกำหนด โครงสร้างพื้นฐานภาษาทั่วไป (CLI) [ 2 ]คำสั่ง CIL จะถูกดำเนินการโดยสภาพแวดล้อมรันไทม์ที่เข้ากันได้กับ CIL เช่นCommon Language Runtimeภาษาที่กำหนดเป้าหมาย CLI จะคอมไพล์เป็น CIL CIL เป็นไบต์โค้ดแบบอิงตามสแต็กและเชิงวัตถุ โดยทั่วไปแล้วรันไทม์ จะคอมไพ ล์ คำสั่ง CIL เป็นโค้ดเนทีฟแบบทันที
CIL เดิมทีรู้จักกันในชื่อ Microsoft Intermediate Language (MSIL) ในช่วงเบต้าของการเปิดตัวภาษา .NET เนื่องจากการกำหนดมาตรฐานของC#และ CLI ทำให้ไบต์โค้ดนี้เป็นที่รู้จักอย่างเป็นทางการในชื่อ CIL [ 3 ] คำจำกัดความไวรัส ของ Windows Defenderยังคงอ้างถึงไบนารีที่คอมไพล์ด้วย MSIL [ 4 ]
ข้อมูลทั่วไป
ระหว่างการคอมไพล์ภาษาการเขียนโปรแกรม CLIโค้ดต้นฉบับจะถูกแปลงเป็นโค้ด CIL แทนที่จะเป็นโค้ดออบเจ็กต์ เฉพาะแพลตฟอร์มหรือโปรเซสเซอร์ CIL เป็น ชุดคำสั่งที่ไม่ขึ้นกับ CPUและแพลตฟอร์ม ซึ่งสามารถดำเนินการได้ในสภาพแวดล้อมใดๆ ที่รองรับโครงสร้างพื้นฐานภาษาทั่วไป เช่นรันไทม์ .NETบนWindowsหรือ รันไทม์ Mono แบบข้ามแพลตฟอร์ม ในทางทฤษฎีแล้ว สิ่งนี้จะช่วยลดความจำเป็นในการแจกจ่ายไฟล์ปฏิบัติการที่แตกต่างกันสำหรับแพลตฟอร์มและประเภท CPU ที่แตกต่างกัน โค้ด CIL จะได้รับการตรวจสอบความปลอดภัยระหว่างรันไทม์ ซึ่งให้ความปลอดภัยและความน่าเชื่อถือที่ดีกว่าไฟล์ปฏิบัติการที่คอมไพล์แบบดั้งเดิม[ 5 ] [ 6 ]
ขั้นตอนการดำเนินการมีดังนี้:
- โค้ดต้นฉบับจะถูกแปลงเป็นไบต์โค้ด CIL และสร้างแอสเซมบลี CLI ขึ้นมา
- เมื่อเรียกใช้โค้ดแอสเซมบลี CIL โค้ดนั้นจะถูกส่งผ่าน คอมไพเลอร์ JITของรันไทม์เพื่อสร้างโค้ดเนทีฟ อาจใช้การคอมไพล์ล่วงหน้าได้เช่นกัน ซึ่งจะช่วยลดขั้นตอนนี้ แต่จะทำให้ไฟล์ปฏิบัติการไม่สามารถพกพาได้ในหลายแพลตฟอร์ม
- หน่วยประมวลผลของคอมพิวเตอร์จะประมวลผลโค้ดเนทีฟ
คำแนะนำ
ไบต์โค้ด CIL มีคำสั่งสำหรับงานกลุ่มต่างๆ ดังต่อไปนี้:
- โหลดและจัดเก็บ
- เลขคณิต
- การแปลงประเภท
- การสร้างและการจัดการวัตถุ
- การจัดการสแต็กตัวดำเนินการ (push / pop)
- การถ่ายโอนการควบคุม (การแยกสาขา)
- การเรียกใช้เมธอดและการส่งคืนค่า
- การโยนข้อยกเว้น
- การทำงานพร้อมกันโดยอาศัยมอนิเตอร์
- การจัดการข้อมูลและตัวชี้ฟังก์ชันเป็นสิ่งจำเป็นสำหรับโค้ด C++/CLI และโค้ด C# ที่ไม่ปลอดภัย
แบบจำลองการคำนวณ
ภาษา Common Intermediate Language (CLI) เป็นภาษาเชิงวัตถุและใช้สแต็กซึ่งหมายความว่าพารามิเตอร์คำสั่งและผลลัพธ์จะถูกเก็บไว้ในสแต็กเดียว แทนที่จะเก็บไว้ในรีจิสเตอร์หลายตัวหรือตำแหน่งหน่วยความจำอื่นๆ เหมือนในภาษาโปรแกรม ส่วน ใหญ่
โค้ดที่บวกเลขสองจำนวนในภาษาแอสเซมบลี x86โดยที่ eax และ edx ระบุรีจิสเตอร์อเนกประสงค์ สองตัวที่แตกต่างกัน :
เพิ่มeax , edxเขียนโค้ดในภาษาตัวกลาง (IL) โดยที่ 0 คือ eax และ 1 คือ edx:
ldloc.0 // ผลักตัวแปรโลคอล 0 ลงในสแต็กldloc.1 // ผลักตัวแปรโลคอล 1 ลงในสแต็กadd // ดึงค่าสองค่าบนสุด ของ สแต็ ก ออกมาแล้วบวกเข้าด้วยกัน จากนั้นผลักผลลัพธ์ ลงในสแต็กstloc.0 // ดึงค่าค่าบนสุดของสแต็กออกมาแล้วเก็บค่าไว้ในตัวแปรโลคอล 0ในตัวอย่างหลังนี้ ค่าของรีจิสเตอร์สองตัว คือ eax และ edx จะถูกผลักลงบนสแต็กก่อน เมื่อมีการเรียกใช้คำสั่งบวก ตัวถูกดำเนินการจะถูก "ดึงออก" หรือดึงกลับมา และผลลัพธ์จะถูก "ผลัก" หรือจัดเก็บลงบนสแต็ก จากนั้นค่าที่ได้จะถูกดึงออกจากสแต็กและจัดเก็บไว้ใน eax
แนวคิดเชิงวัตถุ
CIL ถูกออกแบบมาให้เป็นภาษาเชิงวัตถุ ผู้ใช้สามารถสร้างวัตถุ เรียกใช้เมธอด และใช้งานสมาชิกประเภทอื่นๆ เช่น ฟิลด์ได้
ทุกเมธอด (ยกเว้นบางกรณี) จำเป็นต้องอยู่ในคลาส ดังนั้นเมธอดแบบ static นี้ก็เช่นกัน:
.class public Foo { .method public static int32 Add ( int32 , int32 ) cil managed { .maxstack 2 ldarg .0 // โหลดอาร์กิวเมนต์แรก; ldarg .1 // โหลดอาร์กิวเมนต์ที่สอง; add // บวกกัน; ret // คืนค่าผลลัพธ์; } }เมธอด Add ไม่จำเป็นต้องประกาศอินสแตนซ์ของ Foo เพราะมันถูกประกาศเป็นแบบ static อยู่แล้ว และสามารถใช้งานได้ดังนี้ใน C#:
int r = Foo.Add ( 2 , 3 ) ; // 5ในระบบ CIL จะมีลักษณะดังนี้:
ldc.i4.2 ldc.i4.3 call int32 Foo :: Add ( int32 , int32 ) stloc.0คลาสอินสแตนซ์
คลาสอินสแตนซ์ประกอบด้วยคอนสตรัคเตอร์ อย่างน้อยหนึ่งตัว และ สมาชิก อินสแตนซ์ บางส่วน คลาสต่อไปนี้มีชุดเมธอดที่แสดงถึงการกระทำของวัตถุรถยนต์
. class public Car { . method public specialname rtspecialname instance void . ctor ( int32 , int32 ) cil managed { /* Constructor */ }. เมธอดpublic void Move ( int32 ) cil managed { /* ละเว้นการใช้งาน */ } . เมธอดpublic void TurnRight () cil managed { /* ละเว้นการใช้งาน */ } . เมธอดpublic void TurnLeft () cil managed { /* ละเว้นการใช้งาน */ } . เมธอดpublic void Brake () cil managed { /* ละเว้นการใช้งาน */ } }การสร้างวัตถุ
ในภาษา C# การสร้างอินสแตนซ์ของคลาสทำได้ดังนี้:
รถmyCar = รถใหม่( 1 , 4 ); รถyourCar = รถใหม่( 1 , 3 );และข้อความเหล่านั้นก็โดยคร่าวๆ เหมือนกับคำแนะนำเหล่านี้ใน CIL:
ldc . i4 .1ldc . i4 .4อินสแตนซ์newobj void Car ::. ctor ( int32 , int32 )stloc .0 // myCar = รถใหม่ (1, 4);ldc . i4 .1ldc . i4 .3อินสแตนซ์newobj void Car ::. ctor ( int32 , int32 )stloc .1 // yourCar = new Car(1, 3);การเรียกใช้เมธอดอินสแตนซ์
ในภาษา C# การเรียกใช้เมธอดแบบอินสแตนซ์จะทำได้ดังนี้:
myCar . ย้าย( 3 );ตามที่อ้างถึงใน CIL:
ldloc .0 // โหลดอ็อบเจ็กต์ "myCar" ลงบนสแต็กldc . i4 .3 เรียกอินสแตนซ์void Car :: Move ( int32 )เมตาเดตา
โครงสร้างพื้นฐานภาษาทั่วไป (CLI) บันทึกข้อมูลเกี่ยวกับคลาสที่คอมไพล์แล้วในรูปแบบของเมตาเดตาเช่นเดียวกับไลบรารีประเภทในโมเดลออบเจ็กต์คอมโพเนนต์สิ่งนี้ช่วยให้แอปพลิเคชันสามารถรองรับและค้นหาอินเทอร์เฟซ คลาส ประเภท เมธอด และฟิลด์ในแอสเซมบลีได้ กระบวนการอ่านเมตาเดตาดังกล่าวเรียกว่า " การสะท้อน " (reflection)
เมตาเดตาคือข้อมูลในรูปแบบของ "แอตทริบิวต์" แอตทริบิวต์สามารถปรับแต่งได้โดยการขยายAttributeคลาส นี่เป็นคุณสมบัติที่ทรงพลัง ช่วยให้ผู้สร้างคลาสสามารถเพิ่มข้อมูลเพิ่มเติมให้กับคลาส ซึ่งผู้ใช้งานคลาสสามารถนำไปใช้ได้อย่างมีความหมายหลากหลายวิธี ขึ้นอยู่กับขอบเขตการใช้งาน
ตัวอย่าง
ด้านล่างนี้คือโปรแกรม "Hello, World!" พื้นฐาน ที่เขียนด้วยภาษาแอสเซมบลี CIL โปรแกรมนี้จะแสดงข้อความ "Hello, world!"
. assembly Hello {} . assembly extern mscorlib {} . method static void Main () { . entrypoint . maxstack 1 ldstr "Hello, world!" call void [ mscorlib ] System . Console :: WriteLine ( string ) ret }โค้ดต่อไปนี้มีความซับซ้อนมากขึ้นในแง่ของจำนวนโอเปอเรชันโค้ด
โค้ดนี้สามารถนำไปเปรียบเทียบกับโค้ดที่เกี่ยวข้องในบทความเกี่ยวกับไบต์โค้ดของภาษาจาวาได้ เช่นกัน
static void Main ( string [ ] args ) { for ( int i = 2 ; i < 1000 ; i ++ ) { for ( int j = 2 ; j < i ; j ++ ) { if ( i % j == 0 ) goto outer ; } Console.WriteLine ( i ) ; outer :; } }ในไวยากรณ์แอสเซมเบลอร์ CIL จะมีลักษณะดังนี้:
. เมธอดprivate hidebysig static void Main ( string [] args ) cil managed { . entrypoint . maxstack 2 . locals init ( int32 V_0 , int32 V_1 )แอลดีซีi4 .2 stloc .0 br . s IL_001f IL_0004 : ldc i4 .2 stloc .1 br . s IL_0011 IL_0008 : ldloc .0 ldloc .1 rem brfalse s IL_001b ldloc .1 ldc i4 .1 เพิ่มstloc .1 IL_0011 : ldloc .1 ldloc .0 blt s IL_0008 ldloc .0 การเรียกระบบเป็นโมฆะ[ mscorlib ] คอนโซล:: WriteLine ( int32 ) IL_001b : ldloc .0 ldc i4 .1 เพิ่มstloc .0 IL_001f : ldloc .0 ldc i4 0x3e8 blt . s IL_0004 ยกเลิก}นี่เป็นเพียงภาพจำลองลักษณะของ CIL ใน ระดับ เครื่องเสมือน (VM) เมื่อคอมไพล์แล้ว เมธอดจะถูกเก็บไว้ในตาราง และคำสั่งจะถูกเก็บไว้เป็นไบต์ภายในแอสเซมบลี ซึ่งเป็นไฟล์ปฏิบัติการแบบพกพา (PE)
รุ่น
โค้ดแอสเซมบลีและคำสั่ง CIL ถูกสร้างขึ้นโดยคอมไพเลอร์หรือยูทิลิตี้ที่เรียกว่าIL Assembler ( ILAssembly ) ซึ่งมาพร้อมกับสภาพแวดล้อมการทำงาน
นอกจากนี้ โค้ด CIL ที่ประกอบเสร็จแล้วยังสามารถแยกกลับเป็นโค้ดได้อีกครั้งโดยใช้IL Disassembler (ILDASM) ยังมีเครื่องมืออื่นๆ เช่น.NET Reflectorที่สามารถถอดรหัส CIL เป็นภาษาโปรแกรมระดับสูง (เช่น C# หรือVisual Basic ) ได้อีกด้วย ทำให้ CIL เป็นเป้าหมายที่ง่ายมากสำหรับการวิศวกรรมย้อนกลับ คุณสมบัตินี้พบได้ในไบต์โค้ดของ Javaเช่นกัน อย่างไรก็ตาม มีเครื่องมือที่สามารถทำให้โค้ดอ่านยาก แต่ยังคงสามารถทำงาน ได้
การประหารชีวิต
การรวบรวมแบบทันเวลาพอดี
การคอมไพล์แบบทันเวลา ( Just-in-Time Compilationหรือ JIT) คือการแปลงไบต์โค้ดให้เป็นโค้ดที่ซีพียูสามารถเรียกใช้งานได้ทันที การแปลงจะเกิดขึ้นทีละน้อยในระหว่างการทำงานของโปรแกรม การคอมไพล์แบบ JIT ให้การปรับแต่งที่เหมาะสมกับสภาพแวดล้อมและการตรวจสอบความถูกต้องของแอสเซมบลี เพื่อให้บรรลุเป้าหมายนี้ คอมไพเลอร์ JIT จะตรวจสอบเมตาเดตาของแอสเซมบลีเพื่อหาการเข้าถึงที่ไม่ถูกต้องและจัดการกับการละเมิดอย่างเหมาะสม
การรวบรวมล่วงหน้า
สภาพแวดล้อมการทำงานที่เข้ากันได้ กับ CLIยังมีตัวเลือกในการทำการคอมไพล์ล่วงหน้า ( Ahead-of-time compilationหรือ AOT) ของแอสเซมบลีเพื่อให้ทำงานได้เร็วขึ้นโดยการกำจัดกระบวนการ JIT ในระหว่างการรันไทม์
ใน.NET Frameworkมีเครื่องมือพิเศษที่เรียกว่าNative Image Generator (NGEN) ซึ่งทำหน้าที่ AOT (Automatic Object-Oriented) อีกแนวทางหนึ่งสำหรับ AOT คือCoreRTซึ่งช่วยให้สามารถคอมไพล์โค้ด .NET Core ไปเป็นไฟล์ปฏิบัติการเดียวโดยไม่ต้องพึ่งพา Runtime นอกจาก นี้ Monoยังรองรับการคอมไพล์แบบ AOT ด้วย
คำสั่งเกี่ยวกับตัวชี้ - C++/CLI
ความแตกต่างที่เห็นได้ชัดจากไบต์โค้ดของ Java คือ CIL มาพร้อมกับ คำสั่ง ldind`init`, stind` ldlocainit` และคำสั่งเรียก (call) จำนวนมาก ซึ่งเพียงพอสำหรับการจัดการตัวชี้ข้อมูล/ฟังก์ชันที่จำเป็นในการคอมไพล์โค้ด C/C++ ให้เป็น CIL
คลาสA { public : virtual void __stdcall meth () {} }; void test_pointer_operations ( int param ) { int k = 0 ; int * ptr = & k ; * ptr = 1 ; ptr = & param ; * ptr = 2 ; A a ; A * ptra = &a } a ; ptra -> meth (); }โค้ดที่เกี่ยวข้องใน CIL สามารถแสดงได้ดังนี้:
. เมธอดassembly static void modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvCdecl ) test_pointer_operations ( int32 param ) cil managed { . vtentry 1 : 1 // ขนาดโค้ด 44 (0x2c) . maxstack 2 . locals ([ 0 ] int32 * ptr , [ 1 ] valuetype A * V_1 , [ 2 ] valuetype A * a , [ 3 ] int32 k ) // k = 0; IL_0000 : ldc . i4 .0 IL_0001 : stloc .3 // ptr = &k; IL_0002 : ldloca . s k // คำสั่งโหลดที่อยู่ของ local IL_0004 : stloc .0 // *ptr = 1; IL_0005 : ldloc .0 IL_0006 : ldc i4 .1 IL_0007 : stind i4 // คำสั่งทางอ้อม// ptr = ¶m IL_0008 : ldarga s param // คำแนะนำที่อยู่ของพารามิเตอร์โหลดIL_000a : stloc .0 // *ptr = 2 IL_000b : ldloc .0 IL_000c : ldc i4 .2 IL_000d : สตินi4 // a = A ใหม่; IL_000e : ldloca s a IL_0010 : เรียกvaluetype A * modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvThiscall ) ' A .{ ctor } ' ( valuetype A * modopt ([ mscorlib ]ระบบ. รันไทม์ บริการคอมไพเลอร์IsConst ) modopt ([ mscorlib ] ระบบ. Runtime . CompilerServices . IsConst )) IL_0015 : pop // ptra = &a; IL_0016 : ldloca s a IL_0018 : stloc .1 // ptra->meth(); IL_0019 : ldloc .1 IL_001a : ซ้ำIL_001b : ldind i4 // อ่าน VMT สำหรับการโทรเสมือนIL_001c : ldind i4 IL_001d : calli unmanaged stdcall void modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvStdcall )( native int ) IL_0022 : ret } // end of method 'Global Functions'::test_pointer_operationsดูเพิ่มเติม
อ่านเพิ่มเติม
- บ็อค, เจสัน (2002). การเขียนโปรแกรม CIL: เบื้องหลัง .NET . สำนักพิมพ์ A. ISBN 978-1590590416.
ลิงก์ภายนอก
- โครงสร้างพื้นฐานภาษาทั่วไป (มาตรฐาน ECMA-335)
- “มาตรฐาน ECMA C# และ Common Language Infrastructure” บนเว็บไซต์ Visual Studio
- โปรแกรม "สวัสดีโลก" ใน CIL
- ความเร็ว: NGen เร่งประสิทธิภาพของคุณด้วยคุณสมบัติใหม่ที่ทรงพลัง -- นิตยสาร MSDN เมษายน 2548
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ ภาษากลางทั่วไป
ภาษาตัวกลางทั่วไป ( CIL ) ซึ่งเดิมเรียกว่า ภาษาตัวกลางของ Microsoft ( MSIL ) หรือ ภาษาตัวกลาง ( IL ) [ 1 ] คือชุดคำสั่งไบนารีของ ภาษาตัวกลาง ที่กำหนดไว้ในข้อกำหนด...
ข้อมูลทั่วไป
ระหว่างการคอม ไพล์ภาษาการเขียนโปรแกรม CLI โค้ด ต้นฉบับ จะถูกแปลงเป็นโค้ด CIL แทนที่จะเป็น โค้ดออบเจ็กต์ เฉพาะแพลตฟอร์มหรือโปรเซสเซอร์ CIL เป็น ชุดคำสั่งที่ไม่ขึ้นกับ CPU และแพลตฟอร์ม ซึ่งสามารถดำเนินการได้ในสภาพแวดล้อมใดๆ ที่รองรับโครงสร้างพื้นฐานภาษาทั่วไป...
คำแนะนำ
ไบต์โค้ด CIL มี คำสั่ง สำหรับงานกลุ่มต่างๆ ดังต่อไปนี้:
แบบจำลองการคำนวณ
ภาษา Common Intermediate Language (CLI) เป็นภาษาเชิงวัตถุและ ใช้สแต็ก ซึ่งหมายความว่าพารามิเตอร์คำสั่งและผลลัพธ์จะถูกเก็บไว้ในสแต็กเดียว แทนที่จะเก็บไว้ในรีจิสเตอร์หลายตัวหรือตำแหน่งหน่วยความจำอื่นๆ เหมือนใน ภาษาโปรแกรม ส่วน ใหญ่