cuốn sách gpt4 ai đã làm

Cuộc gọi chức năng lắp ráp này có an toàn/hoàn chỉnh không?

In lại Tác giả: Vũ trụ không gian Thời gian cập nhật: 2023-11-04 04:30:15 32 4
mua khóa gpt4 Nike

Tôi không có kinh nghiệm lắp ráp, nhưng đây là những gì tôi đã và đang làm. Nếu thiếu bất kỳ khía cạnh cơ bản nào khi truyền tham số và gọi hàm thông qua con trỏ trong hợp ngữ, thì tôi muốn có đầu vào.
Ví dụ, tôi muốn biết liệu tôi có nên hoàn nguyênngoại hối,edx,esi,biên tập, . Tôi đọc được rằng chúng là những thanh ghi có mục đích chung nhưng tôi không thể tìm thấy chúng. Tôi có nên làm gì để dọn dẹp sau cuộc gọi không?
Đây là mã hiện tại của tôi và nó thực sự hoạt động:

#include "stdio.h"

void foo(int a, int b, int c, int d)
{
printf("giá trị = %d và %d và %d và %d\r\n", a, b, c, d);
}

int main()
{

int a=3,b=6,c=9,d=12;
__asm__(
"di chuyển %3, %%ecx;"
"di chuyển %2, %%edx;"
"di chuyển %1, %%esi;"
"di chuyển %0, %%edi;"
"gọi %4;"
:
: "g"(a), "g"(b), "g"(c), "g"(d), "a"(foo)
);

}

câu trả lời hay nhất

Câu hỏi ban đầu làCuộc gọi chức năng lắp ráp này có an toàn/hoàn chỉnh không?. Câu trả lời là: không. Mặc dù nó có vẻ hoạt động trong ví dụ đơn giản này (đặc biệt khi tính năng tối ưu hóa bị vô hiệu hóa), nhưng bạn đang vi phạm các quy tắc (những quy tắc khó tìm) mà cuối cùng sẽ gây ra lỗi.
Tôi muốn giải quyết câu hỏi tiếp theo (rõ ràng) về cách đảm bảo an toàn, nhưng tôi thực sự không thể làm điều đó nếu không có phản hồi của nhà điều hành về mục đích thực tế.
Vì vậy, tôi sẽ cố gắng hết sức với những gì chúng tôi có và cố gắng mô tả những điều khiến nó không an toàn cũng như một số điều bạn có thể làm để giải quyết vấn đề đó.
Hãy bắt đầu bằng cách đơn giản hóa asm:

 __asm__(
"di chuyển %0, %%edi;"
:
: "g"(a)
);

Ngay cả với câu lệnh duy nhất này, mã này đã không an toàn. Tại sao? Bởi vì chúng ta thay đổi giá trị của một thanh ghi (edi) mà không cho trình biên dịch biết.
Làm sao trình biên dịch không biết bạn đang hỏi? Rốt cuộc thì nó ở đó! Câu trả lời đến từ tài liệu gccDòng này trong:
GCC không tự phân tích các hướng dẫn của trình biên dịch mã, cũng như không
Biết ý nghĩa của chúng và thậm chí liệu chúng có phải là đầu vào hợp lệ của trình biên dịch mã hay không.
Trong trường hợp này, làm cách nào để bạn cho GCC biết chuyện gì đang xảy ra? Câu trả lời nằm ở việc sử dụng các ràng buộc (cái đứng sau dấu hai chấm) để mô tả tác động của asm.
Có lẽ cách dễ nhất để sửa mã này là như sau:
  __asm__(
"di chuyển %0, %%edi;"
:
: "g"(a)
: biên tập
);

Điều này sẽ thêm edi vào danh sách người làm hỏng việcở giữa. Nói tóm lại, điều này cho GCC biết rằng giá trị của EDI sẽ được mã thay đổi và GCC không nên cho rằng bất kỳ giá trị cụ thể nào sẽ xuất hiện khi ASM thoát.
Bây giờ, mặc dù đây là cách đơn giản nhất nhưng nó có thể không nhất thiết là cách tốt nhất. Hãy xem xét đoạn mã sau:
  __asm__(
""
:
: "D"(a)
);

