Di Linux, terdapat banyak idea pengaturcaraan yang patut dipelajari. Ramai pakar teknikal telah menggunakan idea dan mekanisme ini pada pengaturcaraan mikropengawal, terutamanya mensimulasikan proses pemulaan automatik kernel Linux dalam STM32.
Secara umumnya, kami mengikut rutin tertentu semasa menulis program. Kami akan melaksanakan fungsi satu demi satu mengikut logik urutan.
Jika logiknya sangat kompleks dan melibatkan banyak modul, maka kod yang dilaksanakan secara berurutan akan menjadi kembung dan modul akan digabungkan dengan sangat rapat. Terdapat pelbagai pemacu persisian dalam kernel Linux, dan hampir mustahil untuk melaksanakannya secara logik dalam urutan.
Dan kod kenrel boleh mempunyai jumlah kod yang begitu besar, ia besar tetapi tidak kemas, ia memisahkan setiap peringkat dan modul dengan berkesan, dan sejumlah besar kod disusun secara logik bersama, dan initcall ini memainkan peranan penting.
Dengan meniru kaedah ini, kami akhirnya mengosongkan kod fungsi utama dalam gambar, memisahkan logik ini, dan mencapai fungsi yang sama.
Cara melaksanakan fungsi sedemikian memerlukan pengetahuan latar belakang:
1. Organisasi kod program
2. Pengetahuan berkaitan skrip pautan.
3. Aplikasi penunjuk fungsi.
Organisasi kod, seperti gambar, anda perlu tahu pembolehubah a, b dan fungsi penunjuk f, f2 disimpan di bahagian mana program, anda boleh membaca ini stm32 pelaksanaan kod permulaan | di atas a, f disimpan dalam segmen bss, b, f2 disimpan dalam segmen data, kerana nilai awal telah diberikan, dan melaksanakan intcall ini akan meletakkan data yang perlu dimulakan secara automatik ke dalam segmen tersuai, seperti .initcall.
Bagaimana untuk meletakkannya dalam bahagian tertentu, anda perlu menggunakan kata kunci atribut((bahagian)) untuk menukar bahagian storan data.
Atur cara semasa disusun menggunakan segmen ini Kecuali untuk .isr_vector, yang juga ditambah, yang lain adalah yang lalai pengkompil.
Tambahkan sekeping kod dahulu:
Sudah tentu ini tidak mencukupi, anda juga perlu memberitahu penghubung (LD) untuk memautkan bahagian .initcall ke dalam program, jadi bahagian ini juga perlu diubah suai.
Bahagian ini diselaraskan dengan 8 bait, mentakrifkan dua pembolehubah global dan memautkan data ini dalam urutan 0-5 Dengan kedua-dua pengubahsuaian ini, mari kita lihat setiap bahagian program.
Seperti gambar:
Terdapat kotak merah tambahan untuk bahagian .initcalls Bahagian ini berjumlah 8 bait, bermula dari 0x80005a8.
Mari kita lihat situasi khusus perenggan ini, menggunakan alat readelf.
Ia sepadan dengan alat saiz di atas, dan alamat kotak hijau ialah SystemInit (0x08000231, mod endian kecil.)
Jadi melalui atribut dan mengubah suai skrip pautan, pembolehubah penunjuk fungsi diletakkan di bahagian .initcall.
Jadi bagaimana untuk memanggil fungsi ini? Ia serupa dengan data segmen data permulaan sebelumnya Ia merentasi segmen ini, kemudian mengeluarkan alamat fungsi, dan kemudian menukar alamat dalam segmen itu secara paksa kepada penunjuk fungsi, dan kemudian memanggilnya secara langsung. .
Gambar yang dilaksanakan adalah untuk mengambil alamat fungsi dari bahagian .initcall dan kemudian memanggilnya secara terus Sangat mudah untuk mengelirukan alamat fungsi dengan alamat pembolehubah penunjuk fungsi.
Dengan kod yang diubah suai seperti ini, fungsi permulaan automatik memang boleh dilaraskan, tetapi setiap kali saya perlu menulis bahagian panjang statik initcall_t __ attribute__(( __ used__,__ section__(“.initcall.0.init”) )), iaitu Tidak Selesa Diubah suai melalui makro dalam kernel Linux.
Begitu juga dengan yang ini.
Tambah beberapa makro yang dilaksanakan dalam susunan logik program
0, low_level_init Contohnya, mulakan jam asas sistem
1, arch_init Contohnya, letakkan seni bina CPU d seperti memulakan beberapa permulaan NVIC.
2. dev_init memulakan modul persisian, seperti i2c, flash, spi, dll.
3. board_init membuat beberapa tetapan untuk papan perkakasan tertentu.
4 os_init Beberapa tetapan sistem pengendalian, seperti sistem fail, susunan protokol rangkaian, dsb.
5, app_init akhirnya menjalankan program pengguna.
Ubah suai program anda sendiri dan gunakan makro sebaliknya. Dengan cara ini, panggilan ke do_initcalls akan dilaksanakan dalam susunan 0, 1 hingga 5.
Akhirnya mari kita lihat bahagian initcall:
Dengan cara ini, cuma tambahkan sesuatu seperti dev_init(), app_init() pada fungsi permulaan automatik, dan ia akan dipanggil secara automatik, tanpa perlu melaksanakannya satu demi satu dalam fungsi utama.
Sebagai contoh, permulaan kawalan i2c diletakkan dalam dev_init Terdapat banyak peranti hamba i2c yang tergantung di bawah untuk menukar yang asal , tahap gandingan yang tinggi antara modul yang dipisahkan.
Ini mensimulasikan permulaan dan pengesahan kenerl Linux berjaya, dan akhirnya dimuat naik ke perpustakaan.
Atas ialah kandungan terperinci Simulasikan proses pemulaan automatik Linux pada STM32. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!