Mục đích của thanh ghi con trỏ khung EBP là gì?


94

Tôi là người mới bắt đầu sử dụng hợp ngữ và nhận thấy rằng mã x86 được phát ra bởi các trình biên dịch thường giữ con trỏ khung xung quanh ngay cả trong chế độ phát hành / tối ưu hóa khi nó có thể sử dụng thanh EBPghi cho thứ khác.

Tôi hiểu tại sao con trỏ khung có thể giúp mã gỡ lỗi dễ dàng hơn và có thể cần thiết nếu alloca()được gọi trong một hàm. Tuy nhiên, x86 có rất ít thanh ghi và việc sử dụng hai trong số chúng để giữ vị trí của khung ngăn xếp khi một thanh ghi đủ sẽ không có ý nghĩa đối với tôi. Tại sao việc bỏ qua con trỏ khung được coi là một ý tưởng tồi ngay cả trong các bản dựng được tối ưu hóa / phát hành?


19
Nếu bạn nghĩ rằng x86 có rất ít đăng ký, bạn nên kiểm tra 6502 :)
Sedat Kapanoglu


1
C99 VLA cũng có thể được hưởng lợi từ nó.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功


1
Con trỏ khung không làm cho con trỏ ngăn xếp dư thừa? . TL; DR: 1. không tầm thường chồng alignment 2. đống phân bổ ( alloca) 3. dễ thực hiện thời gian chạy: exceptoins xử lý, sandbox, GC
Alexander Malakhov

Câu trả lời:


102

Con trỏ khung là một con trỏ tham chiếu cho phép trình gỡ lỗi biết biến cục bộ hoặc đối số đang ở đâu với một độ lệch hằng số duy nhất. Mặc dù giá trị của ESP thay đổi trong quá trình thực thi, nhưng EBP vẫn giữ nguyên giúp có thể đạt được cùng một biến ở cùng một mức bù (chẳng hạn như tham số đầu tiên sẽ luôn ở EBP + 8 trong khi hiệu số ESP có thể thay đổi đáng kể vì bạn sẽ đẩy / popping things)

Tại sao các trình biên dịch không loại bỏ con trỏ khung? Bởi vì với con trỏ khung, trình gỡ lỗi có thể tìm ra vị trí các biến cục bộ và đối số đang sử dụng bảng ký hiệu vì chúng được đảm bảo ở mức bù không đổi đối với EBP. Nếu không, không có cách nào dễ dàng để tìm ra biến cục bộ ở bất kỳ điểm nào trong mã.

Như Greg đã đề cập, nó cũng giúp giải nén ngăn xếp cho trình gỡ lỗi vì EBP cung cấp danh sách liên kết ngược các khung ngăn xếp, do đó cho phép trình gỡ lỗi tìm ra kích thước của khung ngăn xếp (biến cục bộ + đối số) của hàm.

Hầu hết các trình biên dịch cung cấp một tùy chọn để bỏ qua con trỏ khung mặc dù nó làm cho việc gỡ lỗi thực sự khó khăn. Tùy chọn đó không bao giờ được sử dụng trên toàn cầu, ngay cả trong mã phát hành. Bạn không biết khi nào bạn cần gỡ lỗi sự cố của người dùng.


10
Trình biên dịch có thể biết những gì nó làm với ESP. Tuy nhiên, các điểm khác vẫn hợp lệ, +1
erikkallen 24/02/09

8
Các trình gỡ lỗi hiện đại có thể thực hiện các dấu vết ngăn xếp ngay cả trong mã được biên dịch bằng -fomit-frame-pointer. Cài đặt đó là cài đặt mặc định trong gcc gần đây.
Peter Cordes

2
@SedatKapanoglu: Một phần dữ liệu ghi lại các thông tin cần thiết: yosefk.com/blog/...
Peter Cordes

