Do trình biên dịch-nhà văn thực sự cần phải 'hiểu' mã máy? [đóng cửa]


10

Có thể là một loại câu hỏi kỳ lạ.

Một anh chàng viết trình biên dịch C ++ (hoặc bất kỳ ngôn ngữ không phải VM nào): Anh ta có cần đọc / viết ngôn ngữ máy thô không? Làm thế nào mà làm việc?

EDIT: Tôi đặc biệt đề cập đến các trình biên dịch biên dịch mã máy chứ không phải một số ngôn ngữ lập trình khác.



1
Không. Bạn thậm chí không cần biết điều đó, bạn chỉ có thể sao chép một cách mù quáng, vô thức sao chép đặc tả kỹ thuật của mục tiêu của bạn: dl.acm.org/citation.cfm?id=1706346
SK-logic

1
Coffescript biên dịch thành javascript.
Kartik

@Kartik Trình biên dịch CoffeeScript có biên dịch thành Javascript không, cũng bao gồm trình biên dịch Javascript biên dịch thành bất kỳ Javascript nào được biên dịch? Hay nó chỉ biên dịch thành mã nguồn Javascript và không có gì nữa?
Aviv Cohn

Trình biên dịch coffeescript chỉ đơn giản là chuyển đổi cofeescript thành javascript. Javascript không được biên dịch, nó được xử lý bởi trình duyệt. Tôi muốn nói rằng bạn có thể viết một trình biên dịch biên dịch một ngôn ngữ này sang ngôn ngữ khác, bạn không cần phải biết ngôn ngữ máy cho ngôn ngữ đó. Một ví dụ khác là trình biên dịch 'SPL' biên dịch Shakespeare phát thành C ++. shakespearelang.sourceforge.net
Kartik

Câu trả lời:


15

Không hoàn toàn không. Thay vào đó, điều hoàn toàn có thể (và thường là thích hợp hơn) để trình biên dịch của bạn phát ra mã lắp ráp thay thế. Trình biên dịch sau đó đảm nhiệm việc tạo mã máy thực tế.

Nhân tiện, việc phân biệt triển khai không VM và thực hiện VM của bạn là không hữu ích.

  • Đối với người mới bắt đầu, sử dụng VM hoặc tiền biên dịch cho mã máy chỉ là những cách khác nhau để thực hiện ngôn ngữ; trong hầu hết các trường hợp, một ngôn ngữ có thể được thực hiện bằng cách sử dụng một trong hai chiến lược. Tôi thực sự đã phải sử dụng một trình thông dịch C ++ một lần.

  • Ngoài ra, nhiều máy ảo như JVM đều có mã máy nhị phân và một số trình biên dịch, giống như một kiến ​​trúc thông thường.

LLVM (được các trình biên dịch Clang sử dụng) đáng được đề cập đặc biệt ở đây: Nó định nghĩa một VM mà các hướng dẫn có thể được biểu diễn dưới dạng mã byte, tập hợp văn bản hoặc cấu trúc dữ liệu giúp dễ dàng phát ra từ trình biên dịch. Vì vậy, mặc dù nó sẽ hữu ích cho việc gỡ lỗi (và để hiểu những gì bạn đang làm), bạn thậm chí sẽ không phải biết về ngôn ngữ lắp ráp, chỉ về API LLVM.

Điều thú vị về LLVM là VM của nó chỉ là một sự trừu tượng hóa và mã byte thường không được giải thích, nhưng thay vào đó là JITted trong suốt. Vì vậy, hoàn toàn có thể viết một ngôn ngữ được biên dịch hiệu quả mà không cần phải biết về tập lệnh của CPU.


Và một đặc tính tốt khác của LLVM là người ta không cần phải hiểu sâu về ISA đích để thực hiện một phụ trợ hiệu quả. Đó là một tuyên bố khá hay, vì vậy người ta gần như có thể sao chép và dán một đặc tả của ISA vào các tệp .td mà không cần cố gắng hiểu nó.
SK-logic

