Pertanyaan Apa yang dimaksud dengan tumpukan frame dalam perakitan?


Apa struktur dari stack frame dan bagaimana itu digunakan saat memanggil fungsi dalam perakitan?


33
2017-09-13 09:43


asal


Jawaban:


Bingkai tumpukan x86-32 dibuat dengan mengeksekusi

function_start:
    push ebp
    mov ebp, esp

sehingga dapat diakses melalui ebp dan terlihat seperti

ebp+00 (current_frame) : prev_frame
ebp+04                 : return_address
                         ....
prev_frame             : prev_prev_frame
prev_frame+04          : prev_return_address

Ada beberapa keuntungan menggunakan ebp untuk stack frame dengan desain instruksi perakitan, sehingga argumen dan penduduk setempat biasanya diakses menggunakan register ebp.


10
2017-09-13 11:22



Setiap rutinitas menggunakan sebagian dari tumpukan, dan kami menyebutnya sebagai kerangka tumpukan. Meskipun programmer assembler tidak dipaksa untuk mengikuti gaya berikut, itu sangat disarankan sebagai praktik yang baik.

Rangka stack untuk setiap rutin dibagi menjadi tiga bagian: parameter fungsi, back-pointer ke frame stack sebelumnya, dan variabel lokal.

Bagian 1: Parameter Fungsi

Bagian stack stack rutin ini diatur oleh pemanggil. Menggunakan instruksi 'push', penelepon mendorong parameter ke stack. Bahasa yang berbeda dapat mendorong parameter pada pesanan yang berbeda. C, jika saya ingat dengan benar, mendorong mereka dari kanan ke kiri. Artinya, jika Anda menelepon ...

foo (a, b, c);

Penelepon akan mengonversinya menjadi ...

push c
push b
push a
call foo

Karena setiap item didorong ke tumpukan, tumpukan menumpuk. Yaitu, penunjuk-penunjuk tumpukan dikurangi dengan empat (4) byte (dalam mode 32-bit), dan item disalin ke lokasi memori yang ditunjukkan oleh daftar penunjuk-tumpukan. Perhatikan bahwa instruksi 'panggilan' akan secara implisit mendorong alamat pengirim pada stack. Pembersihan parameter akan dibahas di Bagian 5.

Bagian 2: Stackframe kembali pointer

Pada titik waktu ini, instruksi 'panggilan' telah dikeluarkan dan kita sekarang berada di awal rutinitas yang disebut. Jika kami ingin mengakses parameter kami, kami dapat mengaksesnya seperti ...

[esp + 0]   - return address
[esp + 4]   - parameter 'a'
[esp + 8]   - parameter 'b'
[esp + 12]  - parameter 'c'

Namun, ini bisa menjadi kikuk setelah kami mengukir ruang untuk variabel lokal dan hal-hal. Jadi, kami menggunakan register stackbase-pointer selain register stack-pointer. Namun, kami ingin register stackbase-pointer disetel ke frame kami saat ini, dan bukan fungsi sebelumnya. Jadi, kita menyimpan yang lama di stack (yang memodifikasi offset parameter pada stack) dan kemudian salin register stack-pointer saat ini ke register stackbase-pointer.

push ebp        ; save previous stackbase-pointer register
mov  ebp, esp   ; ebp = esp

Terkadang Anda mungkin melihat ini dilakukan hanya dengan menggunakan instruksi 'ENTER'.

Bagian 3: Mengukir ruang untuk variabel lokal

Variabel lokal disimpan di stack. Karena tumpukan bertambah, kami kurangi beberapa # byte (cukup untuk menyimpan variabel lokal kami):

sub esp, n_bytes ; n_bytes = number of bytes required for local variables

Bagian 4: Menyatukan semuanya. Parameter diakses menggunakan register stackbase-pointer ...

[ebp + 16]  - parameter 'c'
[ebp + 12]  - parameter 'b'
[ebp + 8]   - parameter 'a'
[ebp + 4]   - return address
[ebp + 0]   - saved stackbase-pointer register

Variabel lokal diakses menggunakan register stack-pointer ...

[esp + (# - 4)] - top of local variables section
[esp + 0]       - bottom of local variables section

Bagian 5: Pembersihan Stackframe

Ketika kita meninggalkan rutinitas, stack frame harus dibersihkan.

mov esp, ebp   ; undo the carving of space for the local variables
pop ebp        ; restore the previous stackbase-pointer register

Terkadang Anda mungkin melihat instruksi 'TINGGALKAN' mengganti kedua instruksi tersebut.

Tergantung pada bahasa yang Anda gunakan, Anda mungkin melihat salah satu dari dua bentuk instruksi 'RET'.

ret
ret <some #>

Mana yang dipilih akan tergantung pada pilihan bahasa (atau gaya yang ingin Anda ikuti jika menulis dalam assembler). Kasus pertama menunjukkan bahwa penelepon bertanggung jawab untuk menghapus parameter dari tumpukan (dengan contoh foo (a, b, c) itu akan melakukannya melalui ... tambahkan esp, 12) dan itu adalah cara 'C' tidak saya t. Kasus kedua menunjukkan bahwa instruksi kembali akan muncul # kata (atau # byte, saya tidak ingat yang mana) dari tumpukan ketika kembali, sehingga menghapus parameter dari stack. Jika saya ingat dengan benar, ini adalah gaya yang digunakan oleh Pascal.

Ini panjang, tapi saya harap ini membantu Anda lebih memahami stackframes.


116
2017-09-13 12:05



Ini berbeda tergantung pada sistem operasi dan bahasa yang digunakan. Karena tidak ada format umum untuk tumpukan di ASM, satu-satunya hal yang dilakukan tumpukan di ASM adalah menyimpan alamat kembali ketika melakukan lompatan-subrutin. Ketika mengeksekusi return-from-subroutine, alamat diambil dari stack dan dimasukkan ke dalam Program-Counter (lokasi memori di mana instruksi eksekusi CPU berikutnya harus diulang)

Anda perlu berkonsultasi dengan dokumentasi Anda untuk compiler yang Anda gunakan.


2
2017-09-13 10:34



Frame stack x86 dapat digunakan oleh compiler (tergantung pada compiler) untuk melewatkan parameter (atau pointer ke parameter) dan mengembalikan nilai. Lihat ini 


0
2017-09-13 09:58