MSIL cơ bản – Part 1/6: Giới thiệu về MSIL

Intermediate Language (IL) hay còn được biết đến với tên Microsoft Intermediate Language (MSIL) và hiện tại được gọi là Common Intermediate Language (CIL), là một ngôn ngữ trung gian được tạo ra sau quá trình biên dịch từ các loại ngôn ngữ khác trong .Net như C#, C++, VB.Net, J#,… Trong bài này bạn sẽ được giới thiệu để viết chương trình đầu tiên bằng CIL và các đặc điểm chung của CIL.  (Tôi sẽ dùng tên MSIL trong tiêu đề vì đây là tên gọi phổ biến và dễ phân biệt nhất khi nói về ngôn ngữ này)

Cần chuẩn bị gì để bắt đầu?

Để bắt đầu với IL, bạn chỉ cần 3 công cụ là ildasm.exe, ilasm.exe và một text editor đơn giản như notepad hay notepad++. Các công cụ này đã được tích hợp sẵn khi bạn cài đặt Visual Studio. Ngoài ra kiến thức về ít nhất một ngôn ngữ lập trình .Net là một điều kiện không thể thiếu.

Chương trình đầu tiên: Hello World

Trong bài về cách sử dụng ildasm.exe và ilasm.exe, bạn đã làm quen với hai công cụ này cũng như ít nhiều thấy được đoạn CIL của chương trình in dòng chữ “Hello World!” ra màn hình Console.

Một điểm bạn cần biết trước khi bắt đầu là CIL là ngôn ngữ phân biệt hoa thường. Có thể bạn không cần phải gõ những đoạn mã CIL khó hiểu nhưng cũng cần phải đọc và sửa lỗi khi cần thiết. Bây giờ bạn hãy mở notepad và gõ đoạn mã sau vào:

.assembly extern mscorlib {}
.assembly HelloWorld {}

.method static void main()
{
	.entrypoint
	.maxstack 1

	ldstr "Hello world!"
	call void [mscorlib]System.Console::WriteLine(string)
	ret
}

Sau đó lưu lại với tên HelloWorld.il (bạn có thể lưu với tên khác nhưng nên giữ phần mở rộng .il). Mở Command Prompt để biên dịch chương trình bằng ilasm.exe sau đó thực thi tập tin .exe vừa được tạo ra. Bạn sẽ có kết quả sau:

HelloWorld (Intermediate Language)

Với kiến thức lập trình .Net sẵn có, bạn có thể hiểu được phần nào chương trình đơn giản trên. Điểm đầu tiên ta cần chú ý là các chỉ thị (directive ) trong CIL. Trong đoạn mã trên, bạn chỉ sử dụng một vài chỉ thị cơ bản mà chương trình CIL nào cũng cần phải có. Đặc điểm để nhận biết là các chỉ thị được bắt đầu bằng dấu chấm “.”. Chúng ta hãy phân tích các dòng chỉ thị để biết được công dụng của chúng.

Đầu tiên là chỉ thị khai báo việc sử dụng một assembly bên ngoài:

.assembly extern mscorlib {}

Chỉ thị này cho biết rằng chương trình HelloWorld của chúng ta sẽ sử dụng các thành phần trong thư viện mscorlib (extern: viết tắt của external). Thư viện mscorlib.dll là assembly chính của các lớp trong .Net framework, và dĩ nhiên nó chứa phương thức System.Console::WriteLine(string) mà bạn cần sử dụng trong phương thức main().

Dòng tiếp theo:

.assembly HelloWorld {}

Chỉ ra rằng chúng ta sẽ tạo ra một assembly tên là HelloWorld. Nếu không có chỉ thị này, việc biên dịch chương trình bằng ilasm.exe vẫn thành công tuy nhiên ta không thể thực thi chương trình được.

Chỉ thị .method dùng để khai báo một phương thức, cụ thể đây là phương thức chính của chương trình, tức là nơi chương trình bắt đầu. Nó phải là một phương thức tĩnh (static) và từ khóa void được sử dụng là kiểu trả về của phương thức.

.method static void main()

Chỉ thị .entrypoint: một dấu hiệu để nhận biết rằng phương thức chứa chỉ thị này (Main()) là phương thức bắt đầu của chương trình.  Nếu quên đặt chỉ thị này vào phương thức chính, bạn sẽ gặp lỗi khi biên dịch:

Error: No entry point declared for executable

Chỉ thị .maxstack chỉ ra độ lớn của stack cần dùng. Tức là số lượng phần tử lớn nhất mà stack có thể lưu trữ tại một thời điểm. Độ lớn này không tính bằng số byte mà dựa vào số slot (mỗi slot chứa một phần tử), giá trị mặc định của nó là 8. Trong chương trình trên, vì chỉ cần nạp chuỗi “Hello World!” vào nên ta chỉ cần đặt .maxstack là 1.

Như vậy bạn đã hiểu công dụng của các chỉ thị được sử dụng ở trên. Phần còn lại là các lệnh CIL mà ta sử dụng để in ra màn hình dòng chữ “Hello World!”.

ldstr “Hello world!”

call void [mscorlib]System.Console::WriteLine(string)

ret

