
Danh sách Hợp ngữ Motorola MC6800, cho thấy hợp ngữ thời đầu và hình thức kết hợp | |
| Mẫu hình | Bắt buộc, Phi cấu trúc |
|---|---|
| Xuất hiện lần đầu | 1949; 76 năm trước |
Trong lĩnh vực lập trình máy tính, Hợp ngữ (hay còn gọi là assembly) thường được rút gọn là asm. Đây là một ngôn ngữ lập trình cấp thấp, có sự liên kết chặt chẽ với các lệnh máy của kiến trúc. Vì hợp ngữ gắn bó mật thiết với mã máy, mỗi trình biên dịch sẽ có một hợp ngữ riêng biệt, được thiết kế để làm việc với một kiến trúc máy tính cụ thể. Hợp ngữ còn được gọi là mã máy biểu tượng (symbolic machine code).
Mã hợp ngữ được chuyển thành mã máy thực thi nhờ một chương trình gọi là assembler. Quá trình này gọi là assembling. Thông thường, mỗi lệnh hợp ngữ sẽ tương ứng với một lệnh máy (1:1), nhưng các chú thích, chỉ thị biên dịch, macros, nhãn chương trình và địa chỉ bộ nhớ cũng có thể được hỗ trợ trong quá trình này.
Mỗi hợp ngữ được phát triển đặc thù cho một kiến trúc máy tính cụ thể, và đôi khi còn phải tùy chỉnh theo hệ điều hành. Tuy nhiên, một số hợp ngữ không cung cấp cú pháp riêng cho việc gọi hệ điều hành. Phần lớn các hợp ngữ có thể sử dụng chung với nhiều hệ điều hành khác nhau, vì chúng cho phép tiếp cận đầy đủ khả năng của bộ xử lý, mặc dù các cơ chế gọi hệ thống có thể bị giới hạn. Trái lại, ngôn ngữ lập trình bậc cao có thể chạy trên nhiều kiến trúc khác nhau nhưng lại đụng phải quá trình thông dịch hoặc biên dịch phức tạp hơn rất nhiều so với việc assembling.
Hợp ngữ từng được áp dụng rộng rãi trong nhiều lĩnh vực lập trình, nhưng hiện nay ngôn ngữ này chỉ còn được dùng chủ yếu trong một số ứng dụng đặc biệt. Chúng thường được sử dụng khi cần giao tiếp trực tiếp với phần cứng hoặc giải quyết các vấn đề đòi hỏi tốc độ cao như trong các trình điều khiển thiết bị, hệ thống nhúng cấp thấp và các ứng dụng thời gian thực.
Cú pháp hợp ngữ
Trước đây, việc lập trình trực tiếp vào máy tính qua mã máy số là một công việc tốn thời gian, dễ gặp lỗi và vô cùng mệt mỏi. Tuy nhiên, nhờ vào việc sử dụng các thuật nhớ (mnemonics), việc lập trình đã trở nên dễ dàng hơn, giúp các lập trình viên viết mã hiệu quả và ít sai sót hơn so với cách cũ.
Trong hợp ngữ, các lệnh máy hoặc mã cấp thấp được thể hiện qua các thuật nhớ (mnemonics). Mỗi lệnh có thể yêu cầu các toán hạng để tạo thành một lệnh đầy đủ. Các trình hợp dịch cho phép đặt tên cho các hằng số, thanh ghi, nhãn, và có thể tính toán các biểu thức toán học. Điều này giúp lập trình viên tránh được việc phải làm các tính toán phức tạp một cách lặp đi lặp lại, đồng thời làm cho mã dễ hiểu hơn so với mã máy. Các kiến trúc khác nhau có thể kết hợp các yếu tố này bằng cách sử dụng offset hoặc địa chỉ cố định, với nhiều trình hợp dịch cung cấp các công cụ hỗ trợ phát triển chương trình và gỡ lỗi hiệu quả.
Thuật ngữ trong hợp ngữ
- Một trình hợp dịch macro sử dụng một tập lệnh macro để biểu diễn văn bản hợp ngữ có tham số, giúp tạo mã mở rộng dễ dàng hơn.
- Trình hợp dịch đa nền tảng có thể hoạt động trên hệ thống máy tính hoặc hệ điều hành khác với hệ thống đích mà mã sẽ chạy. Các trình hợp dịch chéo hỗ trợ việc phát triển phần mềm trên các hệ thống không đủ tài nguyên, như vi điều khiển hay hệ thống nhúng. Mã kết quả phải được chuyển đến hệ thống đích qua bộ nhớ chỉ đọc hoặc các phương thức khác.
- Trình hợp dịch bậc cao cung cấp các tính năng của các ngôn ngữ bậc cao như các cấu trúc điều khiển (IF/THEN/ELSE, DO CASE...) và các loại dữ liệu phức tạp như cấu trúc, lớp, và tập hợp.
- Một vi hợp dịch là chương trình để chuẩn bị các chương trình vi mô, giúp kiểm soát máy tính ở mức độ thấp.
- Trình hợp dịch meta là một thuật ngữ để chỉ các chương trình chấp nhận mô tả cú pháp và ngữ nghĩa của hợp ngữ và tạo biên dịch cho ngôn ngữ đó.
- Assembly time là giai đoạn mà trình biên dịch chạy để tính toán và tạo mã đối tượng.
Các khái niệm cơ bản trong hợp ngữ
Trình hợp dịch (Assembler) là công cụ giúp chuyển đổi mã hợp ngữ thành mã máy hoặc mã đối tượng mà máy tính có thể thực thi. Trình hợp dịch thực hiện quá trình phiên dịch từng lệnh hợp ngữ thành mã thực thi (opcodes) và xử lý các biểu danh (symbolic names) cho các vùng nhớ và các thành phần khác. Việc sử dụng các biểu danh giúp giảm thiểu công sức tính toán và sửa đổi thủ công mỗi khi có thay đổi trong ứng dụng. Hầu hết các trình hợp dịch đều hỗ trợ tính năng macro, cho phép thay thế một nhóm lệnh bằng một tên gọi ngắn gọn, giúp tăng tính hiệu quả và dễ đọc trong quá trình lập trình.
Một số trình hợp dịch có khả năng thực hiện tối ưu hóa đặc thù cho từng loại tập lệnh. Ví dụ như trình hợp dịch x86 của các nhà cung cấp khác nhau có thể thay thế các lệnh nhảy dài bằng các lệnh nhảy ngắn hoặc tương đối, nhằm tiết kiệm bộ nhớ và cải thiện hiệu suất. Các trình hợp dịch này cũng có thể tái sắp xếp hoặc chèn lệnh để tối ưu hóa lịch trình, như trường hợp các trình hợp dịch cho kiến trúc RISC, giúp tối ưu hóa việc sử dụng kênh chuyền dữ liệu của CPU một cách hiệu quả.
Tương tự như các ngôn ngữ lập trình cổ điển như Fortran, Algol, Cobol, và Lisp, các trình hợp dịch đã được phát triển từ những năm 1950, trong thời kỳ đầu của các giao diện máy tính văn bản. Tuy nhiên, trình hợp dịch xuất hiện đầu tiên vì chúng đơn giản hơn nhiều so với trình biên dịch cho các ngôn ngữ bậc cao. Mỗi lệnh hợp ngữ được phiên dịch trực tiếp thành mã máy mà không cần nhiều phân tích, giúp tiết kiệm thời gian và tài nguyên. Bên cạnh đó, cũng có những lớp dịch giả hoặc trình tạo mã bán tự động có tính chất vừa giống hợp ngữ vừa giống ngôn ngữ bậc cao, trong đó Speedcode là một ví dụ nổi bật.
Các trình hợp dịch đã xuất hiện từ lâu và đóng vai trò quan trọng trong việc phát triển phần mềm, đặc biệt là vào những năm đầu của ngành lập trình máy tính. Những trình hợp dịch này giúp chuyển đổi mã hợp ngữ thành mã thực thi, cho phép các lập trình viên tạo ra các chương trình có thể chạy trên máy tính. Sự phát triển của trình hợp dịch đã làm cho việc lập trình trở nên dễ dàng hơn và mở ra nhiều cơ hội mới cho các ứng dụng phức tạp.
Có thể có một số trình biên dịch với cú pháp khác nhau cho một cấu trúc CPU hoặc tập lệnh cụ thể. Chẳng hạn, một lệnh để thêm dữ liệu bộ nhớ vào một thanh ghi trong bộ xử lý họ x86 có thể là add eax,[ebx], trong cú pháp gốc của Intel, trong khi điều này sẽ được viết là addl (%ebx),%eax trong cú pháp của AT&T được dùng trong GNU Assembler. Mặc dù xuất hiện khác nhau, các hình thức cú pháp khác nhau thường tạo ra cùng một mã máy. Xem bên dưới. Một trình biên dịch đơn cũng có thể có các chế độ khác nhau để hỗ trợ các biến thể trong các hình thức cú pháp cũng như các diễn giải ngữ nghĩa chính xác của chúng (như cú pháp FASM, cú pháp TASM, chế độ lý tưởng, v.v., trong trường hợp đặc biệt của lập trình hợp ngữ x86).
Các trình hợp dịch nói chung dễ tạo hơn so với các chương trình dịch cho ngôn ngữ cấp cao. Những trình hợp ngữ đầu tiên xuất hiện từ những thập niên 1950, trong buổi đầu sơ khai của máy tính đã tạo ra một bước ngoặt lớn đối với những lập trình viên vốn rất mệt mỏi vì việc lập trình bằng ngôn ngữ máy. Các trình hợp dịch hiện đại ngày nay, đặc biệt cho các dòng chip RISC như MIPS, Sun SPARC và HP PA-RISC, thường tối ưu việc sắp xếp và đồng bộ các chỉ thị lệnh (instruction scheduling) để tận dụng các kênh chuyền dữ liệu (pipeline) của CPU một cách hiệu quả.
Số lần
Có hai loại trình hợp dịch dựa trên số lần truyền qua nguồn cần thiết (số lần trình biên dịch đọc nguồn) để tạo tệp đối tượng.
- Trình hợp dịch một lần đi qua mã nguồn một lần. Bất kỳ ký hiệu nào được sử dụng trước khi được xác định sẽ yêu cầu "errata" ở cuối mã đối tượng (hoặc, ít nhất, không sớm hơn điểm mà biểu tượng được xác định) báo cho trình liên kết hoặc trình tải "quay lại" và ghi đè lên giữ chỗ đã được để lại nơi sử dụng biểu tượng chưa xác định.
- Trình hợp dịch nhiều lần tạo một bảng có tất cả các ký hiệu và giá trị của chúng trong các lượt đầu tiên, sau đó sử dụng bảng trong các lần truyền sau để tạo mã.
Trong cả hai trường hợp, trình biên dịch cần có khả năng xác định kích thước của mỗi lệnh trong các chuyền ban đầu để tính toán địa chỉ của các ký hiệu tiếp theo. Điều này có nghĩa là nếu kích thước của một hoạt động liên quan đến toán hạng được xác định sau phụ thuộc vào loại hoặc khoảng cách của toán hạng, trình biên dịch sẽ đưa ra ước tính bi quan khi gặp thao tác lần đầu và nếu cần, sẽ đệm thao tác này bằng một hoặc nhiều lệnh 'no-operation' trong quá trình duyệt hoặc errata. Với một trình biên dịch có tối ưu hóa lỗ nhìn trộm, địa chỉ có thể được tính toán lại trong các lần chuyển tiếp để thay thế mã bi quan bằng mã được điều chỉnh cho phù hợp với khoảng cách chính xác từ mục tiêu.
Lý do ban đầu để sử dụng bộ hợp dịch một lần là tốc độ hợp dịch - thường thì lần hợp dịch thứ hai yêu cầu tua lại và đọc lại nguồn chương trình từ băng hoặc đọc lại chuỗi bìa đục lỗ. Các máy tính sau này có bộ nhớ lớn hơn nhiều, đặc biệt là bộ nhớ đĩa, đủ không gian để thực hiện tất cả các xử lý cần thiết mà không cần phải đọc lại. Ưu điểm của trình hợp dịch nhiều lượt là việc không có errata giúp quá trình liên kết (hoặc tải chương trình nếu trình biên dịch tạo mã thực thi trực tiếp) diễn ra nhanh chóng hơn.
Ví dụ: trong đoạn mã dưới đây, trình hợp dịch một lượt có thể xác định địa chỉ của BKWD tham chiếu ngược khi hợp dịch câu lệnh S2, nhưng không thể xác định địa chỉ của FWD tham chiếu chuyển tiếp khi hợp dịch câu lệnh nhánh S1; thực tế, FWD có thể không được xác định. Trình hợp dịch hai lượt sẽ xác định cả hai địa chỉ trong lần 1, vì vậy chúng sẽ được biết khi tạo mã trong lần 2.
S1 B FWD
...
FWD GÁN *
...
BKWD GÁN *
...
S2 B BKWD
Trình biên dịch cấp cao
Nhiều trình biên dịch cấp cao còn hỗ trợ những khả năng ngôn ngữ trừu tượng như:
- Khai báo thủ tục/hàm cấp cao
- Các cấu trúc điều khiển phức tạp (IF/THEN/ELSE, SWITCH)
- Khai báo hàm cấp cao
- Các kiểu dữ liệu trừu tượng cấp cao bao gồm các cấu trúc/bản ghi, unions, lớp và sets
- Xử lý macro phức tạp (dù đã có trên các trình biên dịch từ thập niên 1950 cho dòng IBM 700 và từ thập niên 1960 cho IBM/360, cùng nhiều thiết bị khác)
- Những tính năng lập trình hướng đối tượng như lớp, đối tượng, trừu tượng hóa, đa hình và kế thừa.
Ngôn ngữ hợp ngữ (Assembly language)
Một chương trình viết bằng hợp ngữ bao gồm một chuỗi các lệnh (instructions) dễ hiểu, tương ứng với một chuỗi các chỉ thị khả thi (executable), khi được biên dịch bởi một trình hợp dịch, sẽ có thể được nạp vào bộ nhớ và thực thi. Ví dụ, bộ vi xử lý x86/IA-32 có thể thực hiện chỉ thị nhị phân sau (được thể hiện dưới dạng ngôn ngữ máy):
- 10110000 01100001 (hệ thập lục phân: 0xb061)
Lệnh này tương ứng với một chỉ thị hợp ngữ dễ hiểu hơn như sau:
- mov al, 061h
Chỉ thị lệnh này có nghĩa là: gán giá trị thập lục phân 61 (tương đương với 97 trong hệ thập phân) vào thanh ghi trong bộ vi xử lý mang tên "al". Thuật ngữ "mov" là mã thực thi (operation code / opcode), được người thiết kế tập lệnh thay thế cho từ "move", và các đối/ tham số của lệnh theo sau, ngăn cách bởi dấu phẩy ",".
Trình hợp dịch thực hiện việc chuyển đổi hợp ngữ sang ngôn ngữ máy, trong khi trình phân dịch (disassembler) thực hiện ngược lại. Khác với các ngôn ngữ bậc cao, các chỉ thị hợp ngữ cơ bản thường có mối liên hệ một-một với các chỉ thị ngôn ngữ máy. Tuy nhiên, trong một số trường hợp, trình hợp dịch có thể thêm vào các lệnh giả (pseudo-instructions) vào tập lệnh ngôn ngữ máy để cung cấp các chức năng sử dụng thường xuyên. Hầu hết các trình hợp dịch đa năng đều đi kèm với một tập macro phong phú, giúp nhà sản xuất thiết bị và lập trình viên tạo mã lệnh cũng như các dãy dữ liệu phức tạp.
Mỗi hệ thống máy tính đều có ngôn ngữ máy riêng biệt và do đó cũng có hợp ngữ riêng, chúng được phân biệt qua số lượng và loại lệnh mà chúng hỗ trợ. Các hệ thống này cũng có thể khác nhau về số lượng và kích thước của các thanh ghi, cũng như cách thức lưu trữ và biểu diễn các kiểu dữ liệu trong bộ nhớ. Mặc dù các máy tính công dụng chung có thể thực hiện các chức năng tương tự nhau, nhưng phương thức thực hiện lại khác biệt, phản ánh sự khác biệt giữa các hợp ngữ dành cho từng kiểu máy tính.
Ngôn ngữ máy (Machine language)
Ngôn ngữ máy được hình thành từ các chỉ thị và lệnh độc lập, tùy theo từng kiến trúc xử lý mà tập lệnh sẽ được thiết lập với các đặc điểm riêng biệt:
- Các thanh ghi dùng trong các phép toán số học
- Cấu trúc bộ nhớ và cách tính địa chỉ
- Cách thức điều khiển nhánh
- Các kiểu đánh địa chỉ đặc trưng để giải quyết các toán hạng
Nhiều lệnh phức tạp được tạo thành bằng cách kết hợp các chỉ thị đơn giản, tuân thủ nguyên lý máy tính Von Neumann, nghĩa là thực hiện các lệnh tuần tự và chuyển nhánh theo các lệnh phân luồng. Một số lệnh cơ bản có mặt trong hầu hết các tập lệnh bao gồm:
- Lệnh gán
- Gán một giá trị hằng số cụ thể vào một thanh ghi (vùng nhớ tạm trong CPU)
- Chuyển dữ liệu giữa các vùng nhớ và thanh ghi, thao tác này chuẩn bị dữ liệu cho các phép tính sau hoặc lưu kết quả tính toán trước đó.
- Đọc và ghi dữ liệu từ và vào các thiết bị phần cứng
- Lệnh tính toán
- Các phép cộng, trừ, nhân, chia trên các giá trị trong thanh ghi, lưu kết quả vào một thanh ghi
- Thực hiện các phép toán logic bit như "và"/"hoặc" (AND/OR) giữa các thanh ghi, hoặc phủ định bit trên một thanh ghi
- So sánh các giá trị lưu trong hai thanh ghi (lớn hơn, nhỏ hơn, bằng nhau)
- Lệnh điều khiển rẽ nhánh
- Nhảy tới vị trí khác trong chương trình và thực thi các lệnh tại đó
- Nhảy tới một vị trí nếu điều kiện đã thỏa mãn
- Nhảy đến một vị trí và lưu lại vị trí của lệnh tiếp theo để có thể quay lại (thường dùng trong gọi hàm)
Một số hệ thống máy tính bao gồm các chỉ thị lệnh phức hợp trong tập lệnh của chúng. Lệnh phức hợp thường thực hiện các tác vụ đòi hỏi nhiều chỉ thị trên các máy khác nhau, thực hiện qua nhiều bước và điều khiển nhiều đơn vị chức năng. Dưới đây là một số lệnh phức hợp điển hình:
- Lưu nhiều thanh ghi vào ngăn xếp chỉ một lần
- Di chuyển các vùng nhớ lớn
- Các phép toán số học phức tạp như sin, cos, căn bậc hai, v.v.
- Các lệnh ALU thực hiện toán hạng từ bộ nhớ thay vì từ thanh ghi
Một loại lệnh phức hợp phổ biến hiện nay là các phép toán SIMD hay lệnh vector (vector instruction), cho phép thực hiện một phép toán số học đồng thời trên nhiều phần dữ liệu. Các lệnh SIMD (single instruction multiple data) hỗ trợ thực thi song song các thuật toán trong xử lý âm thanh, hình ảnh, video một cách hiệu quả. Các tập lệnh SIMD được tích hợp vào nhiều CPU và đã được thương mại hóa với các tên gọi như MMX và SSE, SSE2, SSE3, SSE4 (Intel), 3DNow! (AMD), AltiVec (IBM), tm3260 và tm5250 (Nexperia - Philips), v.v.
Thiết kế
Trong hợp ngữ, các chỉ thị lệnh thường rất đơn giản và không phức tạp như trong các ngôn ngữ bậc cao. Mỗi chỉ thị điển hình bao gồm một mã lệnh (opcode) và một hoặc nhiều toán hạng, hoặc có thể không có toán hạng nào. Các chỉ thị này thường tham chiếu tới một giá trị đơn hoặc một cặp giá trị. Mỗi chỉ thị lệnh được mã hóa thành một chỉ thị ngôn ngữ máy đơn lẻ, có thể thực thi. Các thành phần cơ bản có trong hợp ngữ gồm:
- Định nghĩa dữ liệu (Data definitions). Các chỉ thị phụ giúp lập trình viên chỉ định một vùng nhớ để lưu trữ các giá trị mà các lệnh ngôn ngữ máy sẽ tham chiếu. Các vùng nhớ này có thể chứa các ký tự, chuỗi hay các kiểu dữ liệu cơ bản khác.
- Nhãn (Labels). Lập trình viên sử dụng nhãn để tham chiếu đến các định nghĩa dữ liệu. Nhãn có thể là hằng số, biến, hoặc các thành phần của cấu trúc. Ngoài ra, nhãn cũng có thể được dùng để đánh dấu các vùng mã thực thi như điểm bắt đầu của thủ tục hoặc mục tiêu nhảy của lệnh GOTO. Các trình hợp dịch hỗ trợ linh hoạt trong việc quản lý nhãn, giúp lập trình viên thao tác với nhiều không gian tên và tự động tính toán độ lệch địa chỉ trong các cấu trúc dữ liệu, tham chiếu đến các nhãn chứa giá trị cố định hoặc kết quả tính toán.
- Chú dẫn (Comments). Giống như các ngôn ngữ lập trình khác, hợp ngữ cho phép thêm các chú dẫn vào mã nguồn. Các chú dẫn này không ảnh hưởng đến quá trình biên dịch và chỉ phục vụ cho lập trình viên tham khảo.
- Tập lệnh bó (Macros). Hầu hết các trình hợp dịch hỗ trợ ngôn ngữ macro. Lập trình viên sử dụng macro để tái sử dụng các đoạn mã lặp lại. Trong quá trình tiền biên dịch, các lệnh trong macro được điều chỉnh và chèn vào vị trí gọi. Macro cũng được sử dụng để thực hiện các phép toán đặc biệt, ví dụ:
- Bộ vi xử lý 8 bit sử dụng macro để thao tác với giá trị 16 bit, việc này thường phải thực hiện trong ba hoặc bốn chỉ thị lệnh đơn lẻ. (Ví dụ: bộ vi xử lý MOS Technology 6502)
- Các nhà sản xuất thiết bị cung cấp macro cho các thao tác vào/ra (I/O) và các yêu cầu hệ thống cấp thấp. Các máy tính lớn của IBM có các thư viện macro giúp truy xuất và dịch vụ hệ thống khác
Các tính năng này được vay mượn từ các ngôn ngữ bậc cao, giúp đơn giản hóa các vấn đề trong lập trình và bảo trì mã nguồn ở mức thấp. Mã nguồn hợp ngữ cũng có thể được tạo ra thông qua các trình biên dịch ngôn ngữ bậc cao hoặc trình phân dịch mã máy, nhưng chúng thường thiếu các chú dẫn và các định danh dễ hiểu, làm cho việc đọc mã trở nên khó khăn hơn.
Mặc dù có những đặc điểm cơ bản như trên, nhưng một số hợp ngữ còn có các tính năng đặc biệt như:
- Nhiều trình hợp dịch cung cấp các ngôn ngữ macro rất mạnh mẽ, cho phép sử dụng các yếu tố của ngôn ngữ bậc cao như biến tượng trưng, lệnh điều kiện, thao tác chuỗi và phép toán số học. Một macro có thể thay thế một số lớn các lệnh hợp ngữ hoặc các định nghĩa dữ liệu dựa trên các tham số. Macro có thể tạo ra các cấu trúc dữ liệu kiểu bản ghi hoặc vòng lặp "mở" (unrolled), hoặc giải quyết một thuật toán phức tạp dựa trên các tham số của macro.
Ứng dụng
Trong quá khứ
Về mặt lịch sử, rất nhiều chương trình đã được xây dựng hoàn toàn bằng hợp ngữ. Trước khi ngôn ngữ C ra đời vào thập niên 1970 và 1980, các hệ điều hành độc quyền chủ yếu được viết bằng hợp ngữ. Nhiều phần mềm thương mại cũng vậy, đặc biệt là phần mềm dành cho các máy tính lớn của IBM do các tập đoàn lớn phát triển. Sau này, ngôn ngữ COBOL và FORTRAN đã dần thay thế hợp ngữ, mặc dù nhiều tổ chức vẫn giữ lại các cấu trúc ứng dụng kiểu hợp ngữ vào những năm 1980. Hầu hết các máy tính cá nhân thời kỳ đầu chủ yếu sử dụng hợp ngữ, bao gồm hệ điều hành và các ứng dụng lớn. Điều này là do hệ thống bị giới hạn về tài nguyên, phần cứng, bộ nhớ và giao diện hiển thị, cùng với các dịch vụ hệ thống dễ gặp lỗi. Quan trọng hơn cả là sự thiếu hụt các trình biên dịch bậc cao phù hợp với những hệ thống máy tính này. Các ứng dụng lớn được viết bằng hợp ngữ bao gồm hệ điều hành CP/M và MS-DOS, phần mềm bảng tính như Lotus-123 trên các máy tính IBM-PC đời đầu, và nhiều trò chơi phổ biến trên máy Commodore 64. Thậm chí vào những năm 1990, hợp ngữ vẫn được sử dụng để phát triển các trò chơi video, bao gồm các trò chơi trên các hệ máy Mega Drive/Genesis và Super Nintendo Entertainment System.
Ngoài ra, còn có một loại "ứng dụng" không được khuyến khích, đó là virus máy tính. Vào những năm '80 và đầu những năm '90, hầu hết các virus máy tính được viết bằng hợp ngữ, vì hợp ngữ giúp giảm kích thước virus và cho phép nó can thiệp sâu vào hệ thống.
Hiện nay
Trước đây, đã có không ít cuộc tranh luận về sự tiện dụng và hiệu năng của hợp ngữ so với các ngôn ngữ bậc cao, mặc dù ngày nay ít người quan tâm đến điều này. Tuy nhiên, hợp ngữ vẫn giữ một vai trò quan trọng trong một số tình huống cụ thể. Các trình biên dịch hiện đại hiện nay có thể chuyển các ngôn ngữ bậc cao thành mã thực thi nhanh chóng, ít nhất là ngang với hợp ngữ. Sự phát triển của các bộ vi xử lý hiện đại giúp tối ưu hóa mã hiệu quả hơn, đồng thời phần lớn thời gian của CPU thường ở trạng thái rỗi, vì vậy tốc độ thực thi mã thô không còn là yếu tố quan trọng đối với hầu hết lập trình viên. Sự gia tăng của các ngôn ngữ thông dịch là minh chứng rõ ràng cho sự thay đổi này.
Ngày nay, chỉ có một vài tình huống mà các chuyên gia thực sự cần sử dụng hợp ngữ trong công việc của họ, cụ thể như sau:
- Khi các thiết bị hoạt động độc lập và không cần đến tài nguyên hay thư viện của các ngôn ngữ bậc cao. Đây là tình huống khá phổ biến.
- Khi cần giao tiếp trực tiếp với phần cứng, như việc viết trình điều khiển thiết bị hoặc sử dụng các chỉ thị vi xử lý mà trình biên dịch không thể tận dụng được.
- Khi yêu cầu tối ưu hóa mã rất chặt chẽ, như trong các thuật toán sử dụng vòng lặp tốn nhiều tài nguyên xử lý.
- Khi hệ thống yêu cầu mã thủ công để tận dụng tối đa tài nguyên hạn chế, mặc dù ngày nay điều này ít gặp do giá thành CPU giảm và hiệu suất của CPU ngày càng cao.
- Khi ngôn ngữ bậc cao không thể chạy trên một CPU mới hoặc CPU chuyên dụng.
Hiện nay, lập trình viên có thể chọn sử dụng các ngôn ngữ cấp thấp như C để phát triển ứng dụng yêu cầu hiệu suất cao. Tuy nhiên, việc sử dụng C không phải lúc nào cũng mang lại hiệu quả vượt trội hơn hợp ngữ. Bên cạnh đó, hợp ngữ vẫn được giảng dạy trong hầu hết các chương trình Khoa học máy tính, vì các khái niệm nền tảng như số học nhị phân, quản lý bộ nhớ, xử lý ngăn xếp, mã hóa ký tự, xử lý ngắt và thiết kế trình biên dịch vẫn rất quan trọng. Cách thức hoạt động của máy tính được xác định bởi tập lệnh cơ sở của nó, và để hiểu rõ các khái niệm này, nghiên cứu hợp ngữ là một phương pháp hiệu quả. May mắn thay, hầu hết các máy tính hiện đại có tập lệnh tương tự nhau, vì vậy việc nắm vững hợp ngữ của một máy tính sẽ giúp hiểu được các hệ thống khác.
Các ứng dụng điển hình
Hợp ngữ ở mức thấp thường được sử dụng cho BIOS, lưu trữ trong ROM của hệ thống, với mục đích khởi tạo và kiểm tra phần cứng trước khi hệ điều hành được tải. Sau khi quá trình khởi tạo phần cứng hoàn tất, quyền điều khiển hệ thống sẽ được chuyển giao cho các mã thực thi khác, thường được viết bằng ngôn ngữ bậc cao. Điều này cũng áp dụng cho phần lớn các trình khởi động (boot loader).
Nhiều trình biên dịch chuyển ngữ các ngôn ngữ bậc cao thành hợp ngữ trước khi thực hiện biên dịch chính thức. Điều này không chỉ giúp kiểm tra mã mà còn phục vụ mục đích tối ưu hóa và gỡ lỗi. Các ngôn ngữ cấp thấp như C cung cấp cú pháp đặc biệt để tích hợp trực tiếp hợp ngữ vào mã nguồn. Các chương trình sử dụng tính năng này, chẳng hạn như Nhân Linux, có thể tạo ra các lớp trừu tượng để tương thích với nhiều kiến trúc phần cứng khác nhau.
Hợp ngữ cũng rất quan trọng trong kỹ thuật dịch ngược (reverse engineering). Các chương trình lớn, thường chỉ được phân phối dưới dạng mã máy, có thể dễ dàng dịch ngược thành hợp ngữ để kiểm tra. Tuy nhiên, việc dịch ngược chúng thành mã ngôn ngữ bậc cao lại vô cùng khó khăn.
- Hợp ngữ dòng x86 – hợp ngữ dành cho các bộ vi xử lý 80x86 của Intel
- Trình biên dịch
- Trình phân dịch
- Danh sách trình biên dịch
Sách
- The Art of Assembly Language Programming Lưu trữ 2004-12-31 tại Wayback Machine, [1] Lưu trữ 2002-06-22 tại Wayback Machine by Randall Hyde
- Computer-Books.us Lưu trữ 2018-02-24 tại Wayback Machine, Online Assembly Language Books
- PC Assembly Language by Dr Paul Carter; *PC Assembly Tutorial using NASM and GCC Lưu trữ 2018-02-24 tại Wayback Machine by Paul Carter
- Programming from the Ground Up by Jonathan Bartlett
- The x86 ASM Book by the ASM Community
- Dominic Sweetman: See MIPS Run. Morgan Kaufmann Publishers. ISBN 1-55860-410-3
- Robert Britton: MIPS Assembly Language Programming. Prentice Hall. ISBN 0-13-142044-5
- John Waldron: Introduction to RISC Assembly Language Programming. Addison Wesley. ISBN 0-201-39828-1
- Jeff Duntemann Assembly Language Step-by-Step Lưu trữ 2006-12-16 tại Wayback Machine
Liên kết ngoài
- The ASM Community Messageboard
- MenuetOS - hệ điều hành hobby cho PC được viết hoàn toàn bằng hợp ngữ 64bit
- Danh sách các tài nguyên; sách, website, nhóm tin nhắn và kênh IRC
- Unix Assembly Language Programming Lưu trữ 2020-02-17 tại Wayback Machine
- PPR: Học ngôn ngữ hợp ngữ
- CodeTeacher Lưu trữ 2007-02-03 tại Wayback Machine
- Ví dụ lập trình hợp ngữ
- Typed Assembly Language (TAL)
- Tạo ứng dụng Windows bằng hợp ngữ
- Diễn đàn RosAsm assembler/ RosAsm assembly
- Ví dụ lập trình RosAsm
- Trình giả lập 80x86
- AVR Assembler
- The Program Transformation Wiki
- GNU lightning là một thư viện sinh mã hợp ngữ tại thời gian chạy, rất hữu ích cho các trình biên dịch Just-In-Time
- "Thông tin về lập trình hợp ngữ trên các nền tảng khác nhau: IA32 (x86), IA64 (Itanium), x86-64, SPARC, Alpha, hoặc bất kỳ nền tảng nào có đóng góp"
- "Terse: Algebraic Assembly Language for x86"
- Iczelion's Win32 Assembly Tutorial Lưu trữ 2008-03-08 tại Wayback Machine
- SB-Assembler cho hầu hết các bộ vi xử lý/controller 8-bit
- Assembly Tutorials BeginnersCode.com
- IBM z/Architecture Principles of Operation Sách hướng dẫn về ngôn ngữ máy và cấu trúc bên trong của máy mainframe IBM.
- IBM High Level Assembler Sách hướng dẫn về ngôn ngữ hợp ngữ trên mainframe IBM.
- www.mis-algoritmos.com – Ví dụ ASM x386 cơ bản Lưu trữ 2006-12-15 tại Wayback Machine dùng ngắt INT 21h và INT 10h [bằng tiếng Tây Ban Nha]
- Công cụ và bài học cho lập trình viên x86
- Assembly Optimization Tips Lưu trữ 2019-05-07 tại Wayback Machine bởi Mark Larson
Hệ thống nhúng | |
|---|---|
| Thuật ngữ chung |
|
| Firmware và hệ thống điều khiển |
|
| Trình tải khởi động |
|
| Thư viện phần mềm |
|
| Công cụ lập trình |
|
| Hệ điều hành |
|
| Ngôn ngữ lập trình |
|
| |
| Tiêu đề chuẩn |
|
|---|