Cảm ơn đã trả lời. Câu hỏi: Tôi hiểu từ câu trả lời của bạn và câu trả lời của người khác rằng trình biên dịch-biên dịch viên không phải hiểu mã máy, anh ta có thể sử dụng một công cụ khác thực hiện chuyển đổi mã thực tế thành mã máy cho anh ta. Tuy nhiên, anh chàng đã viết công cụ đó đã phải hiểu ngôn ngữ máy móc, phải không? Anh chàng đã viết phần mềm thực hiện chuyển đổi thực tế từ một số ngôn ngữ sang mã máy phải thực sự hiểu ngôn ngữ máy phải không?
Aviv Cohn

5
@Prog có. Nếu bạn tạo một lớp trừu tượng, bạn chỉ phải hiểu lớp bên dưới bạn. Mặc dù rất hữu ích khi có một sự hiểu biết cơ bản về tất cả các lớp, nhưng điều này thực sự không cần thiết. Bạn không cần phải hiểu vật lý lượng tử để sử dụng bóng bán dẫn. Bạn không cần phải hiểu thiết kế chip để sử dụng CPU. Bạn không cần biết mã máy để viết lắp ráp. Bạn không cần phải biết tập lệnh của nền tảng khi sử dụng VM, v.v. Nhưng ai đó đã phải xây dựng các mức trừu tượng bên dưới của bạn.
amon

1
@ SK-logic Không đúng (ít nhất là nếu bạn muốn mã tốt) từ những gì tôi đã nghe. Những người đã triển khai chương trình phụ trợ Aarch64 cho llvm có khá nhiều thử thách (chuyển vị trí cho một, mô hình cửa hàng tải khủng khiếp, ..). Và đó là phớt lờ những con voi lớn nhất trong phòng: Mô hình bộ nhớ ISA và mô hình bộ nhớ của ngôn ngữ mà bạn đang quan tâm đến việc Bạn có thể làm việc trên một trình biên dịch, nhưng bạn không thể làm việc trên một backend mà không hiểu kiến trúc ...
Voo

1
Tôi sẽ thêm rằng thực sự không có sự khác biệt đáng kể giữa lắp ráp và mã máy, về mặt khái niệm. Bạn sẽ không thực sự có nhiều lợi ích, một khi biết cách sử dụng một lệnh cụ thể, opcode của lệnh đó là gì. Nếu bạn biết cách sử dụng MOV, điều đó thực sự không quan trọng nếu bạn không biết rằng đó là hướng dẫn 27, mà tôi nghĩ tương tự như những gì @ SK-logic đang mô tả.
whatsisname

9

Không. Điểm mấu chốt của câu hỏi của bạn là biên soạn là thuật ngữ cực kỳ rộng. Việc biên dịch có thể xảy ra từ bất kỳ ngôn ngữ nào sang bất kỳ ngôn ngữ nào. Và mã lắp ráp / mã máy chỉ là một trong nhiều ngôn ngữ cho mục tiêu biên dịch. Ví dụ, các ngôn ngữ Java và .NET như C #, F # và VB.NET đều biên dịch thành một loại mã trung gian thay vì mã dành riêng cho máy. Không thành vấn đề nếu nó chạy trên VM, ngôn ngữ vẫn được biên dịch. Ngoài ra còn có tùy chọn biên dịch sang một số ngôn ngữ khác, như C. C thực sự là mục tiêu biên dịch khá phổ biến và nhiều công cụ thực hiện nó. Và cuối cùng, bạn có thể sử dụng một số công cụ hoặc thư viện để thực hiện công việc khó khăn trong việc sản xuất mã máy cho bạn. ví dụ như LLVM có thể giảm nỗ lực cần thiết để tạo một trình biên dịch độc lập.

Ngoài ra, chỉnh sửa của bạn không có ý nghĩa gì. Nó giống như hỏi "Có phải mọi kỹ sư đều cần hiểu cách thức hoạt động của động cơ? Và tôi đang hỏi về các kỹ sư làm việc trên động cơ." Nếu bạn đang làm việc trên một chương trình hoặc thư viện phát ra mã máy, thì bạn phải hiểu nó. Vấn đề là, bạn không phải làm điều đó khi viết trình biên dịch. Nhiều người đã làm điều đó trước bạn, vì vậy bạn cần có lý do nghiêm túc để làm lại.


Và người viết công cụ hoặc thư viện thực hiện chuyển đổi thực tế sang ngôn ngữ máy, có phải hiểu ngôn ngữ máy hoàn toàn không?
Aviv Cohn