3
@SedatKapanoglu: .eh_frame_hdrphần này cũng được sử dụng cho các trường hợp ngoại lệ thời gian chạy. Bạn sẽ tìm thấy nó (với objdump -h) trong hầu hết các mã nhị phân trên hệ thống Linux, Nó khoảng 16k /bin/bashcho GNU /bin/true, so với 572B cho GNU , 108k cho ffmpeg. Có một tùy chọn gcc để vô hiệu hóa việc tạo nó, nhưng đó là phần dữ liệu "bình thường", không phải phần gỡ lỗi stripsẽ xóa theo mặc định. Nếu không, bạn không thể truy xuất ngược thông qua một hàm thư viện không có ký hiệu gỡ lỗi. Phần đó có thể lớn hơn các push/mov/pophướng dẫn mà nó thay thế, nhưng nó có chi phí thời gian chạy gần như bằng không (ví dụ: uop cache).
Peter Cordes

3
Về "chẳng hạn như tham số đầu tiên sẽ luôn ở EBP-4": Không phải tham số đầu tiên trên EBP + 8 (trên x86)?
Aydin K.

31

Chỉ cần thêm hai xu của tôi vào câu trả lời đã tốt.

Đó là một phần của kiến ​​trúc ngôn ngữ tốt để có một chuỗi các khung ngăn xếp. BP trỏ đến khung hiện tại, nơi lưu trữ các biến cục bộ chương trình con. (Người dân địa phương có hiệu số âm và đối số có hiệu số dương.)

Ý tưởng rằng nó đang ngăn cản một thanh ghi hoàn toàn tốt được sử dụng trong việc tối ưu hóa đặt ra câu hỏi: khi nào và ở đâu việc tối ưu hóa thực sự đáng giá?

Việc tối ưu hóa chỉ có giá trị trong các vòng lặp chặt chẽ mà 1) không gọi các hàm, 2) trong đó bộ đếm chương trình dành một phần đáng kể thời gian của nó, và 3) trong mã trình biên dịch thực sự sẽ thấy (tức là các hàm không phải là thư viện). Đây thường là một phần rất nhỏ của mã tổng thể, đặc biệt là trong các hệ thống lớn.

Các mã khác có thể được xoắn và siết chặt để loại bỏ các chu kỳ, và điều đó đơn giản là không thành vấn đề, bởi vì bộ đếm chương trình thực tế không bao giờ ở đó.

Tôi biết bạn đã không hỏi điều này, nhưng theo kinh nghiệm của tôi, 99% các vấn đề về hiệu suất không liên quan gì đến việc tối ưu hóa trình biên dịch. Họ có mọi thứ để làm với thiết kế quá mức.


Cảm ơn @Mike, tôi thấy câu trả lời của bạn rất hữu ích.
sixtyfootersdude

2
Loại bỏ con trỏ khung cũng giúp bạn tiết kiệm một vài hướng dẫn cho mỗi lần gọi hàm, đây chỉ là một sự tối ưu hóa nhỏ. BTW, việc bạn sử dụng "begs the question" là không chính xác; ý bạn là "đặt ra câu hỏi".
August

@augurar: Đã sửa. Cảm ơn. Bản thân tôi hơi khó hiểu về ngữ pháp :)
Mike Dunlavey

3
@augurar Ngôn ngữ phát triển: "Đặt câu hỏi" bây giờ chỉ có nghĩa là "đặt ra câu hỏi". Việc trở thành một người theo chủ nghĩa chỉ định đối với việc sử dụng lỗi thời không thêm gì.
user3364825

9

Nó phụ thuộc vào trình biên dịch, chắc chắn. Tôi đã thấy mã được tối ưu hóa được phát ra bởi trình biên dịch x86 sử dụng tự do thanh ghi EBP làm thanh ghi mục đích chung. (Tuy nhiên, tôi không nhớ trình biên dịch mà tôi nhận thấy điều đó với.)

