2011-09-04 47 views
31

Tôi luôn đọc những điều về cách các chức năng nhất định trong ngôn ngữ lập trình C được tối ưu hóa bằng cách được viết trong assembly. Hãy để tôi xin lỗi nếu câu đó có vẻ hơi sai lầm.Mã C gọi mã lắp ráp (ví dụ: strlen được tối ưu hóa) như thế nào?

Vì vậy, tôi sẽ nói rõ ràng: Làm thế nào khi bạn gọi một số chức năng như strlen trên hệ thống UNIX/C, chức năng thực tế bạn đang gọi được viết bằng assembly? Bạn có thể viết assembly ngay vào chương trình C bằng cách nào đó hay nó là một tình huống gọi bên ngoài? Nó là một phần của tiêu chuẩn C để có thể làm điều này, hoặc nó là một hệ điều hành cụ thể điều?

+0

Một trong những phần thông tin quan trọng nhất bạn cần là mô tả về cách trình biên dịch C của bạn chuyển các đối số và trả về địa chỉ cho một chương trình con. Điều này được gọi là "quy ước gọi điện" cho máy hoặc bộ xử lý đó. Ví dụ, nó là điển hình trên x86 để truyền các đối số và trả về địa chỉ bằng cách sử dụng ngăn xếp. Điều này chỉ có thể làm việc cho các hàm đối số biến nếu các đối số được đẩy vào ngăn xếp theo thứ tự từ phải sang trái, sau đó địa chỉ trả về được đẩy. Nếu bạn viết chức năng ngôn ngữ lắp ráp của bạn để mong đợi bố cục ngăn xếp này ("bản ghi kích hoạt"), thì chỉ quan trọng là ... –

+0

... thực hiện bổ sung là chức năng asm của bạn, sau khi được lắp ráp và liên kết, được gán một địa chỉ phân đoạn mã chương trình của bạn. Do đó, mã C của bạn có thể truyền thực thi bộ xử lý đến địa chỉ này của hàm asm của bạn. Tại thời điểm đó, miễn là chức năng của bạn thực hiện đúng với thanh ghi (một số phải được giữ nguyên cho người gọi, chẳng hạn như EBP), biết cách tìm đối số và trả về địa chỉ trên ngăn xếp và trả về kết quả của nó ở đúng vị trí (Giá trị trả về 32 bit có trong EAX trên x86), sau đó không có gì về việc loại bỏ giá trị đó. –

Trả lời

34

Chuẩn C quy định những gì mà mỗi hàm thư viện phải làm thay vì cách nó được triển khai.

Hầu như tất cả các triển khai C được biết đều được biên dịch sang ngôn ngữ máy. Nó phụ thuộc vào những người triển khai trình biên dịch/thư viện C cách họ chọn để thực hiện các chức năng như strlen. Họ có thể chọn để thực hiện nó trong C và biên dịch nó cho một đối tượng, hoặc họ có thể chọn để viết nó trong lắp ráp và lắp ráp nó vào một đối tượng. Hoặc họ có thể thực hiện nó theo một cách khác. Nó không quan trọng miễn là bạn nhận được hiệu quả đúng và kết quả khi bạn gọi strlen.

Bây giờ, khi nó xảy ra, nhiều bộ công cụ C cho phép bạn viết lắp ráp nội tuyến, nhưng đó hoàn toàn không phải là một phần của tiêu chuẩn. Bất kỳ facilties như vậy phải được bao gồm như là phần mở rộng cho tiêu chuẩn C.

+0

Cảm ơn bạn rất nhiều :) đã xóa nó rất nhiều cho tôi. –

+2

Để lưu ý: nếu các hàm như 'strlen' được viết trong assembly thay vì C, nó thường được thực hiện vì lý do hiệu suất. –

17

Ở cuối đường, các chương trình và chương trình được biên dịch thành lắp ráp là tất cả ngôn ngữ máy, để chúng có thể gọi cho nhau. Cách này được thực hiện bằng cách sử dụng mã assembly sử dụng cùng một quy ước gọi (cách chuẩn bị cho cuộc gọi, chuẩn bị các thông số và như vậy) như chương trình được viết bằng C. Tổng quan về các quy ước gọi phổ biến cho bộ vi xử lý x86 có thể được tìm thấy here.

+4

Đối với x86 [Hướng dẫn tối ưu hóa Agner Fogs] (http://www.agner.org/optimize/optimizing_assembly.pdf) cũng là một tham chiếu hữu ích. – user786653

+0

@user liên kết tuyệt vời, cảm ơn! – fvu

0

Bạn có thể viết lắp ráp nội tuyến vào mã C của mình. Cú pháp cho điều này là cao trình biên dịch cụ thể nhưng từ khóa asm được sử dụng một cách ususally. Nhìn vào lắp ráp nội tuyến để biết thêm thông tin.

4

Khi mã C được biên dịch bởi gcc, trước tiên nó được biên dịch thành các hướng dẫn lắp ráp, sau đó được biên dịch lại thành tệp nhị phân, máy thực thi. Bạn có thể xem hướng dẫn lắp ráp được tạo bằng cách chỉ định -S, như trong gcc file.c -S.

Assembler mã chỉ vượt qua giai đoạn đầu tiên của C-to-lắp ráp biên soạn và sau đó không thể phân biệt từ mã được biên soạn từ C.

+4

Một cách để thực hiện một hàm trong assembly là viết một hàm C trống, biên dịch nó bằng -S, sau đó chỉnh sửa trực tiếp tệp assembly. – Giorgio

1

Một cách để làm điều đó là sử dụng lắp ráp nội tuyến. Điều đó có nghĩa là bạn có thể viết mã assembly trực tiếp vào mã C của bạn. Cú pháp cụ thể là trình biên dịch cụ thể. Ví dụ: xem GCC syntaxMS Visual C++ syntax.

8

Nhiều trình biên dịch C (hầu hết?) Xuất hiện để hỗ trợ inline assembly, mặc dù nó không phải là một phần của tiêu chuẩn. Điều đó nói rằng, không có nhu cầu nghiêm ngặt cho một trình biên dịch để hỗ trợ bất kỳ điều như vậy.

Đầu tiên, hãy nhận ra rằng cụm máy chủ yếu chỉ là mã máy có thể đọc được (con người) và C cũng kết thúc dưới dạng mã máy.

"Gọi" hàm C chỉ tạo ra một bộ hướng dẫn chuẩn bị sổ đăng ký, ngăn xếp và/hoặc một số cơ chế phụ thuộc máy khác theo quy ước gọi điện được thiết lập và sau đó nhảy đến đầu hàm được gọi.

Một khối mã lắp ráp có thể phù hợp với quy ước gọi thích hợp, và do đó tạo ra một blob mã máy mà một mã màu khác của mã máy được viết ban đầu trong C có thể gọi. Ngược lại, tất nhiên, cũng có thể.

Chi tiết về quy ước gọi điện, quy trình lắp ráp và quy trình liên kết (để liên kết tệp đối tượng được tạo với tệp đối tượng C tạo) có thể thay đổi một cách dữ dội giữa các nền tảng, trình biên dịch và trình liên kết. Một hướng dẫn lắp ráp tốt cho nền tảng lựa chọn của bạn có thể sẽ bao gồm các chi tiết như vậy.

Tôi tình cờ thích trung tâm x86 PC Assembly Tutorial, cụ thể là địa chỉ giao tiếp hội tụ và mã C.

+0

Hướng dẫn thú vị, cảm ơn sự giúp đỡ :) –

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