3
@Prog Bạn có cần hiểu một ngôn ngữ lập trình đầy đủ để lập trình trong đó không? Không, nhưng bạn có thể viết mã tối ưu phụ và bạn không thể thực hiện một số điều mà người khác có thể làm. Bạn có cần phải hiểu hoàn toàn ngôn ngữ máy nếu bạn viết một trình biên dịch dịch sang đó. Không, nhưng trình biên dịch của bạn sẽ không tối ưu và không có khả năng thực hiện một số việc nhất định.
Sumurai8

@ Sumurai8: mặc dù ở một mức độ nào đó, bạn có thể "hiểu" từng phần của ngôn ngữ máy để viết một trình phát mã máy để hiểu toàn bộ nội dung tốt hơn bạn. Ví dụ: nếu bạn viết một khung công tác tốt, bạn có thể định cấu hình định nghĩa của từng opcode cùng với các cân nhắc về chi phí và đường ống của nó, và sau đó khung của bạn có thể viết mã máy được tối ưu hóa mặc dù bạn không có chuyên môn gì trong việc tối ưu hóa máy cụ thể đó. Có thể tự lập trình mã máy đó một cách thành thạo có lẽ không bị tổn thương.
Steve Jessop

@SteveJessop Nếu bạn hiểu từng opcode đến một điểm mà bạn có thể tìm hiểu một máy làm thế nào để xâu chuỗi opcode đó với các opcode khác để diễn đạt một khái niệm cấp cao hơn, bạn hoàn toàn hiểu ngôn ngữ máy. Sau đó, bạn quá lười biếng để tìm giải pháp tối ưu cho mọi vấn đề ngoài kia ;-)
Sumurai8

@ Sumurai8: hmm, nhưng ít nhất về nguyên tắc tôi có thể "hiểu" từng opcode trong năm phút để tôi định cấu hình nó, và sau đó tôi đã quên nó sau khi tôi "hiểu" opcode sau đó. Đó có lẽ không phải là những gì người hỏi có nghĩa là "có thể đọc / viết ngôn ngữ máy thô". Tất nhiên tôi đang giả sử một khung công tác khá tốt ở đây, đủ cấu hình để xác định và sử dụng tất cả các thông tin hữu ích về mỗi opcode của tập lệnh. LLVM phần nào nhắm đến điều này nhưng theo "Voo" (trong một bình luận bên dưới) đã không đạt được điều đó.
Steve Jessop

3

Về mặt kinh điển, trình biên dịch có ba phần: phân tích từ vựng, phân tích cú pháp và tạo mã. Phân tích từ vựng chia văn bản của chương trình thành các từ khóa, tên và giá trị ngôn ngữ. Phân tích cú pháp làm thế nào các mã thông báo đến từ phân tích từ vựng được kết hợp trong các tuyên bố chính xác về mặt cú pháp cho ngôn ngữ. Việc tạo mã lấy các cấu trúc dữ liệu do trình phân tích cú pháp tạo ra và chuyển chúng thành mã máy hoặc một số biểu diễn khác. Ngày nay, phân tích từ vựng và phân tích cú pháp có thể được kết hợp thành một bước duy nhất.

Rõ ràng người viết trình tạo mã phải hiểu mã máy đích ở mức rất sâu, bao gồm các tập lệnh, đường ống xử lý và hành vi bộ đệm. Nếu không, các chương trình được tạo bởi trình biên dịch sẽ chậm và không hiệu quả. Họ rất có thể có thể đọc và viết mã máy như được biểu thị bằng số bát phân hoặc thập lục phân, nhưng họ thường sẽ viết các hàm để tạo mã máy, tham khảo nội bộ các bảng hướng dẫn máy. Về mặt lý thuyết, những người viết lexer và trình phân tích cú pháp có thể không biết gì về việc tạo mã máy. Trong thực tế, một số trình biên dịch hiện đại cho phép bạn cắm các thói quen tạo mã của riêng bạn, thứ có thể phát ra mã máy cho một số CPU mà các nhà văn lexer và trình phân tích cú pháp chưa bao giờ nghe thấy.