Các trình biên dịch cũng có thể chọn duy trì sổ đăng ký EBP để hỗ trợ giải nén ngăn xếp trong quá trình xử lý ngoại lệ, nhưng một lần nữa điều này phụ thuộc vào việc triển khai trình biên dịch chính xác.


Hầu hết các trình biên dịch mặc định -fomit-frame-pointerkhi tối ưu hóa được bật. (khi ABI cho phép). GCC, clang, ICC và MSVC đều làm được điều đó, IIRC, ngay cả khi nhắm mục tiêu Windows 32 bit. Đúng, câu trả lời của tôi về Tại sao sử dụng ebp tốt hơn là đăng ký esp để định vị các tham số trên ngăn xếp? cho thấy rằng ngay cả Windows 32-bit cũng có thể bỏ qua con trỏ khung. Linux 32-bit x86 chắc chắn có thể và làm được. Và tất nhiên ABI 64-bit đã cho phép bỏ qua con trỏ khung ngay từ đầu.
Peter Cordes

4

Tuy nhiên, x86 có rất ít đăng ký

Điều này chỉ đúng với nghĩa là mã quang chỉ có thể giải quyết 8 thanh ghi. Bản thân bộ xử lý sẽ thực sự có nhiều thanh ghi hơn thế và sử dụng đổi tên thanh ghi, pipelining, thực thi suy đoán và các từ thông dụng khác của bộ xử lý để vượt qua giới hạn đó. Wikipedia có một đoạn giới thiệu hay về những gì một bộ xử lý x86 có thể làm để vượt qua giới hạn đăng ký: http://en.wikipedia.org/wiki/X86#Current_implementations .


1
Câu hỏi ban đầu là về mã được tạo, được giới hạn nghiêm ngặt đối với các thanh ghi có thể tham chiếu bằng mã opcodes.
Darron

1
Có, nhưng đây là lý do tại sao ngày nay việc bỏ qua con trỏ khung trong các bản dựng được tối ưu hóa không còn quan trọng.
Michael

1
Mặc dù vậy, việc đổi tên đăng ký không hoàn toàn giống với việc thực sự có một số lượng đăng ký lớn hơn. Vẫn còn rất nhiều tình huống mà việc đổi tên đăng ký sẽ không hữu ích, nhưng các đăng ký "thông thường" hơn sẽ có.
jalf

1

Sử dụng khung ngăn xếp đã trở nên vô cùng rẻ trong bất kỳ phần cứng nào thậm chí từ xa hiện đại. Nếu bạn có các khung ngăn xếp rẻ tiền thì việc lưu một vài thanh ghi không quan trọng bằng. Tôi chắc chắn rằng các khung xếp chồng nhanh so với nhiều thanh ghi hơn là một sự đánh đổi kỹ thuật và các khung xếp chồng nhanh đã giành chiến thắng.

Bạn tiết kiệm được bao nhiêu khi đăng ký thuần túy? Nó có đáng không?


Nhiều đăng ký bị giới hạn bởi mã hóa lệnh. x86-64 sử dụng các bit trong byte tiền tố REX để mở rộng phần chỉ định thanh ghi của lệnh từ 3 đến 4 bit cho thanh ghi src và đích. Nếu có chỗ, x86-64 có thể đã đi đến 32 thanh ghi kiến ​​trúc, mặc dù việc lưu / khôi phục nhiều thanh ghi đó trên các công tắc ngữ cảnh bắt đầu tăng lên. 15 là một bước tiến lớn so với 7, nhưng 31 là một cải tiến nhỏ hơn nhiều trong hầu hết các trường hợp. (không tính con trỏ ngăn xếp là mục đích chung.) Làm cho push / pop nhanh là điều tuyệt vời cho nhiều hơn là chỉ các khung xếp chồng. Tuy nhiên, nó không phải là sự đánh đổi bằng số lần đăng ký.
Peter Cordes
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.