HeadlinesBriefing favicon HeadlinesBriefing.com

Optimasi stack trampoline fungsi bersarang GCC

Hacker News •
×

Optimasi Stack Trampoline Fungsi Bersarang GCC. Pemanggilan Tidak Langsung Fungsi Bersarang di GCC Tanpa Stack Executable. Martin Uecker, 2026-08-29.

Kami membahas terakhir kali bagaimana fungsi bersarang dapat digunakan di GCC dan Clang untuk callback tanpa memerlukan stack executable. Namun bagaimana jika perlu mendukung versi GCC yang lebih lama? Tentu saja, bisa saja menerima stack executable, tetapi juga mungkin untuk menghindarinya dengan trik. GCC: Fungsi Bersarang dan Trampoline.

Mari bahas dulu bagaimana GCC mendukung pengambilan alamat fungsi bersarang. Contoh mainan kami tanpa penggunaan makro baru ditunjukkan di bawah. Pada x86_64, assembly yang dihasilkan menempatkan trampoline di stack dan segera memanggilnya melalui fungsi baz yang di-inline.

Trampoline adalah urutan kode singkat yang memuat register frame statis ke struktur di stack yang berisi variabel yang ditangkap dari fungsi induk dan kemudian melompat ke fungsi lokal. Jika menerjemahkan konstanta -17591, -17847, dan -1864106167 kembali ke instruksi assembly, akan mendapatkan kode x86_64 berikut: movq $bar.0, %r11, movq $frame, %r10, jump *%r11. Keduanya, static chain dan alamat kode, adalah konstanta immediate yang digunakan oleh instruksi move di kode trampoline.

Alih-alih menggunakan alamat trampoline untuk memanggil fungsi, kita dapat mengekstrak alamat kode dan static chain dari trampoline dan menggunakannya dengan fungsi built-in __builtin_call_with_static_chain untuk memanggil fungsi lokal secara langsung. Dengan demikian, kita dapat menggunakan pembacaan dua nilai pointer ini dari trampoline sebagai mekanisme fallback di versi GCC lama. Kekurangannya adalah trampoline tetap dibuat, compiler tetap tidak bisa devirtualize pemanggilan tidak langsung, dan stack tetap ditandai executable.

Jadi apa yang didapat? Karena kita tidak pernah benar-benar memanggil trampoline, kita bisa membuat stack non-executable lagi dengan perintah berikut, yang setidaknya mengatasi kekhawatiran keamanan fitur ini. patchelf --clear-execstack program. Ide ini diimplementasikan di library eksperimen saya, noplate, di mana wide pointer dibangun dari alamat kode dan static chain. Trampoline sebagai Deskriptor Fungsi.

Ada ide lain yang menurut saya layak dieksplorasi: Kita juga bisa menggunakan trampoline itu sendiri sebagai deskriptor fungsi. Alih-alih mengekstrak static chain dan code pointer di tempat trampoline dibuat, kita hanya meneruskan alamat trampoline seperti biasa. Tetapi di setiap tempat di mana kita mungkin memanggil trampoline, kita pertama-tama memeriksa apakah pointer menunjuk ke trampoline, lalu mengekstrak alamat kode dan static chain untuk memanggil fungsi bersarang langsung menggunakan __builtin_call_with_static_chain.

Dalam arti tertentu kita bisa bilang alih-alih memanggil trampoline, kita menafsirkan kode trampoline di call site menggunakan interpreter super sederhana yang hanya bisa menafsirkan urutan kode spesifik ini dan begitu sederhana sehingga...