Site icon TAPIT

Trình biên dịch và quá trình biên dịch chương trình C

Chúng ta sử dụng ngôn ngữ bậc cao để viết chương trình, máy tính lại sử dụng ngôn ngữ máy dạng nhị phân.Vậy, làm thế nào để máy tính có thể hiểu và thực thi chương trình của chúng ta? => Chính nhờ vào quá trình biên dịch – Compilation process.

Quá trình này đóng vai trò chuyển đổi ngôn ngữ bậc cao thành ngôn ngữ máy mà vi xử lý có thể đọc và thực thi.

Tại bài viết này, mình sẽ giới thiệu chi tiết về trình biên dịch (Compiler) và quá trình biên dịch với bốn giai đoạn, hướng dẫn thực hành chạy các lệnh để các bạn hiểu rõ hơn về cơ chế hoạt động của quá trình này.

 1. Trình biên dịch

1.1. Giới thiệu về trình biên dịch

=> Biên dịch là quá trình chuyển đổi các dòng lệnh được viết bằng ngôn ngữ bậc cao (C/C++, Python, JavaScript,…) thành ngôn ngữ máy để máy tính có thể hiểu và thực thi chương trình.

=> Sử dụng trình biên dịch để thực hiện quá trình biên dịch một chương trình. Trình biên dịch rất phổ biến được sử dụng để biên dịch chương trình C là GCC (GNU Compiler Collection).

Hình 1. Logo GCC và hệ điều hành GNU

=> Trên website chính thức của gcc-gnu, có định nghĩa sau về GCC:

The GNU Compiler Collection includes front ends for C, C++, Objective-C, Fortran, Ada, Go, D, Modula-2, and COBOL as well as libraries for these languages (libstdc++,…). GCC was originally written as the compiler for the GNU operating system. The GNU system was developed to be 100% free software, free in the sense that it respects the user’s freedom.(Tham khảo tại đây)

 

Chúng ta cùng phân tích chi tiết về định nghĩa trên:

1/ “The GNU Compiler Collection includes front ends for C, C++, Objective-C, Fortran, Ada, Go, D, Modula-2, and COBOL as well as libraries for these languages (libstdc++,…). GCC was originally written as the compiler for the GNU operating system.

→ GCC là viết tắt của “GNU Compiler Collection” – tập hợp các trình biên dịch trên hệ điều hành GNU.

→ front end: là phần phân tích và xử lý mã nguồn đầu vào, chịu trách nhiệm phân tích cú pháp và ngữ nghĩa.

→ libraries: GCC còn cung cấp các thư viện hệ thống cho các ngôn ngữ. Một số thư viện hệ thống như: stdio.h, string.h, stdlib.h (ngôn ngữ C);  iostream, vector, queue (ngôn ngữ C++),…

 

2/ “The GNU system was developed to be 100% free software, free in the sense that it respects the user’s freedom.

GCC được phát triển dựa trên triết lý mã nguồn mở và quyền tự do người dùng. Nhờ đó các nhà phát triển có thể hiệu chỉnh để tương thích với các hệ điều hành và phần cứng khác nhau như Linux, MacOS, Window. GCC trên các hệ điều hành:

1.2. Trình biên dịch chéo

Hình 2. Trình biên dịch chéo biên dịch mã nguồn trên chip Intel tạo file thực thi trên chip ARM

Một ví dụ thực tế, khi bạn lập trình cho vi điều khiển, bạn viết mã chương trình trên máy tính Window với chip Intel (Machine A), chương trình được biên dịch với mục tiêu chạy trên vi điều khiển chip ARM (Machine B). Vậy thì các trình biên dịch mà chúng ta đã đề cập trên không thể hỗ trợ chúng ta được việc này. Khi đó chúng ta cần sử dụng đến Trình biên dịch chéo, công cụ này sẽ có khả năng biên dịch mã nguồn trên máy tính Intel, rồi tạo file thực thi có thể được nạp và chạy trên chip ARM. Các bạn xem minh hoạ tại hình 2.

Vậy, trình biên dịch chéo là một loại trình biên dịch có thể tạo mã thực thi cho một nền tảng khác với nền tảng mà trình biên dịch đang chạy. Như ví dụ trên, nền tảng bạn đang chạy là Windows/Intel, nền tảng khác chính là ARM.

