Làm thế nào một chương trình ở ngôn ngữ cấp cao được dịch sang ngôn ngữ máy bằng trình thông dịch

Hầu hết sau khi chúng ta sau khi viết xong một chương trình và chạy chúng bằng trình biên dịch, ta chỉ quan tâm đến việc chương trình của mình đúng hay sai chứ chẳng mấy khi quan tâm đến việc chương trình đó được biên dịch như thế nào?

Biên dịch chương trình là gì?

Quy trình dịch là quá trình chuyển đổi từ ngôn ngữ bậc cao sang ngôn ngữ đích [ngôn ngữ máy] để máy tính có thể hiểu và thực thi. Ngôn ngữ lập trình C++ là một ngôn ngữ dạng biên dịch. Chương trình được viết bằng C++ muốn chạy được trên máy tính phải trải qua một quá trình biên dịch để chuyển đổi từ dạng mã nguồn sang chương trình dạng mã thực thi. Quá trình được chia ra làm 4 giai đoạn chính:

1. Preprocessing [tiền xử lý]

Bộ tiền xử lý có nhiệm vụ thực hiện:

  • Nhận mã nguồn
  • Xóa bỏ tất cả chú thích, comments của chương trình
  • Chỉ thị tiền xử lý [bắt đầu bằng #] cũng được xử lý

Chúng ta có thể bắt lỗi ngay ở giai đoạn này với việc sử dụng một cách hợp lý các chỉ thị #if  #error. Bằng cách sử dụng option -E của trình biên dịch như bên dưới, chúng ta có thể dừng quá trình biên dịch ngay ở giai đoạn tiền xử lý nếu có lỗi ở giai đoạn này.

Ví dụ: chỉ thị #include cho phép ghép thêm mã chương trình của một tệp tiêu để vào mã nguồn cần dịch. Các hằng số được định nghĩa bằng #define sẽ được thay thế bằng giá trị cụ thể tại mỗi nơi sử dụng trong chương trình.

Sau khi thực hiện tiền xử lý

Ta có thể thấy các hằng số được đinh nghĩa bằng #define đã được thay thế bằng các giá trị cụ thể

2. Compilation [biên dịch]

Bước biên dịch được thực hiện trên mỗi output của bộ tiền xử lý. Trình biên dịch phân tích mã nguồn C++ thuần túy [bây giờ không có bất kỳ chỉ thị tiền xử lý nào] và chuyển đổi nó assembly code. Ở giai đoạn này, trình biên dịch sẽ bắt các lỗi về kiểu dữ liệu, phân tích [syntax] cú pháp đồng thời có thể thực hiện tối ưu tự động source code để chương trình hoạt động hiệu quả hơn. Nếu có lỗi xảy ra trình biên dịch sẽ thông báo và chúng ta phải sửa lại code để xử lý các lỗi đó và thực hiện biên dịch lại.

Sau khi biên dịch ngon lành ở bước này, compiler sẽ gọi đến một cái back-end bên dưới gọi là assembler để convert tiếp assembly code thành các object code files chứa machine code [mã máy].

Quá trình này sẽ biên dịch các tệp tin .c/.cpp sang tệp tin object .s

3. Assembling

Ở bước này thì assembler sẽ chuyển đổi các assembly code trong các assembler files thành mã máy [machine code – là mã mà CPU có thể hiểu được] trong các object code files. Lưu ý assembler phụ thuộc vào kiến trúc của CPU [x86, PowerPC, ARM,…] nên các kiến trúc CPU khác nhau thì sẽ có các assembler khác nhau. Trên hệ thống UNIX, các object code files có hậu tố .o [.OBJ trên Windows]. Các object code files chứa code đã được biên dịch [ở dạng nhị phân] của các symbols [có hiểu đơn giản symbols ở đây là các hàm, các biến] định nghĩa trong file source đầu vào. Symbols trong các object code files được tham chiếu đến bằng tên.

Nói dễ hiểu thì ở giai đoạn này sẽ dịch chương trình thành mã máy 0, 1 và sinh ra tệp mã máy .o

4. Linker [Trình liên kết]

Giai đoạn này sẽ tạo thành chương trình đích duy nhất của quá trình biên dịch từ các object code files  assembler đã tạo ra ở bước trước đó. Đầu ra này có thể là thư viện shared [or dynamic] library hoặc file chaỵ [executable file].

Nó liên kết tất cả các object code files bằng cách thay thế các tham chiếu đến các symbols bằng các địa chỉ chính xác. Mỗi symbol này có thể được định nghĩa trong các object code files khác hoặc trong các thư viện. Nếu chúng được định nghĩa trong các thư viện khác với thư viện chuẩn, bạn cần phải khai báo rõ với linker về chúng [điều này được thực hiện thông qua các config build].

Ở giai đoạn này, các lỗi phổ biến nhất là thiếu định nghĩa hoặc định nghĩa trùng lặp.

  • Thiếu định nghĩa : Điều này có nghĩa là các định nghĩa không tồn tại [các class, các hàm không được implement] hoặc object code files hoặc thư viện nơi chúng cư trú không được cung cấp cho trình linker biết.
  • Trùng lặp: cùng một symbol được định nghĩa trong hai hoặc nhiều object code files hoặc thư viện khác nhau.
  • Chương trình chính không có hàm main[].

Tạm kết

Hi vọng qua bài viết bạn có thể hiểu được quá trình biên dịch diễn ra như thế nào. Khi có thể hiểu được quá trình biên dịch ta có thể dễ dàng biết lỗi từ bước nào để fix.

Nguồn tham khảo: cppdeveloper.com

Chương trình dịch là chương trình Chuyển đổi chương trình viết bằng hợp ngữ hoặc ngôn ngữ lập trình bậc cao sang ngôn ngữ máy

Trắc nghiệm: Chương trình dịch là chương trình:

A. Chuyển đổi ngôn ngữ máy sang ngôn ngữ lập trình bậc cao

B. Chuyển đổi chương trình viết bằng hợp ngữ hoặc ngôn ngữ lập trình bậc cao sang ngôn ngữ máy

C. Chuyển đổi hợp ngữ sang ngôn ngữ lập trình bậc cao

D. Chuyển đổi ngôn ngữ máy sang hợp ngữ

Đáp án đúng: B. Chuyển đổi chương trình viết bằng hợp ngữ hoặc ngôn ngữ lập trình bậc cao sang ngôn ngữ máy

Kiến thức mở rộng

– Chương trình máy tính được hiểu là một chuỗi những câu lệnh của máy tính, đó là tập hợp những thông tin hướng dẫn để người thực hiện có thể tiến hành thực hiện được những nhiệm vụ của một máy tính.

– Đối với các máy tính, đòi hỏi phải có những chương trình để hoạt động được theo ý muốn của con người, dựa vào chương trình máy tính mà con người có thể thực hiện được các lệnh máy tính, các lệnh này sẽ nằm ở phần trung tâm xử lý.

– Đối với mỗi chương trình máy tính thì sẽ được viết bởi một ngôn ngữ lập trình khác nhau.

Ví dụ:

– Trình duyệt web Mozilla, Safari của hệ điều hành IOS. Những chương trình này sẽ giúp cho người dùng có thể truy cập vào internet.

– Chương trình máy tính quản lý hệ văn phòng

a. Khái niệm

– Chương trình dịch [compiler] còn được gọi là trình biên dịch. Nhiệm vụ của chương trình dịch là dịch một chuỗi các câu lệnh được viết bằng một ngôn ngữ lập trình cụ thể [hay còn được gọi là ngôn ngữ nguồn hoặc mã nguồn] thành một chương trình mới nhưng dưới dạng một ngôn ngữ máy tính [hay còn gọi là ngôn ngữ đích. Thông thường, ngôn ngữ đích là ngôn ngữ ở cấp thấp hơn được dùng để cho máy tính hiểu được các câu lệnh. Chương trình mới được được chương trình dịch tạo ra này còn được gọi là mã đối tượng.

b. Đặc trưng của chương trình dịch

– Một chương trình dịch tốt cần có các đặc trưng sau:

+ Tính toàn vẹn: kết quả ở ngôn ngữ đích phải hoàn toàn tương đương với đầu vào viết ở ngôn ngữ nguồn

+ Tính hiệu quả: chương trình dịch sử dụng không quá nhiều bộ nhớ và công suất tính toán, kết quả ở ngôn ngữ đích là đủ tốt

 + Tính trong suốt: chương trình dịch phải rõ ràng về kết quả sau từ bước thực hiện, giúp người dùng có thể hiệu chỉnh và sửa lỗi nếu có sau từng bước thực hiện

 + Tính chịu lỗi: chương trình có thể chấp nhận một số lỗi của đầu vào và đưa ra các gợi ý xử lý phù hợp. Chương trình dừng ở ngay lỗi đầu tiên không thể coi là tốt

c. Phân loại chương trình dịch

Có hai loại chương trình dịch là biên dịch và thông dịch:

– Trình biên dịch [compiler]: nhận toàn bộ nguồn rồi dịch sang đích một lượt

+ Tĩnh [statically]: mã sinh ra chạy trực tiếp ngay

+ Động [dynamically]: mã sinh ra cần thao tác tái định vị rồi mới có thể chạy được

– Trình thông dịch [interpreter]: nhận mã nguồn từng phần, nhận được phần nào dịch [và thực thi] phần đó

 Nhận xét:

– Compiler hoạt động giống như dịch giả.

– Interpreter hoạt động giống như người phiên dịch [các cuộc giao tiếp].

– Hiện nay: ranh giới giữa compiler và interpreter ngày càng mờ dần.

– Một số ngôn ngữ lập trình kết hợp cả compiler và interpreter, chẳng hạn như java. Mã java được biên dịch thành mã bytecode. Máy ảo chạy mã bytecode ở dạng thông dịch.

– Một số sử dụng compiler và just-in-time compiler.

– Mã C# được biên dịch thành mã IL. Mã IL được biên dịch thành mã máy trong lần chạy đầu.

d. Các giai đoạn của chương trình dịch

– Ngoài ra, chương trình dịch trải qua hai giai đoạn: phân tích và tổng hợp. Giai đoạn phân tích nhầm phân tích chương trình nguồn về từ vựng và cú pháp. Giai đoạn tổng hợp nhằm tạo ra chương trình đích gồm ba bước, đó là:

+ Sinh mã trung gian [chuyển chương trình nguồn về chương trình trung gian];

+ Tối ưu mã [chỉnh sửa, tối ưu chương trình trung gian];

+ Sinh mã [tạo chương trình đích từ chương trinh trung gian đã tối ưu].

Video liên quan

Chủ Đề