2013-04-13 38 views
9

Gần đây tôi đã cố gắng đắm mình trong thế giới lập trình lắp ráp với mục tiêu cuối cùng là tạo ra ngôn ngữ lập trình của riêng tôi. Tôi muốn dự án thực sự đầu tiên của tôi là một trình biên dịch đơn giản được viết bằng C, có thể lắp ráp một phần rất nhỏ của ngôn ngữ máy x86 và tạo một tệp thực thi Windows. Không có macro, không có trình liên kết. Chỉ cần lắp ráp.Tôi muốn tạo một bộ lắp ráp đơn giản trong C. Tôi nên bắt đầu từ đâu?

Trên giấy, có vẻ như đủ đơn giản. Mã lắp ráp đi kèm, mã máy xuất hiện.

Nhưng ngay khi tôi nghĩ về tất cả các chi tiết, nó đột nhiên trở nên rất khó khăn. Các hệ điều hành nào yêu cầu hệ điều hành? Làm cách nào để căn chỉnh dữ liệu và tính toán các bước nhảy? Bên trong của một thực thi thậm chí trông như thế nào?

Tôi cảm thấy lạc lõng. Không có bất kỳ hướng dẫn về điều này mà tôi có thể tìm thấy và nhìn vào mã nguồn của lắp ráp phổ biến không phải là cảm hứng (tôi sẵn sàng thử lại, mặc dù).

Tôi nên đi đâu từ đây? Bạn đã làm điều đó như thế nào? Có hướng dẫn hay tài liệu hay về chủ đề này không?

+1

Điều gì đó cũng cần suy nghĩ: Tự động hữu hạn để kiểm tra xem người dùng có sử dụng hướng dẫn thích hợp không và bạn cũng sẽ cần một trình phân tích cú pháp để đảm bảo rằng lập trình viên viết là chính xác. Mặc dù có rất nhiều công cụ bên hệ thống bạn sẽ cần phải lo lắng về, cũng có rất nhiều Lý thuyết tính toán bạn sẽ cần phải biết là tốt. –

+1