Các lệnh trên có công dụng như sau:

  • ldstr (viết tắt của LoadString), như tên gọi của nó, thực hiện việc thêm chuỗi “Hello World” vào đầu stack (push)
  • call : thực hiện việc gọi phương thức WriteLine() từ thư viện mscorlib. Lệnh được gọi phải ghi đầy đủ từ kiểu trả về (void) đến assembly, namespace chứa nó. Khi được gọi, phương thức WriteLine() sẽ lấy dữ liệu từ stack để hiển thị ra màn hình.
  • ret : (return) trả lại quyền điều khiển cho phương thức Main().

Một vài đặc điểm của CIL

–       Qua ví dụ trên bạn cũng thấy được phần nào phương pháp hoạt động của các lệnh CIL. Các dữ liệu đều được thêm vào stack trước khi sử dụng và các phương thức được gọi sẽ lấy dữ liệu từ đỉnh stack.  Sau khi một phương thức được thực hiện, giá trị trả về của nó lại được trả về stack. Vì thế CIL còn được gọi là kiểu ngôn ngữ stack-based.

–       Các lệnh trong CIL chủ yếu thuộc hai nhóm push và pop, tức là chỉ đưa và lấy dữ liệu ra mỗi khi sử dụng (khi một lệnh cần kiểm tra hoặc lấy dữ liệu trong stack, dữ liệu đó sẽ bị đưa ra khỏi stack).

–       Bạn có thể dùng stack lưu mọi loại dữ liệu mà CIL hỗ trợ, từ kiểu giá trị (value type) đến tham chiếu (reference type). Đối với value type, nó được lưu trữ trực tiếp trên stack, còn đối tượng reference type sẽ được lưu trên heap và stack chỉ chứa tham chiếu đến đối tượng đó.

–       Về phương thức làm entry point, bạn không cần thiết phải giữ cố định tên gọi là main() mà có thể sử dụng bất kì tên nào miễn là đúng quy tắc. Trình biên dịch sẽ xác định dựa vào chỉ thị .entrypoint chứ không dựa vào tên của phương thức để xác định. Tuy nhiên như một quy ước, bạn nên đặt là main() để thống nhất.

–       Các chỉ thị trong CIL không nhất thiết phải đặt ở một vị trí cố định. Ví dụ như chỉ thị .entrypoint, bạn có thể đặt nó bất kì ở dòng nào miễn là vẫn ở trong phương thức chính, thậm chí ngay cả sau lệnh ret. Tuy nhiên một vài trường hợp có thể bị trình biên dịch cảnh báo, vì thế cũng như một quy ước, bạn nên đặt cố định một vị trí để giúp mã nguồn rõ ràng và tránh những lỗi đáng tiếc có thể xảy ra.

–       Trong CIL sử dụng các lệnh chứ không có các phương thức để sử dụng. Các phương thức mà bạn có thể dùng đều lấy từ thư viện bên ngoài.

–       Một điểm khác nữa là bạn có thể nhận thấy sự tương đồng giữa CIL và hợp ngữ (assembly), tuy nhiên CIL lại hỗ trợ lập trình ở mức cao hơn. Cụ thể nó cho phép gọi các phương thức từ các thư viện ngoài như WriteLine(), vẫn giữ nguyên cấu trúc OOP của chương trình cũng như các khái niệm đặc trưng của OOP như static, class, struct,…

Chú thích trong CIL

Khi viết mã CIL, bạn có thể sử dụng các chú thích // và /*…*/ như trong C++. Ví dụ bạn có thể thấy tôi chú thích chương trình Hello World trên bằng cả hai cách:

.assembly extern mscorlib {}
.assembly HelloWorld {}

.method static void main()cil managed
{
	.entrypoint
	.maxstack 1
	// load string onto stack
	ldstr /* "Hello someone" */ "Hello world!"
	call void [mscorlib]System.Console::WriteLine(string)
	ret
}

Học qua các ví dụ

Một cách hay để tiếp tục, bạn có thể viết một vài chương trình đơn giản bằng các ngôn ngữ .Net bậc cao như C#, C++, VB.Net,… rồi dùng ildasm.exe để phân tích chúng dưới dạng mã CIL. Với cách học này, bạn có thể nhanh chóng hiểu và làm việc được với CIL, cùng với sự trợ giúp của bảng tra cứu các lệnh CIL tại đây.

Ví dụ nhờ bảng này ta có thể tra được thông tin của các lệnh được sử dụng trong ví dụ HelloWorld trên:

Operation  Code Instruction Description
0×28 call <method> Call method described by method.
0×72 ldstr <string> Push a string object for the literal string.
0x2A ret Return from method, possibly with a value.

Bài viết liên quan:

MSIL – Part 1: Giới thiệu về MSIL
MSIL – Part 2: Biến cục bộ
MSIL – Part 3: Rẽ nhánh và vòng lặp
MSIL – Part 4: Lập trình hướng đối tượng
MSIL – Part 5: Conversion, casting và boxing
MSIL – Part 6: Sử dụng mảng

https://yinyangit.wordpress.com

Advertisements

One thought on “MSIL cơ bản – Part 1/6: Giới thiệu về MSIL

  1. Pingback: A stack-based programming language: Cat - Quan Vu

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s