Tuy nhiên, trong thực tế các trình biên dịch trình biên dịch ở mỗi bước biết rất nhiều về các kiến ​​trúc bộ xử lý khác nhau và điều đó giúp họ thiết kế cấu trúc dữ liệu mà bước tạo mã sẽ cần.


2

Một thời gian dài trước đây tôi đã viết một trình biên dịch chuyển đổi giữa hai tập lệnh shell khác nhau. Nó không có cách nào gần mã máy.

Một trình biên dịch ghi phải hiểu đầu ra của chúng , nhưng đó thường không phải là mã máy.

Hầu hết các lập trình viên sẽ không bao giờ viết trình biên dịch xuất mã máy hoặc mã lắp ráp, nhưng trình biên dịch tùy chỉnh có thể rất hữu ích trên nhiều dự án để tạo ra các đầu ra khác.

YACC là một trình biên dịch như vậy không xuất ra mã máy.


0

Bạn không cần phải bắt đầu với kiến ​​thức chi tiết về ngữ nghĩa của ngôn ngữ đầu vào và đầu ra của mình, nhưng bạn nên hoàn thành tốt hơn với kiến ​​thức chi tiết tinh tế về cả hai, nếu không trình biên dịch của bạn sẽ bị lỗi một cách bất thường. Vì vậy, nếu đầu vào của bạn là C ++ và đầu ra của bạn là một số ngôn ngữ máy cụ thể, cuối cùng bạn sẽ cần phải biết ngữ nghĩa của cả hai.

Dưới đây là một số sự tinh tế trong việc biên dịch C ++ thành mã máy: (ngay trên đỉnh đầu của tôi, tôi chắc chắn có nhiều điều tôi đang quên.)

  1. Kích thước nào sẽ intlà? Lựa chọn "chính xác" ở đây là một nghệ thuật, dựa trên cả kích thước con trỏ tự nhiên của máy, hiệu suất của ALU cho các kích thước khác nhau của phép toán số học và các lựa chọn của trình biên dịch hiện có cho máy. Máy thậm chí có số học 64 bit? Nếu không thì việc thêm các số nguyên 32 bit sẽ dịch sang một lệnh trong khi thêm các số nguyên 64 bit sẽ dịch sang một lệnh gọi hàm để thực hiện phép cộng 64 bit. Máy có các hoạt động thêm 8 bit và 16 bit hay bạn phải mô phỏng những hoạt động với ops 32 bit và mặt nạ (ví dụ: DEC Alpha 21064)?

  2. Quy ước gọi được sử dụng bởi các trình biên dịch, thư viện và ngôn ngữ khác trên máy là gì? Các tham số có được đẩy trên ngăn xếp từ phải sang trái hoặc trái sang phải không? Có một số tham số đi vào thanh ghi trong khi những người khác đi trên ngăn xếp? Là ints và float trong không gian đăng ký khác nhau? Các tham số được cấp phát đăng ký có cần được xử lý đặc biệt đối với các cuộc gọi varargs không? Những thanh ghi nào được lưu trong cuộc gọi và được lưu callee? Bạn có thể thực hiện tối ưu hóa cuộc gọi lá?

  3. Mỗi hướng dẫn thay đổi của máy làm gì? Nếu bạn yêu cầu thay đổi một số nguyên 64 bit bằng 65 bit thì kết quả là gì? (Trên nhiều máy, kết quả tương tự như dịch chuyển 1 bit, trên các máy khác, kết quả là "0".)

  4. Các ngữ nghĩa nhất quán bộ nhớ của máy là gì? C ++ 11 có một ngữ nghĩa bộ nhớ được xác định rất rõ, đặt ra các hạn chế đối với một số tối ưu hóa trong một số trường hợp, nhưng cho phép tối ưu hóa trong các trường hợp khác. Nếu bạn đang biên dịch một ngôn ngữ không có ngữ nghĩa bộ nhớ được xác định rõ (như mọi phiên bản C / C ++ trước C ++ 11 và nhiều ngôn ngữ bắt buộc khác) thì bạn sẽ phải phát minh ra ngữ nghĩa bộ nhớ khi bạn đi cùng và thường bạn sẽ muốn phát minh ra ngữ nghĩa bộ nhớ phù hợp nhất với ngữ nghĩa máy của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.