nó sử dụng hạn chế máyYêu cầu gcc thay đổi biến MộtGiá trị được đặt trong thanh ghi edi. Làm điều này, gcc sẽ tải sổ đăng ký cho bạn khi nó "thuận tiện", có thể bằng cách luôn đặt MộtLưu trong edi.
Mã này có một cảnh báo (quan trọng): bằng cách đặt tham số sau dấu hai chấm thứ hai, chúng tôi khai báo nó là đầu vào. Các tham số đầu vào cần phải ở dạng chỉ đọc (tức là chúng phải có cùng giá trị khi thoát ASM).
Trong trường hợp của bạn, gọi có nghĩa là chúng tôi không đảm bảo rằng edi sẽ không bị thay đổi, vì vậy điều này không hiệu quả lắm. Có một số cách để giải quyết vấn đề này. Cách đơn giản nhất là di chuyển ràng buộc lên sau dấu hai chấm đầu tiên, biến nó thành đầu ra và chỉ định "+D"để chỉ ra rằng giá trị là đọc + ghi. Tuy nhiên, sau asm, MộtNội dung của sẽ gần như không được xác định (printf có thể đặt nó thành bất kỳ giá trị nào). nếu bị phá hủy Mộtkhông thể chấp nhận được, luôn có những tình huống như thế này:
int rác;
__asm__ dễ bay hơi (
""
: "=D" (rác)
: "0"(a)
);

Điều này cho gcc biết rằng khi bắt đầu asm, nó sẽ thay đổi giá trị biến thành MộtĐặt nó ở cùng vị trí với ràng buộc đầu ra 0 (edi). Nó cũng nói rằng ở đầu ra, edi sẽ không còn Một, sẽ chứa các biến rác.
EDIT: Vì biến "rác" thực sự không được sử dụng nên chúng ta cần thêm bay hơiVòng loại. Dễ bay hơi là ẩn mà không có bất kỳ tham số đầu ra nào.
Một điểm khác trên dòng đó: kết thúc bằng dấu chấm phẩy. Điều này là hợp pháp và sẽ hoạt động như mong đợi. Tuy nhiên, nếu bạn muốn sử dụng -Stùy chọn dòng lệnh để xem chính xác mã nào đã được tạo (nếu bạn muốn sử dụng tốt asm nội tuyến, bạn sẽ thấy rằng điều này tạo ra mã khó đọc. Tôi khuyên bạn nên sử dụng \n\tThay thế dấu chấm phẩy.
Tất cả những điều này và chúng tôi vẫn đang ở tuyến đầu. . .
Rõ ràng điều tương tự cũng áp dụng cho hai cái còn lại di chuyểntuyên bố.
Điều này dẫn đến gọi tuyên bố.
Michael và tôi đều liệt kê một số lý do khiến việc gọi asm nội tuyến lại khó khăn.
Xử lý tất cả các thanh ghi có thể bị hỏng do ABI của lệnh gọi hàm.
Xử lý các khu vực màu đỏ.
Xử lý căn chỉnh.
Sốc trí nhớ.
Nếu mục tiêu ở đây là "học tập" thì hãy thử nó. Nhưng tôi không biết liệu mình có cảm thấy thoải mái khi làm điều này trong mã sản xuất hay không. Ngay cả khi nó có vẻ hiệu quả, tôi cũng không tự tin rằng mình sẽ không bỏ lỡ một trường hợp kỳ lạ nào đó. Điều này phù hợp với những gì tôi thường quan tâm hoàn toàn sử dụng asm nội tuyến无关。
Tôi biết, đó là rất nhiều thông tin. như gcc asmCó thể có nhiều mệnh lệnh hơn bạn mong đợi nhưng bạn đã chọn một điểm khởi đầu đầy thử thách.
Nếu bạn chưa làm như vậy, hãy dành thời gian xem gcc Giao diện ngôn ngữ hộiTất cả các tài liệu ở định dạng . Có rất nhiều thông tin hữu ích ở đây và một số ví dụ giải thích cách thức hoạt động của nó.

Về c - Cuộc gọi chức năng lắp ráp này có an toàn/hoàn chỉnh không? , chúng tôi đã tìm thấy một câu hỏi tương tự trên Stack Overflow: https://stackoverflow.com/questions/37156743/

32 4 0
không gian vũ trụ
Hồ sơ

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá taxi Didi miễn phí
Phiếu giảm giá taxi Didi
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress