"Kami malas dan ingin tahu"

Kali ini, alasan posting adalah artikel di majalah bagus yang didedikasikan untuk OS Linux (selanjutnya disebut L), di mana "pakar" yang tertarik memuji pengemudi yang menghubungkan LCD ke papan Raspbery. Karena hal-hal seperti itu (koneksi, bukan OS) masuk dalam ruang lingkup minat profesional saya, saya melihat-lihat artikel dengan penuh perhatian, kemudian menemukan teks sebenarnya dari "pengemudi" dan sedikit terkejut bahwa TI dapat dipuji. Nah, secara umum, tingkat ahli dapat ditentukan jika hanya karena ia dengan keras kepala menyebut program itu sebagai pengemudi, terlepas dari kenyataan bahwa itu sama sekali tidak berarti. Kelihatannya, dan ara dengan dia, Anda tidak pernah tahu apa yang ditulis seseorang untuk dirinya sendiri, tetapi untuk memposting ini di domain publik - "Saya tidak tahu bahwa itu mungkin."
Fakta bahwa alamat perangkat pada bus I2C secara langsung diatur dalam teks program dan untuk perubahannya diperlukan kompilasi ulang (baik karena tidak seluruh kernel) sangat senang. Ngomong-ngomong, saya perhatikan bahwa di forum yang ditujukan untuk L, jawaban paling populer untuk setiap pertanyaan tentang masalah perangkat lunak adalah “membangun kembali versi kernel terbaru”. Pendekatan ini agak aneh bagi saya, mungkin, saya tidak tahu sesuatu. Namun, bagaimanapun, muncul pertanyaan tentang bagaimana parameterisasi driver benar-benar dilaksanakan (di dalam, bukan di luar - semuanya sederhana dan jelas) di A, jawaban yang dikhususkan untuk posting ini.
Bukannya saya terus-menerus menulis driver untuk L, tetapi dengan proses secara keseluruhan saya kenal dan google mengonfirmasi ingatan yang kabur bahwa ada seperangkat makro yang harus digunakan ketika membuat teks sumber modul untuk dapat memberikan parameter operasi padanya, misalnya, alamat perangkat untuk ke bus. Namun demikian, mekanisme proses itu sendiri tidak dijelaskan di mana pun. Saya melihat teks yang sama di banyak tautan (ngomong-ngomong, pertanyaan yang menarik - mengapa melakukan ini, yaitu menempatkan teks orang lain di sumber saya - saya tidak benar-benar mengerti arti dari operasi ini), yang menggambarkan makro di atas. Saya tidak menemukan satu pun menyebutkan mekanisme untuk melakukan operasi, untuk sistem operasi terkenal lainnya (Windows) saya harus menyatakan fakta, dan membatasi diri untuk ini, tetapi salah satu keuntungan dari A adalah ketersediaan teks sumber dan kemampuan untuk menemukan jawaban atas pertanyaan tentang struktur internalnya, apa yang akan kita lakukan. Saya segera mencatat bahwa saya akan mencoba untuk tidak menggandakan informasi yang Anda dapat dapatkan dari sumber lain, dan saya akan membatasi diri hanya untuk apa yang diperlukan untuk memahami teks.
Tetapi, sebelum Anda melihat sumbernya, pertama-tama kami akan berpikir sedikit, tetapi bagaimana kami akan melakukannya jika kami akan mendapatkan tugas serupa (dan tiba-tiba, setelah posting ini, mereka akan mengundang saya ke penambang L, dan Anda tidak akan menolak). Jadi, dimungkinkan untuk membuat modul - unit program yang dirancang khusus yang dapat dimuat ke memori untuk dieksekusi menggunakan beberapa utilitas sistem (insmode - selanjutnya saya), sementara serangkaian karakter dilewatkan sebagai parameter peluncuran. Baris ini dapat menyertakan unit leksikal yang didefinisikan secara ketat, deskripsi format yang ditentukan saat membuat teks sumber modul, dan unit ini berisi informasi yang memungkinkan Anda untuk mengubah nilai variabel internal modul ini.
Mari kita pertimbangkan lebih hati-hati cara menggambarkan unit leksikal di atas, kita perlu ini untuk mempertimbangkan berbagai solusi. Unit analisis ditentukan dengan memanggil makro, yang diinformasikan tentang informasi yang diperlukan - nama variabel yang harus dimodifikasi selama proses pengaturan, nama eksternalnya (biasanya sama dengan yang sebelumnya), jenis variabel dari himpunan terbatas, dan hak akses ke variabel dalam gaya rw-rw-rw. Selain itu, string teks (opsional) yang menjelaskan variabel dapat ditentukan. Jelas, informasi ini diperlukan dan memadai (dalam hubungannya dengan aturan untuk desain unit sintaksis - pemisah dan token) untuk membangun parser daftar parameter yang ditentukan dalam bentuk string teks, tetapi menyisakan ruang untuk implementasi distribusi fungsi antara peserta proses.
Untuk mengkonfigurasi modul, kita perlu:
- form (well, ini pada tahap kompilasi, Anda dapat melakukannya sesuka Anda, meskipun masih menarik bagaimana) dan menyimpan tabel pengaturan di atas
- parsing parameter input menurut tabel ini dan
- membuat perubahan pada area memori tertentu sesuai dengan hasil parsing unit sintaksis.
Kami akan berpikir sedikit dengan gaya "jika saya adalah direktur" dan datang dengan kemungkinan implementasi. Bagaimana kita dapat menerapkan perilaku serupa pada utilitas sistem dan modul - kita akan memulai analisis opsi dalam meningkatkan kompleksitas.
Solusi pertama adalah utilitas Dan hampir tidak melakukan apa-apa, cukup panggil modul yang ditunjukkan padanya dan transfer parameter yang tersisa dalam gaya baris perintah ke sana, dan modul sudah mem-parsingnya, mengandalkan informasi yang tersedia di dalamnya dan membuat modifikasi yang diperlukan. Solusi ini sederhana, dapat dimengerti dan cukup layak, tetapi keadaan berikut ini harus diperhitungkan: analisis parameter tidak boleh diserahkan kepada kehendak penulis modul, karena ini akan memberinya ruang yang tidak dapat diterima, dan bagaimanapun, dua programmer akan selalu menulis tiga opsi pengurai. Jadi kami pergi menemuinya, memungkinkan parameter dari jenis yang tidak terbatas, yang memiliki string teks sebagai nilainya, sudah cukup darinya.
Oleh karena itu, parser standar tertentu harus secara otomatis dimasukkan dalam teks modul, ini mudah diimplementasikan di tingkat substitusi makro.
Solusi ini memiliki dua kelemahan:
- tidak jelas mengapa kita membutuhkannya sama sekali. Dan, Anda dapat langsung memanggil modul dengan parameter dari baris perintah,
- kode modul (bagian inisialisasi) harus berisi ketiga bagian dari informasi yang diperlukan, dan informasi ini diperlukan hanya ketika modul dimulai dan tidak digunakan di masa depan, dan selalu memakan ruang. Segera buat reservasi bahwa informasi ini tentu membutuhkan ruang dalam file, tetapi mungkin tidak masuk ke memori saat memuat modul, jika semuanya dilakukan dengan hati-hati. Untuk melakukan hal itu, kami mengingat arahan _init dan _initdata (ngomong-ngomong, tetapi bagaimana cara kerjanya, kami harus mencari tahu - ini adalah topik dari posting berikutnya - akankah Anda menantikannya?). Tetapi dalam kasus yang terakhir, bagian 2 dan 3 dari informasi dalam file jelas-jelas berlebihan, karena kode yang sama akan ada di banyak modul, secara jahat melanggar prinsip KERING.
Karena kekurangan yang dicatat, pelaksanaan opsi ini sangat tidak mungkin. Selain itu, tidak jelas mengapa kemudian di makro untuk mengatur informasi tentang jenis parameter, karena modul itu sendiri tahu betul apa yang dimodifikasi (meskipun mungkin diperlukan untuk parser ketika memeriksa parameter). Penilaian keseluruhan dari kemungkinan keputusan semacam itu adalah 2-3 persen.
Penyimpangan yang diperlukan tentang kekurangan nomor 2 - saya dibentuk sebagai spesialis pada masa itu ketika 256 kbytes RAM cukup untuk mengatur 4 workstation, 56 kbytes memiliki OS penugasan ganda, dan OS penugasan tunggal mulai bekerja pada 16 kbytes. Yah, 650 kb, yang seharusnya cukup untuk program apa pun, umumnya sesuatu dari bidang fiksi ilmiah. Oleh karena itu, saya terbiasa menganggap RAM sebagai sumber daya yang langka dan saya sangat tidak menyetujui penggunaannya yang boros jika tidak disebabkan oleh keadaan darurat (sebagai aturan, persyaratan kinerja), dan dalam hal ini saya tidak mengamati situasi seperti itu. Karena sebagian besar pembaca saya telah terbentuk dalam realitas yang berbeda, Anda mungkin memiliki penilaian sendiri tentang preferensi opsi ini atau itu.
Solusi kedua - parser itu sendiri ditransfer ke AND, yang mentransfer data yang diekstraksi ke modul (bagian inisialisasi) - nomor dan nilai parameter. Kemudian kami menjaga keseragaman parameter dan mengurangi persyaratan untuk ukuran modul. Pertanyaannya tetap, bagaimana memberikan AND daftar parameter yang mungkin, tetapi ini disediakan oleh makro dengan membuat struktur modul yang telah ditentukan dan lokasi blok di beberapa tempat tertentu (file atau memori). Solusinya lebih baik daripada yang sebelumnya, tetapi masih kelebihan memori dalam modul. Secara umum, saya suka solusinya, karena parser saya (yang lebih buruk daripada semua programmer lain, saya punya parser saya sendiri, bukan tanpa cacat, tapi jelas tidak fatal) bekerja sesuai dengan skema ini, mengembalikan jumlah aturan yang teridentifikasi dan nilai ke program utama parameter. Namun demikian, probabilitas penerapan opsi khusus ini tidak terlalu tinggi - 5 persen.
Sub-opsi dari solusi kedua adalah untuk mentransfer parameter yang diekstraksi bukan ke bagian awal modul, tetapi langsung ke bagian kerja yang dimuat, misalnya, melalui ioctl - persyaratan memori sama. Kami memiliki peluang unik untuk mengubah parameter "on the fly", yang tidak diterapkan di versi lain. Tidak terlalu jelas mengapa kita mungkin membutuhkan fitur seperti itu, tetapi itu terlihat indah. Kerugiannya adalah 1) Anda harus memesan bagian dari area fungsi terlebih dahulu untuk permintaan yang mungkin tidak digunakan, dan 2) kode pengubah harus selalu ada dalam memori terus-menerus. Perkiraan probabilitas implementasi - persen 5.
Solusi ketiga adalah mentransfer ke Dan juga modifikasi parameter. Kemudian, dalam proses memuat kode biner modul Dan, itu dapat memodifikasi data dalam memori menengah dan memuat kode driver dengan parameter yang diubah ke tempat penyebaran permanen, atau membuat modifikasi ini langsung di area memori di mana biner dimuat, dan tabel parameter yang ada dalam file ada di memori dapat memuat dan tidak menempatinya (ingat tentang arahan). Keputusan bertanggung jawab, itu akan membutuhkan, seperti yang sebelumnya, keberadaan area komunikasi yang telah ditentukan antara modul dan DAN untuk menyimpan deskripsi parameter, tetapi lebih jauh mengurangi persyaratan untuk memori yang berlebihan dalam modul. Segera, kami mencatat kelemahan utama dari solusi semacam itu - ketidakmampuan untuk mengontrol nilai parameter dan konsistensinya, tetapi tidak ada yang bisa dilakukan. Ini solusi yang cukup normal, kemungkinan besar adalah - 75 persen.
Varian dari solusi ketiga - informasi tentang parameter tidak disimpan dalam modul itu sendiri, tetapi dalam beberapa file tambahan, maka tidak ada kelebihan memori dalam modul. Pada prinsipnya, hal yang sama dapat dilakukan pada versi sebelumnya, ketika modul berisi bagian konfigurasi, yang digunakan DAN selama proses boot, tetapi tidak dimuat ke dalam RAM yang berisi bagian modul yang sebenarnya dapat dieksekusi dari modul. Dibandingkan dengan versi sebelumnya, file tambahan ditambahkan dan tidak jelas apa yang kita bayar, tetapi mungkin mereka melakukan arahan inisialisasi sebelum penemuan - 5 persen.
7 persen sisanya akan dibiarkan untuk opsi lain yang saya tidak bisa datang dengan. Nah, sekarang karena fantasi kita telah habis dengan sendirinya (milik saya pasti, jika ada ide lagi, silakan tanyakan dalam komentar), kita akan mulai mempelajari sumber L.
Untuk mulai dengan, saya perhatikan bahwa, tampaknya, seni mendistribusikan teks sumber ke file hilang bersama dengan OS, yang muat dalam 16 kb, karena struktur direktori, nama dan nama file mereka terhubung dengan konten sedikit lebih daripada tidak sama sekali. Dengan adanya inklusi tertanam, studi klasik sumber yang diunduh dengan bantuan editor berubah menjadi pencarian yang aneh dan tidak akan produktif. Untungnya, ada utilitas menarik Elixir, tersedia online, yang memungkinkan Anda untuk melakukan pencarian kontekstual, dan di sini dengan itu prosesnya menjadi jauh lebih menarik dan berbuah. Saya melakukan penelitian lebih lanjut di situs elixir.bootlin.com. Ya, situs ini bukan kumpulan resmi keju kernel, tidak seperti kernel.org, tetapi mari kita berharap bahwa kode sumber untuk mereka adalah identik.
Pertama, mari kita lihat makro untuk menentukan parameter - pertama, kita tahu namanya, dan kedua, itu harus lebih mudah (yeah, sekarang). Itu terletak di file moduleparam.h - ini cukup masuk akal, tapi ini kejutan yang menyenangkan, mengingat apa yang akan kita lihat nanti. Makro
{0}module_param(name,type,perm)
adalah pembungkus berakhir
{0a}module_param_named(n,n,t,p)
- Gula sintaksis untuk kasus yang paling umum. Pada saat yang sama, untuk beberapa alasan, penghitungan nilai yang diizinkan dari salah satu parameter, yaitu jenis variabel, diberikan dalam komentar sebelum teks pembungkus, dan bukan makro kedua, yang benar-benar melakukan pekerjaan dan dapat digunakan secara langsung.
Makro {0a} berisi panggilan ke tiga makro
{1}param_check_##t(n,&v)
(ada satu set makro untuk semua jenis yang valid)
{2}module_param_cb(n,&op##t,&v,p)
dan
{3}__MODULE_PARM_TYPE(n,t)
(perhatikan nama, pesona), dan yang pertama digunakan di tempat lain, yaitu, rekomendasi Occam dan prinsip KISS juga dengan berani diabaikan oleh pencipta A - tampaknya, semacam landasan untuk masa depan. Tentu saja, ini hanya makro, tetapi mereka tidak memerlukan biaya apa pun, tapi tetap ....
Makro pertama dari ketiga makro {1}, sesuai namanya, memeriksa korespondensi jenis parameter dan pembungkusnya
__param_check(n,p,t)
Perhatikan bahwa pada tahap pertama pembungkus, tingkat abstraksi makro menurun, dan pada tahap kedua, itu mungkin meningkat dengan cara yang berbeda, dan sepertinya bagi saya itu bisa lebih sederhana dan lebih logis, terutama mengingat bahwa rata-rata makro tidak digunakan di tempat lain. Oke, mari kita coba cara lain untuk memeriksa parameter makro di celengan dan lanjutkan.
Tapi dua makro berikutnya sebenarnya menghasilkan elemen dari tabel parameter. Mengapa tidak bertanya kepada saya dua, dan bukan satu, saya sudah lama tidak lagi memahami logika pencipta L. Kemungkinan besar, berdasarkan perbedaan gaya kedua makro ini, dimulai dengan namanya, yang kedua ditambahkan kemudian untuk memperluas fungsionalitas, dan memodifikasi struktur yang ada Itu tidak mungkin, karena pada awalnya mereka menyesal mengalokasikan tempat untuk menunjukkan parameter opsi. Makro {2}, seperti biasa, menutupi makro dari kami
{2a}_module_param_call(MODULE_PARAM_PREFIX,n,ops,arg,p,-1,0)
(Lucu makro ini tidak dipanggil langsung ke mana pun kecuali 8250_core.c, di mana ia disebut dengan parameter tambahan yang sama), tetapi yang terakhir sudah menghasilkan kode sumber.
Sebuah komentar kecil - selama pencarian kami memastikan bahwa navigasi teks berfungsi dengan baik, tetapi ada dua keadaan yang tidak menyenangkan: pencarian dengan nama fragmen tidak berfungsi (check_param_ tidak ditemukan, walaupun check_param_byte ditemukan) dan pencarian hanya bekerja pada deklarasi objek (variabel tidak ditemukan, kemudian ditemukan dalam file ini oleh ctrF, tetapi pencarian berdasarkan sumber tidak terdeteksi). Tidak terlalu menggembirakan, karena kita mungkin perlu mencari objek di luar file saat ini, tetapi "pada akhirnya, kita tidak punya yang lain."
Sebagai hasil dari karya {1} dalam teks dari modul yang dikompilasi di hadapan dua baris berikut
module_param_named(name, c, byte, 0x444); module_param_named(name1, i, int, 0x444);
sebuah fragmen dari tipe di bawah ini muncul
static const char __param_str_name[] = "MODULE" "." "name"; static struct kernel_param const __param_name \ __attribute__((__used__)) \ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ = { __param_str_name, ((struct module *)0), ¶m_ops_byte, (0x444), -1, 0, { &c } }; static const char __UNIQUE_ID_nametype72[] \ __attribute__((__used__)) __attribute__((section(".modinfo"), unused, aligned(1))) \ = "parmtype" "=" "name" ":" "byte"; static const char __param_str_name1[] = "MODULE" "." "name1"; static struct kernel_param const __param_name1 \ __attribute__((__used__)) \ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ = { __param_str_name1, ((struct module *)0), ¶m_ops_int, (0x444), -1, 0, { &i } }; static const char __UNIQUE_ID_name1type73[] __attribute__((__used__)) \ __attribute__((section(".modinfo"), unused, aligned(1))) \ = "parmtype" "=" "name1" ":" "int";
(pada kenyataannya, file baris tunggal dihasilkan di sana, saya memecahnya menjadi beberapa baris untuk memudahkan peninjauan) dan kita dapat segera mengatakan bahwa tidak ada petunjuk tentang dimasukkannya bagian program parser atau modul untuk menetapkan nilai ke parameter dalam teks sumber, sehingga opsi 1 dan 2 dapat dianggap dikecualikan dari pertimbangan lebih lanjut. Kehadiran atribut khusus untuk penghubung, seolah-olah, mengisyaratkan keberadaan wilayah komunikasi yang terletak di beberapa tempat yang telah ditentukan di mana deskripsi parameter ditransmisikan. Pada saat yang sama, kami mencatat dengan bingung tidak adanya deskripsi dari blok yang dihasilkan dari parameter yang mungkin dalam bentuk teks yang dapat digunakan oleh modul parser. Jelas bahwa kode yang ditulis dengan baik mendokumentasikan diri, tetapi tidak pada tingkat yang sama yang lagi-lagi tidak meningkatkan kemungkinan opsi 1 atau 2, dengan parser yang ditulis oleh pengembang modul.
Kombinasi __used__ dan atribut yang tidak digunakan pada saat yang sama terlihat lucu di baris yang dibuat terakhir, terutama jika Anda melihat fragmen kode makro berikutnya
#if GCC_VERSION < 30300 # define __used __attribute__((__unused__)) #else # define __used __attribute__((__used__)) #endif
Apa kelincahan yang dimiliki oleh para pengembang A, cara pikiran mereka yang berliku-liku dalam kode. Saya tahu bahwa Anda dapat menggunakan kedua bentuk penulisan atribut, tetapi mengapa melakukan ini pada baris yang sama - Saya tidak mengerti.
Satu lagi fitur menarik dari kode yang dihasilkan dapat dicatat - duplikasi informasi tentang nama variabel dan jenisnya. Belum jelas mengapa ini dilakukan, tetapi fakta itu sendiri tidak diragukan. Tentu saja, informasi ini koheren, karena dibangun dalam mode otomatis, dan koherensi ini akan dipertahankan ketika teks sumber berubah (dan ini bagus), tetapi digandakan (dan ini buruk), mungkin nanti kita akan memahami perlunya solusi seperti itu. Juga, kebutuhan untuk membentuk nama unik menggunakan nomor baris dari kode sumber tetap tidak jelas, karena baris yang dihasilkan pertama kali melakukannya tanpa itu.
Catatan lain - mencari tahu apa definisi parameter berubah menjadi bukan tugas yang sepele, tapi berkat MinGW, itu masih selesai. Di bawah tenda ada pengetatan dan pengeleman ganda parameter, pembentukan nama unik, serta trik rumit lainnya untuk bekerja dengan makro, tapi saya hanya menyajikan hasilnya. Meringkas hasil antara, saya dapat mengatakan bahwa belajar makro A bukan dari apa yang ingin saya cari nafkah, itu hanya mungkin sebagai hiburan, tetapi kami melanjutkan.
Kami tidak akan memajukan pemahaman lebih lanjut tentang makro dalam memahami tugas, jadi kami beralih ke kode sumber utilitas Dan dan mencoba untuk memahami apa fungsinya.
Pertama-tama, kami kagum melihat bahwa keju yang dibutuhkan tidak termasuk dalam sumber kernel. Ya, saya siap untuk setuju bahwa saya adalah utilitas dan berinteraksi dengan kernel melalui titik masuk untuk memuat modul, tetapi setiap buku tentang driver L memberitahu kita tentang utilitas ini, sehingga kurangnya versi "resmi" dari sumbernya di suatu tempat dekat sumber penyebab kernel salah paham padaku. Baiklah, oke, Google tidak mengecewakan kami, dan kami semua sama-sama mengeluarkan keju.
Yang luar biasa kedua adalah bahwa utilitas ini dibentuk dari sebuah paket yang namanya sama sekali tidak terkait dengan namanya, ada lebih dari satu paket seperti itu, dan masing-masing diberi nama dengan caranya sendiri di tempat yang berbeda - lucu, untuk sedikitnya. Jika Anda telah menginstal L, maka dengan perintah - Anda dapat mengetahui dari paket mana Utilitas dan dirakit dan kemudian mencarinya, tetapi jika kita melakukan penelitian teoritis (saya pribadi tidak menyimpan L pada komputer di rumah saya karena beberapa alasan, beberapa di antaranya saya Saya menyatakan posting saya, petinju teoretis), maka metode ini tidak tersedia untuk kita dan semua yang tersisa adalah pencarian di Internet, untungnya, itu memberikan hasil.
Nah, hal luar biasa ketiga adalah bahwa nama utilitas itu sendiri tidak muncul di mana pun dalam kode sumber, tidak digunakan dalam nama file dan hanya ditemukan di file make, saya tahu bahwa di C kita diwajibkan untuk menamai fungsi utama, dan ini tidak dibahas (secara pribadi, saya tidak di Saya senang dengan ini, karena Pascal manja, tetapi mereka tidak meminta pendapat saya ketika mendesain bahasa), tetapi setidaknya mungkin untuk menulis nama eksternal utilitas dalam komentar. Catatan yang diperlukan - banyak hal dalam bahasa C dilakukan pada prinsip "sangat biasa dengan kami", mungkin sulit untuk membuat hal-hal berbeda kadang-kadang, atau bahkan tidak mungkin, tetapi apa yang dapat Anda lakukan sekarang, menyeret koper tanpa pegangan lebih jauh.
Kami menemukan dua paket yang berisi teks sumber. Dan, kami juga menemukan keju pada github, kami melihat bahwa mereka identik dan menganggapnya seperti inilah kode sumber dari utilitas tersebut. Selanjutnya, kita hanya mempelajari file pada git, terutama karena di sini hanya disebut insmod.c, kita menemukan bahwa Dan untuk permulaan, itu mengkonversi daftar parameter menjadi satu string null panjang, di mana elemen individu dipisahkan oleh spasi. Setelah ini, ia memanggil dua fungsi, yang pertama disebut grub_file dan jelas membuka biner, sedangkan yang kedua memiliki nama init_module dan mengambil pointer ke file yang terbuka dengan modul biner dan serangkaian parameter dan disebut load_module, yang menunjukkan tujuan fungsi ini sebagai memuat dengan modifikasi parameter.
Kita beralih ke teks dari fungsi kedua, yang terletak di file ... dan di sini adalah mengecewakan - tidak ada di salah satu file dari repositori yang dipelajari di Geet (well, ini hanya logis, ini adalah bagian dari kernel dan tempatnya tidak di sini) bukan. Google lagi-lagi terburu-buru untuk membantu dan mengembalikan kami ke keju kernel di bawah Elixir dan file module.c. Perlu dicatat bahwa, secara mengejutkan, nama file yang berisi fungsi-fungsi untuk bekerja dengan modul terlihat logis, saya bahkan tidak mengerti bagaimana menjelaskannya, ini mungkin terjadi secara tidak sengaja.
Sekarang menjadi jelas bagi kami kurangnya teks Dan di samping kernel - sebenarnya hampir tidak ada apa-apa, hanya mentransfer parameter dari satu bentuk ke bentuk lain dan mentransfer kontrol ke inti itu sendiri, sehingga bahkan tidak layak untuk diletakkan di sebelahnya. Mulai saat ini, menjadi jelas bahwa tidak ada informasi eksternal yang jelas tentang struktur parameter, karena kernel melewatkannya melalui makro sendiri dan mengetahui segalanya tentang mereka dengan sempurna, dan sisanya tidak perlu tahu apa-apa tentang struktur internal (mengingat fakta bahwa sumbernya) tersedia untuk dilihat, beberapa komentar tidak ada salahnya, tetapi pada prinsipnya itu benar-benar semakin jelas bahkan tanpa mereka), tetapi sejauh ini hampir tidak pernah menyoroti penerapan mekanisme eksekusi itu sendiri.
Catatan - mengenai transfer kontrol ke kernel, saya sedikit bersemangat, untuk sekarang kita melihat penggunaan fungsi dalam sumber kernel untuk memastikan, apakah bagian biner akan dihubungkan ke modul, atau jika terletak pada gambar kernel itu sendiri, masih belum diketahui. Fakta bahwa titik masuk ke pemrosesan fungsi ini dibingkai dengan cara khusus, melalui SYSCALL_DEFINE3, secara tidak langsung memberikan kesaksian mendukung opsi kedua, tetapi saya telah lama memahami bahwa ide-ide saya tentang logis dan tidak logis, dapat diterima dan tidak dapat diterima, juga tentang yang dibolehkan dan tidak dapat diterima, sangat signifikan menyimpang dari pengembang L.
Catatan - satu lagi kerikil di taman pencarian bawaan - ketika mencari definisi untuk makro ini, saya melihat banyak tempat untuk menggunakannya sebagai fungsi, di antaranya definisi itu sebagai makro menyembunyikan sangat sederhana.
Misalnya, saya tidak mengerti mengapa utilitas eksternal diperlukan untuk menerjemahkan parameter dari bentuk standar untuk sistem operasi (agrc, argv) ke dalam bentuk string yang diakhiri null dengan spasi sebagai pemisah, yang selanjutnya diproses oleh modul sistem - pendekatan ini agak melampaui tambang kemampuan kognitif. Terutama, mengingat fakta bahwa pengguna memasukkan string parameter dalam bentuk string yang diakhiri nol dengan spasi sebagai pemisah, dan utilitas dalam kernel mengubahnya menjadi bentuk (argc, argv). Sangat mengingatkan pada lelucon lama "Kami mengeluarkan ketel dari kompor, menuangkan air keluar dari situ dan mendapatkan masalah yang solusinya sudah diketahui." Dan karena saya mencoba mematuhi prinsip, “Anggap teman bicara Anda tidak lebih bodoh dari diri Anda, sampai dia membuktikan sebaliknya. Dan bahkan setelah itu, Anda bisa saja salah, ”dan sehubungan dengan pengembang A, frasa pertama sudah pasti valid, itu berarti saya salah paham sesuatu, tapi saya tidak terbiasa. Jika ada yang bisa menawarkan penjelasan yang masuk akal tentang fakta konversi ganda, maka saya bertanya di komentar. Tapi kami melanjutkan penyelidikan.
Prospek untuk penerapan opsi 1 dan 2 menjadi "sangat lemah terlihat" (kata-kata menarik dari artikel baru-baru ini tentang prospek pengembangan ADC kecepatan tinggi domestik), karena akan sangat aneh untuk memuat modul ke dalam memori menggunakan fungsi kernel, dan kemudian memberikan kontrol kepadanya untuk mengimplementasikan kernel fungsi dibangun ke dalam tubuhnya. Dan yang pasti, dalam teks fungsi load_module, kami cukup cepat menemukan panggilan parse_args - sepertinya kami berada di jalur yang benar. Selanjutnya, kita dengan cepat menelusuri rantai panggilan (seperti biasa, kita akan melihat fungsi wrapper dan makro wrapper, tetapi kita sudah terbiasa menutup mata terhadap lelucon lucu dari pengembang) dan kita menemukan fungsi parse_one, yang menempatkan parameter yang diperlukan di tempat yang tepat.
Perhatikan bahwa tidak ada pemeriksaan pada validitas parameter, seperti yang diharapkan, karena kernel, tidak seperti modul itu sendiri, tidak tahu apa-apa tentang tujuannya. Ada pemeriksaan sintaks dan jumlah elemen dalam array (ya, mungkin ada array integer sebagai parameter) dan ketika kesalahan semacam ini terdeteksi, pemuatan modul berhenti, tetapi tidak lebih. Namun, tidak semuanya hilang, karena setelah memuat kontrol ditransfer ke fungsi init_module, yang dapat melakukan validasi yang diperlukan dari parameter yang ditetapkan dan, jika
lemparan save diperlukan, hentikan proses booting.
Namun, kami benar-benar mengabaikan pertanyaan tentang bagaimana fungsi parsing mengakses array sampel parameter, karena tanpa ini, parsing agak sulit. Pandangan cepat pada kode menunjukkan bahwa hack kotor telah diterapkan, trik yang jelas - dalam file biner, fungsi find_module_sections mencari bagian bernama __param, membagi ukurannya dengan ukuran catatan (lebih banyak) dan mengembalikan data yang diperlukan melalui struktur. Saya masih akan meletakkan huruf p di depan nama parameter dari fungsi ini, tetapi ini adalah masalah selera.
Segala sesuatu tampaknya jelas dan dapat dimengerti, satu-satunya hal yang mengkhawatirkan adalah kurangnya atribut __initdata pada data yang dihasilkan, dapatkah itu benar-benar tetap dalam memori setelah inisialisasi, mungkin atribut ini dijelaskan di suatu tempat di bagian umum, misalnya, dalam data linker, jujur saja , malas melihat, melihat prasasti.
Kesimpulannya - akhir pekan bermanfaat, menarik untuk memahami kode sumber L, mengingat sesuatu dan mempelajari sesuatu, tetapi pengetahuan tidak pernah berlebihan.
Nah, dalam asumsi saya, saya tidak mengira, di L ada opsi yang ternyata 7 persen tersisa, tapi rasanya tidak jelas.
Kesimpulannya, tangisan Yaroslavna (bagaimana kita bisa tanpanya) mengapa saya harus mencari informasi yang diperlukan (maksud saya bukan dapur internal, tetapi presentasi eksternal) dari berbagai sumber yang tidak memiliki status resmi, di mana ada dokumen yang mirip dengan buku itu
“Perangkat lunak komputer. Sistem operasi fungsional.
RAFOS. Panduan Pemrogram Sistem. ", Atau apakah mereka tidak lagi?