Một số IDE hỗ trợ các trình biên dịch chéo được sử dụng phổ biến để biên dịch cho các dòng vi điều khiển như:

2. Quá trình biên dịch một chương trình C

2.1. Tổng quan

Quá trình biên dịch trong C được chia thành nhiều giai đoạn với các nhiệm vụ và mục tiêu cụ thể. Các giai đoạn được thực hiện theo trình tự hiệu quả, kiểm tra cú pháp và tạo ra đầu ra có thể thực thi.

Hình 3. Bốn giai đoạn của quá trình biên dịch

Quá trình biên dịch được chia làm 4 giai đoạn chính:

2.2. Cách biên dịch và thực thi chương trình C

Mình sẽ hướng dẫn các bạn các bước để biên dịch và thực thi một chương trình C đơn giản.

1/ Tạo source file

Tạo file source với tên tapit.c với nội dung dưới đây.

2/ Biên dịch chương trình

Mở cửa sổ Command prompt (hoặc Terminal) trỏ đến thư mục chứa file tapit.c và chạy command sau:

Các giai đoạn của quá trình dịch sẽ được triển khai và file thực thi sẽ được sinh ra: tapit.exe (Windown) và tapit (Linux/MacOS)

3/ Thực thi chương trình

Chạy command sau:

Chúng ta thu được kết quả tại hình 4 dưới đây:

Hình 4. Biên dịch và thực thi chương trình bằng command

2.3. Phân tích các giai đoạn của quá trình biên dịch

1/ Preprocessor – Tiền xử lý

Giai đoạn này sẽ thực hiện việc nhận mã nguồn (source code, file chương trình có phần mở rộng .c) và mở rộng mã nguồn với các bước:

Trong các thành phần trên, chỉ thị tiền xử lý thường được sử dụng phổ biến hơn các thành phần còn lại. Ví dụ như #include, #define, #undef, #if, #else,… 

Note: Command thực hiện giai đoạn Preprocessor (.c -> .i)

gcc -E <filename>.c -o <filename>.i

Chúng ta thu được kết quả tại hình 5 dưới đây:

Hình 5. Thực hiện giai đoạn Preprocessor với command

2/ Compiler – dịch ngôn ngữ bậc cao sang Assembly.

Tại giai đoạn này, trình biên dịch sẽ:

Note: Command thực hiện giai đoạn Compiler (.i -> .s)

gcc -S <filename>.i -o <filename>.s

Chúng ta thu được kết quả tại hình 6 dưới đây:

Hình 6. Thực hiện giai đoạn Compiler với command

3/ Assembler – dịch Assembly sang ngôn ngữ máy.

Note: Command thực hiện giai đoạn Assembler (.i -> .o)

as <filename>.s -o <filename>.o

Chúng ta thu được kết quả tại hình 7 dưới đây:

Hình 7. Thực hiện giai đoạn Assembler với command

File sinh ra là file object dạng mã máy nhị phân, các bạn có thể sử dụng Git bash trên Window hoặc Terminal trên Linux/MacOS với command sau:

xxd tapit.o

Do sự khác nhau về kiến trúc hệ thống và các quy ước về file object nhị phân, nên khi đọc hai file, ta thấy có sự khác nhau là điều bình thường.

Hình 8. Đọc file object trên Window và MacOS

4/ Linker.

Note: Giai đoạn Linker được thực hiện khi gọi command sinh file thực thi từ file .c

gcc <filename>.c -o <filename>.exe

Chúng ta thu được kết quả tại hình 9 dưới đây:

Hình 9. Biên dịch chương trình bằng command

Qua bài viết này, mình đã giới thiệu đến các bạn về trình biên dịch, bốn giai đoạn của quá trình biên dịch. Thực hành với các lệnh thực hiện các giai đoạn thì việc hiểu được quá trình biên dịch thật đơn giản. Các bạn có thể thực hành nâng cao hơn với việc sử dụng nhiều hơn các comment, macro, optimization, liên kết nhiều file source,…

Video hướng dẫn liên kết 2 file source bằng command, các bạn có thể tham khảo nhé!

Chúc các bạn thành công!

N.T.Nhien

Tìm hiểu thêm:
Fanpage TAPIT: TAPIT – AIoT Learning