Nó được đẩy vào đâu?
esp - 4
. Chính xác hơn:
esp
bị trừ đi 4
- giá trị được đẩy lên
esp
pop
đảo ngược điều này.
Hệ thống V ABI yêu cầu Linux rsp
chỉ đến một vị trí ngăn xếp hợp lý khi chương trình bắt đầu chạy: Trạng thái thanh ghi mặc định khi chương trình khởi chạy (asm, linux) là gì? đó là những gì bạn thường nên sử dụng.
Làm thế nào bạn có thể đẩy một đăng ký?
Ví dụ về GNU GAS tối thiểu:
.data
/* .long takes 4 bytes each. */
val1:
/* Store bytes 0x 01 00 00 00 here. */
.long 1
val2:
/* 0x 02 00 00 00 */
.long 2
.text
/* Make esp point to the address of val2.
* Unusual, but totally possible. */
mov $val2, %esp
/* eax = 3 */
mov $3, %ea
push %eax
/*
Outcome:
- esp == val1
- val1 == 3
esp was changed to point to val1,
and then val1 was modified.
*/
pop %ebx
/*
Outcome:
- esp == &val2
- ebx == 3
Inverses push: ebx gets the value of val1 (first)
and then esp is increased back to point to val2.
*/
Trên GitHub với các xác nhận có thể chạy được .
Tại sao điều này là cần thiết?
Đúng là những hướng dẫn đó có thể dễ dàng thực hiện thông qua mov
, add
và sub
.
Lý do chúng tồn tại là do sự kết hợp các hướng dẫn đó quá thường xuyên, nên Intel đã quyết định cung cấp chúng cho chúng tôi.
Lý do tại sao những sự kết hợp đó rất thường xuyên, là chúng giúp dễ dàng lưu và khôi phục các giá trị của thanh ghi vào bộ nhớ tạm thời để chúng không bị ghi đè.
Để hiểu vấn đề, hãy thử biên dịch một số mã C bằng tay.
Một khó khăn lớn là quyết định nơi lưu trữ mỗi biến.
Lý tưởng nhất là tất cả các biến sẽ phù hợp với thanh ghi, đây là bộ nhớ nhanh nhất để truy cập (hiện tại nhanh hơn khoảng 100 lần so với RAM).
Nhưng tất nhiên, chúng ta có thể dễ dàng có nhiều biến hơn so với thanh ghi, đặc biệt cho các đối số của các hàm lồng nhau, vì vậy giải pháp duy nhất là ghi vào bộ nhớ.
Chúng ta có thể ghi vào bất kỳ địa chỉ bộ nhớ nào, nhưng vì các biến cục bộ và đối số của các lệnh gọi và trả về hàm phù hợp với một mẫu ngăn xếp đẹp mắt, ngăn chặn phân mảnh bộ nhớ , đó là cách tốt nhất để giải quyết nó. So sánh điều đó với sự điên rồ khi viết một trình phân bổ đống.
Sau đó, chúng tôi để các trình biên dịch tối ưu hóa việc phân bổ thanh ghi cho chúng tôi, vì đó là NP đã hoàn thành và một trong những phần khó nhất khi viết trình biên dịch. Vấn đề này được gọi là cấp phát thanh ghi , và nó là đẳng cấu để tô màu đồ thị .
Khi trình cấp phát của trình biên dịch buộc phải lưu trữ mọi thứ trong bộ nhớ thay vì chỉ đăng ký, điều đó được gọi là tràn .
Điều này dẫn đến một chỉ dẫn xử lý đơn lẻ hay nó phức tạp hơn?
Tất cả những gì chúng ta biết chắc chắn là Intel ghi lại một tài liệu push
và một pop
hướng dẫn, vì vậy chúng là một hướng dẫn theo nghĩa đó.
Bên trong, nó có thể được mở rộng thành nhiều vi mã, một để sửa đổi esp
và một để thực hiện IO bộ nhớ và mất nhiều chu kỳ.
Nhưng cũng có thể một đơn push
nhanh hơn một tổ hợp tương đương của các hướng dẫn khác, vì nó cụ thể hơn.
Điều này chủ yếu là chưa (der) được ghi lại:
b
,w
,l
, hoặcq
để biểu thị kích thước của bộ nhớ bị thao túng. Ví dụ:pushl %eax
vàpopl %eax