Có lẽ bạn nên nghiên cứu một gói như [NASM] (http://www.nasm.us/). –

+0

xem [thử thách này trên sân gôn mã] (http://codegolf.stackexchange.com/questions/4732/emulate-an-intel-8086-cpu) cho 8086 tài nguyên và chương trình mẫu không quá ngắn bằng cách sử dụng tập hợp con của 8086 ở cả dạng nguồn và nhị phân. IMO Sổ tay năm 1979 là nơi bắt đầu. ... Ngoài ra hãy xem [câu hỏi wiki tài nguyên lắp ráp của tôi] (http://stackoverflow.com/a/7203667/), cụ thể là tệp "PDP-1_Macro.pdf" cung cấp một mô tả chi tiết về một trình biên dịch rất nguyên thủy . –

Trả lời

3

Điều bạn đang tìm kiếm không phải là hướng dẫn hoặc mã nguồn, đây là thông số . Xem http://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx

Khi bạn hiểu đặc điểm kỹ thuật của tệp thực thi, hãy viết chương trình để tạo tệp. Việc thực thi bạn xây dựng nên càng đơn giản càng tốt. Sau khi bạn đã nắm vững điều đó, rồi bạn có thể viết một trình phân tích cú pháp theo dòng đơn giản, đọc tên lệnh và đối số dạng số để tạo một khối mã để nhập vào exe. Sau đó, bạn có thể thêm biểu tượng, chi nhánh, phần, bất kỳ thứ gì bạn muốn và đó là nơi mà một cái gì đó như http://www.davidsalomon.name/assem.advertis/asl.pdf sẽ đến.

P.S. Carl Norum có một điểm tốt trong bình luận ở trên. Nếu mục tiêu của bạn là tạo ra ngôn ngữ lập trình của riêng bạn, việc học viết một trình lắp ráp là không liên quan và không phải là cách đúng đắn để bắt đầu (trừ khi ngôn ngữ bạn muốn tạo ra là một ngôn ngữ lắp ráp). Đã có các assembly tạo ra các file thực thi từ nguồn assembler, vì vậy trình biên dịch của bạn có thể tạo ra nguồn lắp ráp và bạn có thể tránh được công việc tái tạo assembly ... và bạn nên làm như vậy. Hoặc bạn có thể sử dụng một cái gì đó như LLVM, mà sẽ giải quyết nhiều vấn đề khó khăn khác của xây dựng trình biên dịch. Các tỷ lệ cược là rất nhỏ mà bạn sẽ bao giờ thực sự sản xuất ngôn ngữ lập trình của riêng bạn, nhưng chúng nhỏ hơn nhiều nếu bạn bắt đầu từ đầu và không cần phải. Quyết định mục tiêu của bạn là gì và sử dụng các công cụ tốt nhất có sẵn để đạt được mục tiêu đó.

4

Bạn nên xem LLVM, llvm là một trình biên dịch mô-đun kết thúc, đầu cuối phổ biến nhất là Clang để biên dịch C/C++/Objective-C. Điều tốt về LLVM là bạn có thể chọn một phần của chuỗi trình biên dịch mà bạn quan tâm và chỉ tập trung vào đó, bỏ qua tất cả những người khác. Bạn muốn tạo ngôn ngữ của riêng bạn, viết một trình phân tích cú pháp tạo mã đại diện nội bộ LLVM và miễn phí bạn sẽ có được tất cả các mục tiêu tối ưu hóa độc lập của lớp giữa và biên dịch cho nhiều mục tiêu khác nhau. Thú vị trong một trình biên dịch cho một số CPU lạ, viết một trình phụ trợ trình biên dịch có mã trung gian LLVM và tạo ra bộ sưu tập của bạn. Có một số ý tưởng về kỹ thuật tối ưu hóa, luồng tự động có lẽ, viết một lớp trung gian xử lý mã trung gian LLVM. LLVM là một bộ sưu tập các thư viện không phải là một nhị phân độc lập như GCC, và vì vậy nó rất dễ sử dụng trong các dự án của bạn.

11

Tôi đã viết một vài bản thân mình (bộ ghép và bộ tách rời) và tôi sẽ không bắt đầu bằng x86. Nếu bạn biết x86 hoặc bất kỳ tập lệnh nào khác, bạn có thể nhận và tìm hiểu cú pháp cho một lệnh khác được đặt theo thứ tự ngắn (một buổi tối/chiều), ít nhất là phần sư tử của nó.Hành động viết một bộ lắp ráp (hoặc disassembler) chắc chắn sẽ dạy cho bạn một bộ hướng dẫn, nhanh chóng, và bạn sẽ biết rằng hướng dẫn thiết lập tốt hơn nhiều lập trình viên dày dạn lắp ráp cho tập lệnh đó, người chưa kiểm tra microcode ở cấp đó. msp430, pdp11 và ngón tay cái (không phải phần mở rộng thumb2) (hoặc mips hoặc openrisc) là tất cả các địa điểm tốt để bắt đầu, không quá nhiều hướng dẫn, không quá phức tạp, v.v.

Tôi khuyên bạn nên tháo rời đầu tiên và Nếu không thì ít nhất hãy sử dụng bộ tách rời (chắc chắn chọn một bộ chỉ dẫn mà bạn đã có một bộ ghép, trình liên kết và bộ tách rời) và bằng bút chì và giấy hiểu mối quan hệ giữa mã máy và lắp ráp, đặc biệt là các nhánh, chúng thường có một hoặc nhiều quirks như bộ đếm chương trình là một lệnh hoặc hai phía trước khi bù đắp được thêm vào, để đạt được một bit khác đôi khi đo lường trong toàn bộ hướng dẫn không phải byte.

Khá dễ dàng để bạo lực phân tích văn bản bằng chương trình C để đọc hướng dẫn. Một nhiệm vụ khó hơn nhưng có lẽ là giáo dục, sẽ sử dụng bison/flex và học ngôn ngữ lập trình đó để cho phép những công cụ tạo ra (một trình phân tích cú pháp mạnh hơn) sau đó giao tiếp với mã của bạn để cho bạn biết những gì đã được tìm thấy ở đâu.

Trình tự lắp ráp khá thẳng về phía trước, chỉ cần đọc ascii và đặt các bit trong mã máy. Các nhánh và các hướng dẫn tương đối khác của máy tính có một chút đau đớn hơn khi chúng có thể thực hiện nhiều lần truyền qua các nguồn/bảng để hoàn toàn giải quyết.

mov r0,r1 
    mov r2 ,#1 

assembler bắt đầu phân tích các văn bản cho một dòng (được định nghĩa là các byte theo sau một trở về vận chuyển 0xD hoặc đường dây ăn 0xA), loại bỏ các khoảng trắng (số lượng và tab) cho đến khi bạn có được một cái gì đó không trắng không gian, sau đó strncmp với các bộ nhớ đã biết. nếu bạn nhấn một cú pháp thì có thể phân tích các kết hợp có thể có của lệnh đó, trong trường hợp đơn giản ở trên sau khi bỏ qua vùng trắng sang không gian trắng, có lẽ điều đầu tiên bạn tìm thấy phải là thanh ghi, sau đó là khoảng trắng tùy chọn, dấu phẩy. loại bỏ khoảng trắng và dấu phẩy và so sánh nó với một bảng chuỗi hoặc chỉ phân tích cú pháp thông qua nó. Sau khi đăng ký được thực hiện sau đó đi qua nơi dấu phẩy được tìm thấy và cho phép nói nó là một trong hai đăng ký hoặc ngay lập tức. Nếu ngay lập tức cho phép nói rằng nó phải có một dấu #, nếu đăng ký cho phép nói rằng nó đã bắt đầu với một trường hợp thấp hơn hoặc trên 'r'. sau khi phân tích cú pháp đăng ký hoặc ngay lập tức, sau đó đảm bảo không có gì khác trên dòng mà không nên trên dòng. xây dựng mã máy cho hướng dẫn này hoặc ít nhất là nhiều nhất có thể, và chuyển sang dòng tiếp theo. Nó có thể tẻ nhạt nhưng không khó phân tích cú pháp ascii ...

ở mức tối thiểu bạn sẽ muốn bảng/mảng tích lũy mã/dữ liệu máy khi được tạo, cộng với một số phương pháp để đánh dấu hướng dẫn là không đầy đủ , các hướng dẫn liên quan đến máy tính sẽ được hoàn tất trên một thẻ trong tương lai. bạn cũng sẽ muốn một bảng/mảng thu thập các nhãn bạn tìm thấy và địa chỉ/offset trong bảng mã máy nơi tìm thấy. Cũng như các nhãn được sử dụng trong lệnh như là một điểm đến/nguồn và bù đắp trong bảng/mảng giữ hướng dẫn hoàn thành một phần họ đi với. sau lần vượt qua đầu tiên, sau đó quay lại các bảng này cho đến khi bạn kết hợp tất cả các định nghĩa nhãn với các nhãn được sử dụng làm nguồn hoặc đích, sử dụng địa chỉ/độ phân giải nhãn để tính khoảng cách cho lệnh được đề cập và sau đó kết thúc việc tạo mã máy cho lệnh đó. (một số tháo gỡ có thể được yêu cầu và/hoặc sử dụng một số phương pháp khác để ghi nhớ loại mã hóa nó là khi bạn quay trở lại nó sau này để hoàn thành việc xây dựng mã máy).

Bước tiếp theo là cho phép nhiều tệp nguồn, nếu đó là thứ bạn muốn cho phép. Bây giờ bạn phải có các nhãn không được giải quyết bởi trình biên dịch, do đó bạn phải để lại phần giữ chỗ trong đầu ra và tạo ra một số hương vị của lệnh nhảy/chi nhánh dài nhất bởi vì bạn không biết đích đến xa như thế nào, mong đợi tồi tệ hơn.Sau đó, có định dạng tệp đầu ra bạn chọn để tạo/sử dụng, sau đó có trình liên kết mà chủ yếu là đơn giản, nhưng bạn phải nhớ điền mã máy cho hướng dẫn tương đối máy tính cuối cùng, không khó hơn so với trong bộ lắp ráp chinh no.

Lưu ý, việc viết một trình biên dịch không nhất thiết liên quan đến việc tạo một ngôn ngữ lập trình và sau đó viết trình biên dịch cho nó, điều riêng biệt, các vấn đề khác nhau. Trên thực tế, nếu bạn muốn tạo một ngôn ngữ lập trình mới, chỉ cần sử dụng một bộ ghép hiện có cho một tập lệnh hiện có. Dĩ nhiên, hầu hết các giáo lý và hướng dẫn đều sử dụng cách tiếp cận bison/flex cho ngôn ngữ lập trình, và có rất nhiều bài giảng/tài nguyên giảng dạy đại học ở đó để bắt đầu các lớp trình biên dịch mà bạn có thể sử dụng để bắt đầu sau đó sửa đổi kịch bản để thêm các tính năng của ngôn ngữ của bạn. Các đầu giữa và mặt sau là thách thức lớn hơn so với giao diện người dùng. có rất nhiều sách về chủ đề này và nhiều tài nguyên trực tuyến. Như đã đề cập trong một câu trả lời khác llvm không phải là một nơi tồi tệ để tạo ra một ngôn ngữ lập trình mới giữa và phụ trợ được thực hiện cho bạn, bạn chỉ cần tập trung vào chính ngôn ngữ lập trình, giao diện người dùng.

Các vấn đề liên quan