GNU/Linux >> Belajar Linux >  >> Linux

x86_64 Perakitan Kebingungan Panggilan Sistem Linux

Cukup banyak yang berubah antara i386 dan x86_64 termasuk instruksi yang digunakan untuk masuk ke kernel dan register yang digunakan untuk membawa argumen panggilan sistem. Ini kode yang setara dengan milik Anda:

.section .data

.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall

Mengutip dari jawaban ini untuk pertanyaan terkait:

Nomor syscall ada di kode sumber Linux di bawah arch/x86/include/asm/unistd_64.h. Nomor syscall dilewatkan dalam register rax. Parameternya ada di rdi, rsi, rdx, r10, r8, r9. Panggilan dipanggil dengan instruksi "syscall". Syscall menimpa register rcx. Pengembaliannya dalam rax.


Anda mengalami satu perbedaan mengejutkan antara i386 dan x86_64:keduanya tidak menggunakan mekanisme panggilan sistem yang sama. Kode yang benar adalah:

movq $60, %rax
movq $2,  %rdi   ; not %rbx!
syscall

Interupsi 0x80 selalu memanggil panggilan sistem 32-bit. Ini digunakan untuk mengizinkan aplikasi 32-bit berjalan di sistem 64-bit.

Untuk tujuan pembelajaran, Anda mungkin harus mencoba mengikuti tutorial dengan tepat, daripada menerjemahkan dengan cepat ke 64-bit -- ada beberapa perbedaan perilaku signifikan lainnya yang mungkin Anda temui. Setelah Anda terbiasa dengan i386, lalu Anda dapat mengambil x86_64 secara terpisah.


silakan baca ini Apa konvensi pemanggilan untuk panggilan sistem UNIX &Linux di x86-64

dan perhatikan bahwa menggunakan int 0x80 untuk syscall pada sistem x64 adalah lapisan kompatibilitas lama. Anda harus menggunakan syscall instruksi pada sistem x64.

Anda masih dapat menggunakan metode lama ini, tetapi Anda perlu mengkompilasi binari Anda dalam mode x86, lihat manual compiler/assembler Anda untuk detailnya.


jawaban senjawuff menunjukkan dengan benar bahwa mekanisme panggilan sistem berbeda untuk Linux x86 64-bit versus Linux 32-bit.

Namun, jawaban ini tidak lengkap dan menyesatkan karena beberapa alasan:

  • Perubahan ini sebenarnya diperkenalkan sebelum sistem 64-bit menjadi populer , termotivasi oleh pengamatan bahwa int 0x80 sangat lambat di Pentium 4. Linus Torvalds membuat kode solusi menggunakan SYSENTER /SYSEXIT instruksi (yang telah diperkenalkan oleh Intel sekitar era Pentium Pro, tetapi buggy dan tidak memberikan manfaat praktis). Jadi sistem Linux 32-bit modern benar-benar menggunakan SYSENTER , bukan int 0x80 .
  • Kernel Linux x86 64-bit sebenarnya tidak menggunakan SYSENTER dan SYSEXIT . Mereka sebenarnya menggunakan SYSCALL yang sangat mirip /SYSRET instruksi.

Seperti yang ditunjukkan di komentar, SYSENTER tidak benar-benar bekerja pada banyak sistem Linux 64-bit —yaitu AMD 64-bit sistem.

Ini memang situasi yang membingungkan. Detailnya ada di sini, tapi intinya adalah ini:

Untuk kernel 32bit, SYSENTER/SYSEXIT adalah satu-satunya pasangan yang kompatibel [antara CPU AMD dan Intel]

Untuk kernel 64bit dalam mode Panjang saja… SYSCALL/SYSRET adalah satu-satunya pasangan yang kompatibel [antara CPU AMD dan Intel]

Tampaknya pada Intel CPU dalam mode 64-bit, Anda dapat menggunakan SYSENTER karena melakukan hal yang sama seperti SYSCALL , namun ini tidak berlaku untuk sistem AMD.

Intinya:selalu gunakan SYSCALL di Linux pada sistem x86 64-bit . Itulah yang sebenarnya ditentukan oleh x86-64 ABI. (Lihat jawaban wiki yang bagus ini untuk detail lebih lanjut.)


Linux
  1. Linux – Mengapa Utils Linux Tidak Menggunakan System Call Untuk Mendapatkan Waktu Saat Ini?

  2. Linux – Metode Panggilan Sistem di Kernel Baru?

  3. Praktik Pengkodean Terbaik untuk Pemrograman Sistem Linux dalam Bahasa C – Bagian 1

  1. Bagaimana cara memetakan tumpukan untuk panggilan sistem clone () di linux?

  2. Tabel panggilan sistem Linux atau lembar contekan untuk Majelis

  3. Bagaimana cara memanggil panggilan sistem melalui syscall atau sysenter di inline assembly?

  1. Panggilan sistem Linux tercepat

  2. Bagaimana cara meneruskan parameter ke panggilan sistem Linux?

  3. Mengapa ada kebutuhan untuk memodifikasi tabel system call di Linux?