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

Gọi scanf trong X64 gcc asm nội tuyến

In lại Tác giả: Vũ trụ không gian Thời gian cập nhật: 2023-11-04 10:09:57 hai mươi bốn 4
mua khóa gpt4 Nike

Tôi có một mảng int 2d được phân bổ động được gọi là hình ảnh và một chuỗi định dạng được gọi là định dạng. Sau đó, tôi sử dụng hai vòng lặp for lồng nhau để lấy đầu vào từ đầu vào tiêu chuẩn và lưu trữ chúng trong một mảng 2D. Vì vậy, tôi có thể phân tích động các số nguyên từ đầu vào có độ dài khác nhau. Ví dụ: nếu tôi có mảng 2D 3x3, tôi sẽ cần sử dụng tập hợp nội tuyến để đẩy địa chỉ của phần tử trong mảng 9 lần rồi đẩy nó vào chuỗi định dạng. Sau đó tôi gọi scanf và cân bằng ngăn xếp khi hoàn thành.

BTW: Giả sử chiều rộng và chiều cao của mảng đã biết.

Đây là mã của tôi trên Windows (hệ thống X64, được biên dịch thành mã x32). Nó hoạt động tốt.

for (int i = 0; i < chiều cao; i++) {
for (int j = width-1; j >=0; j--) {
int tmp_addr = (int)&image[i][j];
__asm ​​​​đẩy tmp_addr;
}
int pop_size = (width+1) * 4;
__asm ​​​​{
định dạng đẩy;
gọi func_scanf;
mov read_size, eax;
thêm đặc biệt, pop_size;
}
}

Khi được chuyển sang Linux (hệ thống X64, mã X64 được biên dịch), mã không chạy.

for (int i = 0; i < chiều cao; i++) {
for (int j = width-1; j >=0; j--) {
dài tmp_addr = (dài)&image[i][j];
//__asm ​​​​đẩy tmp_addr;
__asm__ __dễ bay hơi__(
"đẩy %0\n\t"
::"g"(tmp_addr)
);
}

int pop_size = (width+1) * sizeof(dài);
/*__asm ​​​​{
định dạng đẩy;
gọi func_scanf;
mov read_size, eax;
thêm đặc biệt, pop_size;
}*/
__asm__ __dễ bay hơi__(
"đẩy %0\n\t"
"gọi *%1\n\t"
"di chuyển %%rax,%2\n\t"
"thêm %3,%%rsp"
::"g"(format),"g"(func_scanf),"g"(read_size),"g"(pop_size)
:"%rax","%rsp"
);
}

Một segfault xảy ra khi thực thi mã này. Điều gì có thể xảy ra? Cảm ơn!

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

sử dụng mã x86_64 trên Linux một quy ước gọi điện hoàn toàn kháchơn mã x86 trên Windows. Đặc biệt, nó sẽ cố gắng truyền nhiều tham số vào các thanh ghi trước khi bắt đầu sử dụng ngăn xếp. Ngoài ra, có một số quy tắc bổ sung tinh tế cho các biến thể (ví dụ: bạn phải sử dụng chuột chũi Chỉ định số lượng thanh ghi XMM thực sự được sử dụng hoặc 0 nếu không được sử dụng).

quét Mong muốn tìm thấy sáu đối số con trỏ đầu tiên trong các thanh ghi, nhưng bạn đặt chúng vào ngăn xếp và các thanh ghi chứa các giá trị rác (bất kể điều gì xảy ra ở đó tại thời điểm gọi khi bất kỳ đối số nào trong số chúng bị hủy đăng ký để ghi); đọc các giá trị, bạn nhận được Đã gặp phải lỗi segfault.

Hơn nữa, các trình biên dịch hiện đại thường không sử dụngrbp Các biến và tham số cục bộ được truy cập dưới dạng con trỏ khung.rsp Truy cập các biến cục bộ. Khi bạn đẩy, bạn di chuyển con trỏ ngăn xếp mà trình biên dịch không biết và bây giờ mọi truy cập ngăn xếp giữa lần đẩy của bạn và trả về lệnh gọi hàm sẽ bị hỏng. Bạnhãy cố gắng cầm trình biên dịch xung quanh cái này , nhưng đó là một thứ bẩn thỉu và dễ bị hỏng.

Tệ hơn nữa: nếu gcc cho rằng hàm của bạn là hàm lá (nó có thể nghĩ như vậy nếu lệnh gọi hàm duy nhất nằm trong mã hợp ngữ của bạn, mã này không rõ ràng đối với trình biên dịch) thì có thể nó đang khai thác vùng đỏ , đặt nội dung vào rsp dưới giá trị hiện tại. Các lần đẩy và gọi hàm của bạn có thể ghi đè lên dữ liệu này. Bạncó thể cố gắng chiến đấu ngay cả điều này , nhưng một lần nữa, đây là thứ xấu xí.

Vì vậy: rõ ràng tại sao mã của bạn không hoạt động và rõ ràng việc làm cho nó hoạt động chính xác theo quy ước gọi x86_64 khá phức tạp - bạn phải đặt mọi thứ vào các thanh ghi khác nhau hoặc trên ngăn xếp, tùy thuộc vào lần lặp và tìm Một cách để nói với gcc rằng bạn đang làm rối con trỏ ngăn xếp và tránh sử dụng vùng màu đỏ.

Điều tôi không biết là: Mục đích của việc này là gì? Nếu cần đọc nhiều giá trị, bạn có thể thực hiện trong pure C nếu số lượng giá trị cố định quét cuộc gọi "bình thường". Thay vào đó, nếu số lượng giá trị cần đọc chỉ được biết trong thời gian chạy, thì có vẻ như từ nhận xét của bạn rằng

Nó giống như "%d %d %d ...."và thay đổi độ dài của nó một cách linh hoạt.

Chỉ cần gọi nó nhiều lần quét Và sử dụng chuỗi định dạng phù hợp để đọc một giá trị:

for (int i = 0; i < chiều cao; i++) {
for (int j = 0; j < chiều rộng; j++) {
scanf("%d", &image[i][j]);
}
}

Điều này sẽ có ngữ nghĩa chính xác giống như mã của bạn (trên nền tảng mà nó chạy trên đó). Nhân tiện, hãy thêm một số cách xử lý lỗi (= kiểm tra quét giá trị trả về), chương trình của bạn sẽ ngừng đọc khi gặp giá trị không hợp lệ và tiếp tục sử dụng giá trị chưa được khởi tạo trong hình ảnh<.

Nếu bạn gặp vấn đề về hiệu suất, hãy từ bỏ quét - Bạn có thể thực hiện việc này bằng cách viết mã tokenization theo cách thủ công rồi gọi strtol Dễ dàng đánh bại nó; bằng cách mã hóa thủ công sự chuyển đổi mà bạn thậm chí có thể đánh bại strtol Nhanh hơn (nếu bạn không quan tâm đến ngôn ngữ).

Trong mọi trường hợp, hãy đi sâu vào cấp độ lắp ráp để xây dựng cặp quét Cuộc gọi có thể thay đổi là một giải pháp kém, không khả thi cho vấn đề.

Về việc gọi scanf trong X64 gcc asm nội tuyến, 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/49723621/

hai mươi bốn 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