Tautan berikut menjelaskan konvensi sistem panggilan x86-32 untuk UNIX (BSD flavour) & Linux:
Tapi apa konvensi sistem panggilan x86-64 di UNIX & Linux?
Tautan berikut menjelaskan konvensi sistem panggilan x86-32 untuk UNIX (BSD flavour) & Linux:
Tapi apa konvensi sistem panggilan x86-64 di UNIX & Linux?
sysret
kerjanya, bersama dengan rax diganti dengan nilai pengembalian. Semua register lainnya disimpan pada amd64.Jawaban:
Bacaan lebih lanjut untuk topik apa pun di sini: Panduan Definitif untuk Panggilan Sistem Linux
Saya memverifikasi ini menggunakan GNU Assembler (gas) di Linux.
Antarmuka Kernel
x86-32 alias Konvensi Sistem Panggilan i386 Linux:
Dalam x86-32, parameter untuk panggilan sistem Linux dilewatkan menggunakan register.
%eax
untuk syscall_number. % ebx,% ecx,% edx,% esi,% edi,% ebp digunakan untuk melewatkan 6 parameter ke panggilan sistem.Nilai kembali dalam
%eax
. Semua register lain (termasuk EFLAGS) dilestarikan di seluruhint $0x80
.Saya mengikuti cuplikan dari Tutorial Perakitan Linux tapi saya ragu tentang ini. Jika ada yang bisa menunjukkan contoh, itu akan bagus.
Untuk contoh dan bacaan lebih lanjut, lihat http://www.int80h.org/bsdasm/#alternate-calling-convention . Contoh lain dari Hello World untuk i386 Linux menggunakan
int 0x80
: Halo, dunia dalam bahasa assembly dengan panggilan sistem Linux?Ada cara yang lebih cepat untuk melakukan panggilan sistem 32-bit: menggunakan
sysenter
. Kernel memetakan satu halaman memori ke dalam setiap proses (vDSO), dengan sisi ruang pengguna darisysenter
tarian, yang harus bekerja sama dengan kernel agar dapat menemukan alamat pengirim. Arg untuk mendaftarkan pemetaan sama dengan untukint $0x80
. Anda biasanya harus memanggil ke vDSO daripada menggunakansysenter
secara langsung. (Lihat Panduan Definitif untuk Panggilan Sistem Linux untuk info tentang menautkan dan memanggil ke vDSO, dan untuk info lebih lanjut tentangsysenter
, dan segala sesuatu yang berkaitan dengan panggilan sistem.)x86-32 [Gratis | Buka | Net | DragonFly] Konvensi Sistem Panggilan BSD UNIX:
Parameter dilewatkan pada tumpukan. Dorong parameter (parameter terakhir didorong pertama) ke stack. Kemudian dorong data dummy 32-bit tambahan (Ini sebenarnya bukan data dummy. Lihat tautan berikut untuk info lebih lanjut) dan kemudian berikan instruksi panggilan sistem
int $0x80
http://www.int80h.org/bsdasm/#default-calling-convention
Konvensi Sistem Panggilan Linux x86-64:
x86-64 Mac OS X serupa tetapi berbeda . TODO: periksa apa yang * BSD lakukan.
Lihat bagian: "A.2 Konvensi K64 Linux AMD64 " dari Aplikasi Sistem V Antarmuka Biner Tambahan Prosesor Arsitektur AMD64 . Versi terbaru dari Sistem i386 dan x86-64 psABI dapat ditemukan ditautkan dari halaman ini di repo pengelola ABI . (Lihat jugax86 beri tag wiki untuk tautan ABI terbaru dan banyak hal bagus lainnya tentang as x86.)
Berikut cuplikan dari bagian ini:
Ingat ini dari lampiran khusus Linux ke ABI, dan bahkan untuk Linux itu informatif bukan normatif. (Tapi itu sebenarnya akurat.)
int $0x80
ABI 32-bit ini dapat digunakan dalam kode 64-bit (tapi sangat tidak disarankan). Apa yang terjadi jika Anda menggunakan ABI 32-bit int 0x80 Linux dalam kode 64-bit? Itu masih memotong inputnya ke 32-bit, jadi itu tidak cocok untuk pointer, dan itu nol r8-r11.Antarmuka Pengguna: pemanggilan fungsi
Konvensi Fungsi Memanggil x86-32:
Dalam x86-32 parameter diteruskan pada stack. Parameter terakhir didorong pertama ke stack sampai semua parameter dilakukan dan kemudian
call
instruksi dieksekusi. Ini digunakan untuk memanggil fungsi C library (libc) di Linux dari assembly.Versi modern dari System V ABI i386 (digunakan pada Linux) memerlukan perataan 16 byte
%esp
sebelumcall
, seperti Sistem V86 AB86 x86 yang selalu diperlukan. Calle diizinkan untuk mengasumsikan itu dan menggunakan beban / toko SSE 16 byte yang gagal pada unaligned. Tetapi secara historis, Linux hanya membutuhkan 4-byte stack alignment, sehingga butuh kerja ekstra untuk memesan ruang yang rata-rata bahkan untuk 8-bytedouble
atau sesuatu.Beberapa sistem 32-bit modern lainnya masih tidak memerlukan lebih dari 4 byte stack alignment.
x86-64 Konvensi pengguna-ruang System V: Panggilan Fungsi:
x86-64 System V melewatkan args dalam register, yang lebih efisien daripada konvensi stack args i386 System V. Ini menghindari latensi dan instruksi tambahan menyimpan args ke memori (cache) dan kemudian memuatnya kembali di callee. Ini bekerja dengan baik karena ada lebih banyak register yang tersedia, dan lebih baik untuk CPU berkinerja tinggi modern di mana masalah latensi dan eksekusi tidak sesuai pesanan. (ABI i386 sudah sangat tua).
Dalam mekanisme baru ini : Pertama parameter dibagi ke dalam kelas. Kelas dari setiap parameter menentukan cara di mana ia dilewatkan ke fungsi yang dipanggil.
Untuk informasi lengkap, lihat: "3.2 Urutan Pemanggilan Fungsi" dari Aplikasi Sistem V Antarmuka Biner Tambahan Prosesor Arsitektur AMD64 yang berbunyi, sebagian:
Jadi
%rdi, %rsi, %rdx, %rcx, %r8 and %r9
adalah register agar digunakan untuk melewati bilangan bulat / pointer (yaitu INTEGER kelas) parameter ke fungsi libc dari perakitan. % rdi digunakan untuk parameter INTEGER pertama. % rsi untuk ke-2,% rdx untuk ke-3 dan seterusnya. Makacall
instruksi harus diberikan. Stack (%rsp
) harus sejajar 16B saatcall
dijalankan.Jika ada lebih dari 6 parameter INTEGER, parameter INTEGER ke-7 dan yang lebih baru dilewatkan pada stack. (Pemanggil muncul, sama seperti x86-32.)
8 argumen floating point pertama dilewatkan dalam% xmm0-7, nanti di stack. Tidak ada register vektor yang diawetkan dengan panggilan. (Fungsi dengan campuran argumen FP dan integer dapat memiliki lebih dari 8 argumen register total.)
Fungsi variadik ( seperti
printf
) selalu membutuhkan%al
= jumlah argumen register FP.Ada aturan untuk kapan memasukkan paket ke register (
rdx:rax
saat kembali) vs. dalam memori. Lihat ABI untuk detailnya, dan periksa output kompiler untuk memastikan kode Anda setuju dengan kompiler tentang bagaimana sesuatu harus dilewatkan / dikembalikan.Perhatikan bahwa konvensi pemanggilan fungsi Windows x64 memiliki beberapa perbedaan signifikan dari Sistem x86-64, seperti ruang bayangan yang harus dipesan oleh penelepon (bukan zona merah), dan xmm6-xmm15 yang dipelihara dengan panggilan. Dan aturan yang sangat berbeda untuk arg mana masuk register.
sumber
int 0x80
ABI Linux dalam kode 64-bit, inilah yang terjadi: stackoverflow.com/questions/46087730/… . Ini nol r8-r11, dan bekerja persis seperti ketika dijalankan dalam proses 32-bit. Dalam T&J itu saya memiliki contoh yang menunjukkan itu berfungsi, atau gagal dengan memotong pointer. Dan saya juga menggali sumber kernel untuk menunjukkan mengapa ia berperilaku seperti itu.Mungkin Anda mencari ABI x86_64?
Jika bukan itu yang Anda cari, gunakan 'x86_64 abi' di mesin pencari pilihan Anda untuk menemukan referensi alternatif.
sumber
Konvensi panggilan mendefinisikan bagaimana parameter dilewatkan dalam register saat memanggil atau dipanggil oleh program lain. Dan sumber terbaik konvensi ini adalah dalam bentuk standar ABI yang ditentukan untuk masing-masing perangkat keras ini. Untuk kemudahan kompilasi, ABI yang sama juga digunakan oleh userspace dan program kernel. Linux / Freebsd mengikuti ABI yang sama untuk x86-64 dan perangkat lain untuk 32-bit. Tetapi ABI x86-64 untuk Windows berbeda dari Linux / FreeBSD. Dan umumnya ABI tidak membedakan system call vs "fungsi panggilan" yang normal. Yaitu, berikut adalah contoh khusus dari konvensi pemanggilan x86_64 dan itu sama untuk ruang pengguna dan kernel Linux: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64 / (perhatikan urutan a, b, c, d, e, f dari parameter):
Kinerja adalah salah satu alasan untuk ABI ini (misalnya, melewatkan parameter melalui register alih-alih menyimpan ke dalam tumpukan memori)
Untuk ARM ada berbagai ABI:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.swdev.abi/index.html
https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/iPhoneOSABIReference.pdf
Konvensi ARM64:
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
Untuk Linux di PowerPC:
http://refspecs.freestandards.org/elf/elfspec_ppc.pdf
http://www.0x04.net/doc/elf/psABI-ppc64.pdf
Dan untuk embedded ada PPC EABI:
http://www.freescale.com/files/32bit/doc/app_note/PPCEABI.pdf
Dokumen ini adalah tinjauan umum yang baik dari semua konvensi yang berbeda:
http://www.agner.org/optimize/calling_conventions.pdf
sumber
Kernel Linux 5.0 komentar sumber
Saya tahu bahwa spesifikasi x86 berada di bawah
arch/x86
, dan hal-hal syscall berjalan di bawaharch/x86/entry
. Jadi cepatgit grep rdi
dalam direktori itu membawa saya ke arch / x86 / entry / entry_64.S :dan untuk 32-bit di arch / x86 / entry / entry_32.S :
glibc 2.29 implementasi system call Linux x86_64
Sekarang mari kita selingkuh dengan melihat implementasi libc utama dan lihat apa yang mereka lakukan.
Apa yang bisa lebih baik daripada melihat ke glibc yang saya gunakan saat ini ketika saya menulis jawaban ini? :-)
glibc 2.29 mendefinisikan syscalls x86_64 di
sysdeps/unix/sysv/linux/x86_64/sysdep.h
dan yang berisi beberapa kode menarik, misalnya:dan:
yang saya rasa cukup jelas. Perhatikan bagaimana ini tampaknya telah dirancang untuk benar-benar cocok dengan konvensi pemanggilan fungsi System V AMD64 ABI reguler: https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions
Pengingat cepat dari para clobbers:
cc
berarti register bendera. Tetapi Peter Cordes berkomentar bahwa ini tidak perlu di sini.memory
berarti bahwa penunjuk dapat dilewatkan dalam rakitan dan digunakan untuk mengakses memoriUntuk contoh runnable minimal yang eksplisit dari awal, lihat jawaban ini: Bagaimana menjalankan panggilan sistem melalui sysenter dalam inline assembly?
Buat beberapa panggilan syscall secara manual
Tidak terlalu ilmiah, tetapi menyenangkan:
x86_64.S
GitHub hulu .
aarch64
Saya telah menunjukkan contoh userland runnable minimal di: /reverseengineering/16917/arm64-syscalls-table/18834#18834 TODO grep kode kernel di sini, seharusnya mudah.
sumber
"cc"
mengkritik tidak perlu: syscalls Linux menyimpan / mengembalikan RFLAGS (Thesyscall
/sysret
petunjuk melakukan itu menggunakan R11, dan kernel tidak memodifikasi R11 disimpan / RFLAGS selain melaluiptrace
panggilan sistem debugger.) Bukan berarti itu pernah penting, karena"cc"
mengkritik adalah implisit untuk x86 / x86-64 di GNU C Extended asm, jadi Anda tidak bisa mendapatkan apa-apa dengan meninggalkannya.