GNU/Linux >> Belajar Linux >  >> Linux

Mencoba memahami perataan tumpukan gcc yang rumit di bagian atas main yang menyalin alamat pengirim

Saya sudah mencobanya:

;# As you have already noticed, the compiler wants to align the stack
;# pointer on a 16 byte boundary before it pushes anything. That's
;# because certain instructions' memory access needs to be aligned
;# that way.
;# So in order to first save the original offset of esp (+4), it
;# executes the first instruction:
lea    ecx,[esp+0x4]

;# Now alignment can happen. Without the previous insn the next one
;# would have made the original esp unrecoverable:
and    esp,0xfffffff0

;# Next it pushes the return addresss and creates a stack frame. I
;# assume it now wants to make the stack look like a normal
;# subroutine call:
push   DWORD PTR [ecx-0x4]
push   ebp
mov    ebp,esp

;# Remember that ecx is still the only value that can restore the
;# original esp. Since ecx may be garbled by any subroutine calls,
;# it has to save it somewhere:
push   ecx

Ini dilakukan untuk menjaga agar tumpukan tetap sejajar dengan batas 16 byte. Beberapa instruksi memerlukan tipe data tertentu untuk disejajarkan sebanyak batas 16 byte. Untuk memenuhi persyaratan ini, GCC memastikan bahwa tumpukan awalnya selaras 16-byte, dan mengalokasikan ruang tumpukan dalam kelipatan 16 byte. Ini dapat dikontrol menggunakan opsi -mpreferred-stack-boundary=num . Jika Anda menggunakan -mpreferred-stack-boundary=2 (untuk penyelarasan 2=4-byte), kode penyelarasan ini tidak akan dibuat karena tumpukan selalu disejajarkan setidaknya 4-byte. Namun Anda kemudian dapat mengalami masalah jika program Anda menggunakan tipe data apa pun yang memerlukan penyelarasan yang lebih kuat.

Menurut manual gcc:

Pada Pentium dan PentiumPro, nilai double dan long double harus disejajarkan dengan batas 8 byte (lihat -malign-double) atau mengalami penalti performa waktu proses yang signifikan. Pada Pentium III, tipe data Streaming SIMD Extension (SSE) __m128 mungkin tidak berfungsi dengan baik jika tidak selaras 16 byte.

Untuk memastikan penyelarasan yang tepat dari nilai-nilai ini pada tumpukan, batas tumpukan harus sejajar dengan yang dibutuhkan oleh nilai apa pun yang disimpan di tumpukan. Selanjutnya, setiap fungsi harus dihasilkan sedemikian rupa sehingga menjaga tumpukan tetap sejajar. Dengan demikian memanggil fungsi yang dikompilasi dengan batas tumpukan pilihan yang lebih tinggi dari fungsi yang dikompilasi dengan batas tumpukan pilihan yang lebih rendah kemungkinan besar akan menyelaraskan tumpukan. Disarankan agar pustaka yang menggunakan panggilan balik selalu menggunakan setelan default.

Perataan ekstra ini menghabiskan ruang tumpukan ekstra, dan umumnya meningkatkan ukuran kode. Kode yang sensitif terhadap penggunaan ruang tumpukan, seperti sistem tersemat dan kernel sistem operasi, mungkin ingin mengurangi penyelarasan pilihan menjadi -mpreferred-stack-boundary=2.

lea memuat penunjuk tumpukan asli (dari sebelum panggilan ke main ) menjadi ecx , karena penunjuk tumpukan akan diubah. Ini digunakan untuk dua tujuan:

  1. untuk mengakses argumen ke main fungsi, karena relatif terhadap penunjuk tumpukan asli
  2. untuk memulihkan penunjuk tumpukan ke nilai aslinya saat kembali dari main

lea    ecx,[esp+0x4] ; I assume this is for getting the adress of the first argument of     the main...why ?
and    esp,0xfffffff0 ; ??? is the compiler trying to align the stack pointer on 16 bytes ???
push   DWORD PTR [ecx-0x4] ; I understand the assembler is pushing the return adress....why ?
push   ebp                
mov    ebp,esp
push   ecx  ;why is ecx pushed too ??

Bahkan jika setiap instruksi bekerja dengan sempurna tanpa penalti kecepatan meskipun operan diselaraskan secara sewenang-wenang, penyelarasan masih akan meningkatkan kinerja. Bayangkan sebuah loop mereferensikan kuantitas 16-byte yang hanya tumpang tindih dengan dua baris cache. Sekarang, untuk memuat wchar kecil itu ke dalam cache, dua seluruh baris cache harus dikeluarkan, dan bagaimana jika Anda membutuhkannya di loop yang sama? Cache jauh lebih cepat daripada RAM sehingga kinerja cache selalu kritis.

Selain itu, biasanya ada penalti kecepatan untuk menggeser operan yang tidak selaras ke dalam register. Mengingat bahwa tumpukan sedang diatur ulang, secara alami kita harus menyimpan keselarasan lama untuk melintasi bingkai tumpukan untuk parameter dan mengembalikannya.

ecx adalah register sementara sehingga harus disimpan. Selain itu, bergantung pada tingkat pengoptimalan, beberapa operasi penautan bingkai yang tampaknya tidak benar-benar diperlukan untuk menjalankan program mungkin juga penting untuk menyiapkan rangkaian bingkai siap-pelacakan.


Linux
  1. Kernel Linux:5 inovasi teratas

  2. 20 panduan dan tutorial sysadmin teratas

  3. Memahami Arti `$_`?

  1. Cara menampilkan Alamat IP PC Anda di Panel Atas di Ubuntu

  2. Temukan Komputer Di Jaringan Lan?

  3. Bagaimana cara menemukan ukuran tumpukan maksimum?

  1. Temukan Geolokasi Alamat IP Dari Commandline

  2. Hanya Mengembalikan String yang Cocok Di Sed?

  3. Apa itu pengguna debian-+?