Hiểu khung stack của lệnh gọi hàm trong C / C ++?


19

Tôi đang cố gắng hiểu làm thế nào các khung stack được xây dựng và các biến (params) nào được đẩy để stack theo thứ tự nào? Một số kết quả tìm kiếm cho thấy trình biên dịch C / C ++ quyết định dựa trên các hoạt động được thực hiện trong một hàm. Ví dụ, nếu hàm được cho là chỉ tăng giá trị int được truyền lên 1 (tương tự toán tử ++) và trả về nó, nó sẽ đặt tất cả các tham số của hàm và biến cục bộ vào các thanh ghi.

Tôi đang tự hỏi những thanh ghi nào được sử dụng để trả về hoặc chuyển qua các tham số giá trị. Tài liệu tham khảo được trả về như thế nào? Làm thế nào để trình biên dịch chọn giữa eax, ebx, ecx và edx?

Tôi cần biết gì để hiểu cách các thanh ghi, ngăn xếp và tham chiếu heap được sử dụng, xây dựng và hủy trong các lệnh gọi hàm?


Điều này khá khó đọc (bức tường của văn bản). Bạn có phiền chỉnh sửa bài viết của bạn thành một hình dạng tốt hơn?
gnat

1
Câu hỏi này có vẻ khá rộng đối với tôi. Ngoài ra, đây sẽ không phải là rất cụ thể nền tảng?
Kazark

Câu hỏi cũng được hỏi trên SO: stackoverflow.com/questions/16088040/ trộm
Wayne Conrad

Câu trả lời:


11

Ngoài những gì Dirk đã nói, một công dụng quan trọng của khung stack là lưu các giá trị trước đó của các thanh ghi để chúng có thể được khôi phục sau khi gọi hàm. Vì vậy, ngay cả trên các bộ xử lý nơi các thanh ghi được sử dụng để truyền tham số, trả về giá trị và lưu địa chỉ trả về, các giá trị của các thanh ghi đó được lưu trên ngăn xếp trước khi gọi hàm để chúng có thể được khôi phục sau cuộc gọi. Điều này cho phép một hàm gọi hàm khác mà không ghi đè các tham số của chính nó hoặc quên địa chỉ trả về của chính nó.

Vì vậy, việc gọi hàm B từ hàm A trên hệ thống "chung" điển hình có thể bao gồm các bước sau:

  • chức năng A:
    • đẩy không gian cho giá trị trả về
    • thông số đẩy
    • đẩy địa chỉ trả lại
  • nhảy đến hàm B
  • chức năng B:
    • đẩy địa chỉ của khung stack trước
    • đẩy giá trị của các thanh ghi mà hàm này sử dụng (để chúng có thể được phục hồi)
    • đẩy không gian cho các biến cục bộ
    • làm các tính toán cần thiết
    • khôi phục các thanh ghi
    • khôi phục khung ngăn xếp trước đó
    • lưu trữ kết quả chức năng
    • nhảy đến địa chỉ
  • chức năng A:
    • bật các tham số
    • bật giá trị trả về

Đây không phải là cách duy nhất mà các lệnh gọi hàm có thể hoạt động (và tôi có thể có một hoặc hai bước không theo thứ tự), nhưng nó sẽ cho bạn ý tưởng về cách ngăn xếp được sử dụng để cho bộ xử lý xử lý các lệnh gọi hàm lồng nhau.


"Đẩy" chính xác có nghĩa là gì ở đây? Tôi không có ý tưởng gì để làm cho nó.
Tomáš Zato - Phục hồi Monica

2
@ TomášZato pushpoplà hai hoạt động cơ bản trên một ngăn xếp. Một chồng là một cấu trúc từ trước đến trước, giống như một chồng sách. Khi bạn push, bạn đang đặt một đối tượng mới lên trên ngăn xếp; khi bạn poplấy một vật từ đỉnh ngăn xếp. Bạn không được phép chèn hoặc xóa các đối tượng ở giữa, bạn chỉ có thể hoạt động trên đỉnh của ngăn xếp. Bạn có thể đọc thêm về ngăn xếp nói chung và ngăn xếp chương trình nói riêng trên Wikipedia.
Caleb

11

