Dalam ruang pengguna Linux, kita selalunya perlu memanggil panggilan sistem. Mari kita ambil Linux versi 2.6.37 sebagai contoh untuk menjejaki pelaksanaan panggilan sistem baca. Pelaksanaan panggilan sistem mungkin berbeza antara versi Linux.
Dalam sesetengah aplikasi, kita boleh melihat definisi berikut:
scssCopy code #define real_read(fd, buf, count ) (syscall(SYS_read, (fd), (buf), (count)))
Sebenarnya, yang sebenarnya dipanggil ialah fungsi sistem syscall(SYS_read), iaitu fungsi sys_read(). Dalam versi Linux 2.6.37, fungsi ini dilaksanakan melalui beberapa definisi makro.
Panggilan sistem Linux (SCI, antara muka panggilan sistem) sebenarnya adalah proses pengagregatan dan penguraian berbilang saluran Titik pengagregatan ialah titik masuk gangguan 0x80 (struktur sistem X86). Maksudnya, semua panggilan sistem diagregatkan dari ruang pengguna ke titik gangguan 0x80, dan nombor panggilan sistem tertentu disimpan pada masa yang sama. Apabila pengendali gangguan 0x80 sedang berjalan, panggilan sistem yang berbeza akan diproses secara berasingan mengikut nombor panggilan sistem, iaitu, fungsi kernel yang berbeza akan dipanggil untuk diproses.
Terdapat dua cara untuk menyebabkan panggilan sistem:
(1) int $0×80, ini adalah satu-satunya cara untuk menyebabkan panggilan sistem dalam versi kernel Linux lama.
(2) arahan pemasangan sysenter
Dalam kernel Linux, kita boleh menggunakan takrifan makro berikut untuk membuat panggilan sistem.
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) { struct file *file; ssize_t ret = -EBADF; int fput_needed; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_read(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } return ret; }
Takrifan makro SYSCALL_DEFINE3 adalah seperti berikut:
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
## bermaksud menggantikan terus aksara dalam makro,
Jika name = read, maka __NR_##name digantikan dengan __NR_read dalam makro. NR##nama ialah nombor panggilan sistem, ## merujuk kepada dua pengembangan makro. Iaitu, gantikan "nama" dengan nama panggilan sistem sebenar, dan kemudian kembangkan __NR.... Jika nama == ioctl, ia ialah __NR_ioctl.
#ifdef CONFIG_FTRACE_SYSCALLS #define SYSCALL_DEFINEx(x, sname, ...) \ static const char *types_##sname[] = { \ __SC_STR_TDECL##x(__VA_ARGS__) \ }; \ static const char *args_##sname[] = { \ __SC_STR_ADECL##x(__VA_ARGS__) \ }; \ SYSCALL_METADATA(sname, x); \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) #else #define SYSCALL_DEFINEx(x, sname, ...) \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) #endif
Tidak kira sama ada makro CONFIG_FTRACE_SYSCALLS ditakrifkan atau tidak, takrif makro berikut akhirnya akan dilaksanakan:
__SYSCALL_DEFINEx(x, sname, VA_ARGS)
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS #define SYSCALL_DEFINE(name) static inline long SYSC_##name #define __SYSCALL_DEFINEx(x, name, ...) \ asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)); \ static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)); \ asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__)) \ { \ __SC_TEST##x(__VA_ARGS__); \ return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__)); \ } \ SYSCALL_ALIAS(sys##name, SyS##name); \ static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)) #else /* CONFIG_HAVE_SYSCALL_WRAPPERS */ #define SYSCALL_DEFINE(name) asmlinkage long sys_##name #define __SYSCALL_DEFINEx(x, name, ...) \ asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)) #endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */
Jenis takrifan makro berikut akhirnya akan dipanggil:
asmlinkage sys panjang##nama(__SC_DECL##x(VA_ARGS))
Itulah fungsi sistem sys_read() yang kami nyatakan sebelum ini.
asmlinkage memberitahu pengkompil untuk mengekstrak hanya argumen fungsi dari timbunan. Semua panggilan sistem memerlukan kelayakan ini! Ini serupa dengan definisi makro yang disebutkan dalam artikel quagga kami sebelum ini.
Iaitu, kod berikut dalam definisi makro:
struct file *file; ssize_t ret = -EBADF; int fput_needed; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_read(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } return ret;
Analisis kod:
jika (fail->f_op->baca)
ret = fail->f_op->baca(fail, buf, kiraan, pos);
Pada ketika ini, pemprosesan yang dilakukan oleh lapisan sistem fail maya selesai, dan kawalan diserahkan kepada lapisan sistem fail ext2.
Atas ialah kandungan terperinci Pengesanan kernel Linux panggilan sistem Syscall. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!