Yang tidak ada, dan karenanya mengembalikan -ENOSYS dengan cepat.
Dari arch/x86/entry/entry_64.S:
#if __SYSCALL_MASK == ~0
cmpq $__NR_syscall_max, %rax
#else
andl $__SYSCALL_MASK, %eax
cmpl $__NR_syscall_max, %eax
#endif
ja 1f /* return -ENOSYS (already in pt_regs->ax) */
movq %r10, %rcx
/*
* This call instruction is handled specially in stub_ptregs_64.
* It might end up jumping to the slow path. If it jumps, RAX
* and all argument registers are clobbered.
*/
#ifdef CONFIG_RETPOLINE
movq sys_call_table(, %rax, 8), %rax
call __x86_indirect_thunk_rax
#else
call *sys_call_table(, %rax, 8)
#endif
.Lentry_SYSCALL_64_after_fastpath_call:
movq %rax, RAX(%rsp)
1:
Gunakan nomor panggilan sistem yang tidak valid sehingga kode pengiriman kembali begitu saja
eax = -ENOSYS
alih-alih mengirim ke fungsi penanganan panggilan sistem sama sekali.
Kecuali jika ini menyebabkan kernel menggunakan iret
jalur lambat alih-alih sysret
/ sysexit
. Itu mungkin menjelaskan pengukuran yang menunjukkan angka yang tidak valid menjadi 17 siklus lebih lambat dari syscall(SYS_getpid)
, karena penanganan kesalahan glibc (pengaturan errno
) mungkin tidak menjelaskannya. Tetapi dari pembacaan saya tentang sumber kernel, saya tidak melihat alasan mengapa itu masih tidak menggunakan sysret
sambil mengembalikan -ENOSYS
.
Jawaban ini untuk sysenter
, bukan syscall
. Pertanyaan awalnya mengatakan sysenter
/ sysret
(yang aneh karena sysexit
cocok dengan sysenter
, sementara sysret
cocok dengan syscall
). Saya menjawab berdasarkan sysenter
untuk proses 32-bit pada kernel x86-64.
syscall
64-bit asli ditangani lebih efisien di dalam kernel. (Pembaruan; dengan patch mitigasi Meltdown / Spectre, masih dikirimkan melalui C do_syscall_64
dalam 4.16-rc2).
Apa yang terjadi jika Anda menggunakan ABI Linux 32-bit int 0x80 dalam kode 64-bit? T&J memberikan ikhtisar tentang sisi kernel titik masuk panggilan sistem dari mode compat ke kernel x86-64 (entry_64_compat.S
). Jawaban ini hanya mengambil bagian yang relevan dari itu.
Tautan dalam jawaban itu dan ini adalah ke sumber Linux 4.12, yang tidak berisi manipulasi tabel halaman mitigasi Meltdown, sehingga akan signifikan biaya tambahan.
int 0x80
dan sysenter
memiliki titik masuk yang berbeda. Anda mencari entry_SYSENTER_compat
. AFAIK, sysenter
selalu pergi ke sana, bahkan jika Anda menjalankannya dalam proses ruang pengguna 64-bit. Titik masuk Linux mendorong __USER32_CS
konstan sebagai nilai CS yang disimpan, sehingga akan selalu kembali ke ruang pengguna dalam mode 32-bit.
Setelah mendorong register untuk membuat struct pt_regs
di tumpukan kernel, ada TRACE_IRQS_OFF
hook (tidak tahu berapa banyak jumlah instruksi), lalu call do_fast_syscall_32
yang ditulis dalam C. (Native 64-bit syscall
pengiriman dilakukan langsung dari asm, tetapi panggilan sistem compat 32-bit selalu dikirim melalui C).
do_syscall_32_irqs_on
di arch/x86/entry/common.c
cukup ringan:cukup periksa apakah prosesnya dilacak (menurut saya begini caranya strace
dapat menghubungkan panggilan sistem melalui ptrace
), lalu
...
if (likely(nr < IA32_NR_syscalls)) {
regs->ax = ia32_sys_call_table[nr]( ... arg );
}
syscall_return_slowpath(regs);
}
AFAIK, kernel bisa menggunakan sysexit
setelah fungsi ini kembali.
Jadi jalur pengembaliannya sama apakah EAX memiliki nomor panggilan sistem yang valid atau tidak, dan jelas kembali tanpa pengiriman sama sekali adalah jalur tercepat melalui fungsi itu, terutama di kernel dengan mitigasi Spectre di mana cabang tidak langsung pada tabel penunjuk fungsi akan melalui retpoline dan selalu salah prediksi.
Jika Anda benar-benar ingin menguji sysenter/sysexit tanpa semua overhead tambahan itu, Anda harus memodifikasi Linux untuk menempatkan titik masuk yang lebih sederhana tanpa memeriksa pelacakan atau menekan/membuka semua register.
Anda mungkin juga ingin memodifikasi ABI untuk meneruskan alamat pengirim dalam register (seperti syscall
lakukan sendiri) alih-alih disimpan di tumpukan ruang pengguna yang sysenter
Linux saat ini ABI melakukannya; itu harus get_user()
untuk membaca nilai EIP yang harus dikembalikan.
Jika semua overhead ini adalah bagian dari apa yang ingin Anda ukur, Anda pasti sudah siap dengan eax yang memberi Anda -ENOSYS
; paling buruk Anda akan mendapatkan satu cabang tambahan yang hilang dari jangkauan-periksa apakah prediktor cabang panas untuk cabang itu berdasarkan panggilan sistem 32-bit normal.
Dalam tolok ukur ini oleh Brendan Gregg (ditautkan dari posting blog ini yang merupakan bacaan menarik tentang topik ini) close(999)
(atau fd lain yang tidak digunakan) disarankan.