Điều này phụ thuộc vào quy ước gọi đang được sử dụng. Bất cứ ai xác định quy ước gọi có thể đưa ra quyết định này theo cách họ muốn.

Trong quy ước gọi phổ biến nhất trên x86, các thanh ghi không được sử dụng để truyền tham số; các tham số được đẩy vào ngăn xếp bắt đầu bằng tham số ngoài cùng bên phải. Giá trị trả về được đặt trong eax và có thể sử dụng edx nếu nó cần thêm không gian. Các tham chiếu và con trỏ đều được trả về dưới dạng một địa chỉ trong eax.


5

Nếu bạn hiểu rất rõ về stack thì bạn sẽ hiểu bộ nhớ hoạt động như thế nào trong chương trình và nếu bạn hiểu cách bộ nhớ hoạt động trong chương trình, bạn sẽ hiểu cách lưu trữ chức năng trong chương trình và nếu bạn hiểu cách lưu trữ chức năng trong chương trình, bạn sẽ hiểu chức năng đệ quy hoạt động như thế nào và nếu bạn hiểu chức năng đệ quy hoạt động như thế nào bạn sẽ hiểu cách trình biên dịch hoạt động và nếu bạn hiểu cách trình biên dịch hoạt động, tâm trí của bạn sẽ hoạt động như trình biên dịch và bạn sẽ gỡ lỗi bất kỳ chương trình nào rất dễ dàng

Hãy để tôi giải thích cách stack hoạt động:

Trước tiên, bạn phải biết cách lưu trữ hàm trong stack:

Heap lưu trữ các giá trị cấp phát bộ nhớ động. Ngăn xếp lưu trữ tự động phân bổ và xóa giá trị.

nhập mô tả hình ảnh ở đây

Hãy hiểu ví dụ:

def hello(x):
    if x==1:
        return "op"
    else:
        u=1
        e=12
        s=hello(x-1)
        e+=1
        print(s)
        print(x)
        u+=1
    return e

hello(4)

Bây giờ hãy hiểu các phần của chương trình này:

nhập mô tả hình ảnh ở đây

Bây giờ hãy xem stack là gì và các phần stack là gì:

nhập mô tả hình ảnh ở đây

Phân bổ ngăn xếp:

Hãy nhớ một điều nếu bất kỳ chức năng nào nhận được trở lại của Google, bất kể nó đã tải tất cả các biến địa phương của anh ta hay bất cứ thứ gì nó sẽ ngay lập tức trở về từ ngăn xếp của anh ta. Điều đó có nghĩa là khi bất kỳ hàm đệ quy nào nhận được điều kiện cơ sở và chúng ta đặt trả về sau điều kiện cơ sở để điều kiện cơ sở sẽ không chờ để tải các biến cục bộ nằm trong một phần khác của chương trình, nó sẽ ngay lập tức trả về khung hiện tại từ ngăn xếp và bây giờ nếu một khung Trả lại khung tiếp theo là trong hồ sơ kích hoạt. Xem điều này trong thực tế:

nhập mô tả hình ảnh ở đây

Giao dịch của khối:

Vì vậy, bây giờ bất cứ khi nào một hàm tìm thấy câu lệnh return, nó sẽ xóa khung hiện tại khỏi ngăn xếp.

trong khi trả về từ giá trị ngăn xếp sẽ trả về thứ tự ngược lại theo thứ tự mà chúng được phân bổ trong ngăn xếp.

nhập mô tả hình ảnh ở đây

Đây là những mô tả rất ngắn và nếu bạn muốn biết sâu hơn về stack và đệ quy kép, hãy đọc hai bài đăng của blog này:

Tìm hiểu thêm về ngăn xếp từng bước

Tìm hiểu thêm về đệ quy đôi từng bước với ngăn xếp


3

Những gì bạn đang tìm kiếm được gọi là Giao diện nhị phân ứng dụng - ABI.

Có một đặc điểm kỹ thuật cho mỗi trình biên dịch đánh vần ABI.

Mỗi nền tảng thường sẽ chỉ định và ABI theo thứ tự để hỗ trợ khả năng tương tác giữa các trình biên dịch. Ví dụ, các quy ước gọi x86 đánh vần các quy ước gọi thông thường cho x86 và x86-64. Tuy nhiên, tôi mong đợi một tài liệu chính thức hơn wikipedia.

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.