Halo Saya ingin berbicara tentang kursus saya atau keingintahuan apa yang mengarah.
Untuk waktu yang lama dari tidak ada hubungannya saya menulis program di bawah Symbian. Dan dari waktu ke waktu saya menemukan hal-hal aneh selama kebaktian. Semuanya menunjuk ke utilitas elf2e32. Tugasnya adalah mengubah file biner input dari format elf ke format lain, khusus untuk gambar Symbian-e32. Saya bingung untuk waktu yang lama karena penasaran - bagaimana cara utilitas ini bekerja sama sekali dan mengapa kadang-kadang bermasalah? Beberapa saat kemudian, pertanyaan lain mulai mengganggu saya - topik pekerjaan saja =) Saya memutuskan untuk menggabungkan bisnis dengan kesenangan dan mengunduh kode sumbernya. Dan kita pergi ...
Komit pertama tidak akan
Yang kedua - kami menyertakan ekstensi gcc non-standar, menambahkan kelas yang hilang, fungsi, konstanta dari sumber. Subjek dengan senang hati mengumpulkan dan jatuh. Namun kemajuannya. Kita mulai di bawah debugger - ini menempatkan debugger ke dalam kelas yang hanya menginisialisasi yang lain, yang menginisialisasi berikutnya ... Hore! Fitur nyata! Ayo masuk. Ups Dimana kita? !!! Hentikan debugger! Ahli bedah! Pisau bedah! Alkohol! Mentimun! Lampiran kelas untuk kotak tungku! Berikan nullptr bukan NULL! Kami memiliki C ++ 14! Wow, betapa konstruktor yang menakutkan untuk menginisialisasi semuanya dengan nol! Namun, dan lagi, dan lagi - tetapi dengan kami, C ++ 14 panggilan untuk inisialisasi default untuk kelas! Apa semua ringkas sekarang ...
Baiklah Kami memperbaiki sebanyak mungkin pada suatu waktu. Saya tahu mengapa debugger melompat ke kode sumber seperti pas - aftar mengenai abstraksi, menumbuhkan warisan tingkat 80 dari kelas UseCaseBase :) Kemudian, kelas konstruktor contoh statis untuk kelas Message & ParameterManager terbang dari mata saya. Singleton Myers? Tidak, tidak terdengar. Abstraksi kotak tungku! Revolusi Viva !!! Viva POD !!!
Wow Betapa menariknya pohon ini dibesarkan. Pekerjaan utama dilakukan oleh fungsi BuildAll (). Jika semua parameter ditentukan, fungsi mengumpulkan perpustakaan impor, file menentukan nama fungsi dan variabel dan urutan di mana mereka tersedia di perpustakaan impor dan biner itu sendiri. Semua keturunan dari UseCaseBase mengubah algoritme melalui overloading. Terkadang pada keturunannya kita menyiapkan data tambahan, tetapi paling sering mereka hanya mematikan pembuatan beberapa file. Misalnya, nama file untuk merakit sesuatu tidak ditentukan - kelas baru dibuat. Idiot. Cukup dengan mengganggu eksekusi fungsi-kolektor jika perlu. Mudah untuk memahami tindakan saya B-)
Kami terus menghapus kelas kosong, ganti NULL dengan nullptr_t, ganti range-iterators dengan untuk (otomatis x: *).
Kami memperbaiki kesalahan dalam memproses parameter baris perintah.
Penting untuk memeriksa kode dengan penganalisa statis. Di mana untuk memulai? Hmm, di bawah XP, pilihannya kecil - cppcheck, dan codeblock mendukungnya di luar kotak. Wow, tangkapan yang luar biasa! Bahkan ada hapus untuk char []! Sial, saya tahu di mana setengah dari RAM gratis telah pergi =)
Jadi kami menambahkan file yang dihasilkan dari elf-file libcrypto.dll dan file itu sendiri menjelaskan parameter baris perintah untuk pembuatannya.
Ups CPPCheck salah ... Pasti (a || b) ...
Saya akan mencoba membangun di Visual Studio 15 dan Win10 akan tetap dengan tongkat. Masukan ke mesin virtual. Selesai, unduh, dan jalankan penginstal studio online. Apa? Tidak ingin menyimpan lompatan ke folder bersama dengan tuan rumah ?! Ya, tersedak kamu! Unduh di mana Anda diajar ... Dan sekarang kami mentransfer unduhan ke folder dan memulai instalasi. Apa? Sekali lagi mengabaikan folder bersama ??! Ya, tersedak kamu! Menjadi tempat Anda diajari ...
Pada prinsipnya, selusin sumur berdesir pada satu inti dan 3 gigs dari frame. Studio ke studio! Bijaksana, tapi tidak lama. Kami membuka proyek saya di studio, dan sekali lagi bersumpah di folder ... Berapa banyak yang sudah mungkin? Ya, Anda tersedak ... Kami mengumpulkan, bersumpah pada ekstensi non-standar, STL hash_set. Jauh. Jauh ??? Nyalakan otak =)
Wow, kode yang menarik:
int ElfFileSupplied::UnWantedSymbolp(const char * aSymbol) { static hash_set<const char*, hash<const char*>, eqstr> aSymbolSet; int symbollistsize=sizeof(Unwantedruntimesymbols)/sizeof(Unwantedruntimesymbols[0]); static bool FLAG=false; while(!FLAG) { for(int i=0;i<symbollistsize;i++) { aSymbolSet.insert(Unwantedruntimesymbols[i]); } FLAG=true; } hash_set<const char*, hash<const char*>, eqstr>::const_iterator it = aSymbolSet.find(aSymbol); if(it != aSymbolSet.end()) return 1; else return 0; }
Mari kita berpikir sedikit ... Dan voila:
int ElfFileSupplied::UnWantedSymbolp(const char * aSymbol) { int symbollistsize = sizeof(Unwantedruntimesymbols) / sizeof(Unwantedruntimesymbols[0]); for (int i = 0; i<symbollistsize; i++) { if (strstr(Unwantedruntimesymbols[i], aSymbol)) return 1; } return 0; }
Kecantikan saya ...
Jadi dengan, mengapa program membuat pengecualian jika flag ini tidak diset dengan benar atau tidak disetel sama sekali? Mengapa Anda begitu kejam, cantik jauh ... Mari kita atur ulang bendera ini ke nilai yang aman. Dan bendera ini juga akan menyenangkan ... Dan ini, dan ini, dan ini. Atau mungkin lebih baik meletakkannya di fungsi yang terpisah? Ide bagus! Sebut saja ParameterManager :: CheckOptions ()!
Langkah ke kiri adalah jatuh, langkah ke kanan adalah pengecualian yang tidak tertangkap, lompatan di tempat - terima kasih setidaknya tidak BSOD =)
Membosankan ... Gangguan dan kelengkungan ...
Olya-la !!! Emulasikan CleanUpStack Symbian di STL?:
Pada dasarnya tidak ada yang istimewa:
std::vector<char*> cleanupStack;
Membersihkan:
std::vector<char*>::iterator aPos; char *aPtr; aPos = cleanupStack.begin(); while( aPos != cleanupStack.end() ) { aPtr = *aPos; delete[] aPtr; ++aPos; }
Beberapa kepala cerah bukannya kiri / kanan digunakan l / r. Terima kasih cppcheck.
Ah, malas di depan monitor log cppcheck untuk membongkar ... Apa yang akan ditawarkan github kepada kami? .. Codacy ... Kami menghubungkan proyek ... Saya pikir sedikit dan sudah siap! Sekarang Anda dapat membaca pesan sukses dalam perang melawan kesalahan yang ada di sofa ^^
Jadi, sepertinya tidak bermasalah ... Ayo kumpulkan sesuatu, misalnya libcrypto.dll. Ini berfungsi, meskipun file yang tidak dikompresi adalah seratus byte lebih dari yang dibuat oleh utilitas dari SDK. Selanjutnya, binari yang dibuat oleh versi utilitas ini dan dari SDK akan terus dibandingkan. Opsi baris perintah identik dengan sendirinya.
Dachshund, di mana mendapatkan analog diff untuk file biner? Hmm, dapatkan script di piston. Terlalu banyak informasi - Anda memerlukan sesuatu yang lebih sederhana. Pdf / djvu recognition dll - AlternateReaderRecog.dll adalah pilihan yang bagus, knalpotnya kurang dari 4 kilobyte. Dachshund, offset bervariasi di bagian impor. Kami membukanya di hex editor. Awal adalah sama, dalam versi saya sampah lebih jauh, tepat setelah akhir bagian dalam versi asli. Tetapi dalam versi saya, bagian selanjutnya dimulai 100 byte kemudian. Dengan nilai yang sama dalam byte, file berbeda! Offset selanjutnya menunjukkan alamat yang benar ... Binernya benar !!! Ahhhh !!!
Sebulan kemudian. Jadi dari mana asal seratus byte ini?
Yah, karena tidak jelas cara kerjanya, kami mulai memecah algoritma untuk membuat E32Image. Melanjutkan untuk mengejek AlternateReaderRecog.dll. Kami meningkatkan ukuran biner pada output - tidak mungkin, menimpa bagian memset - tidak mungkin, mengurangi ukuran biner - tidak mungkin. Grrrr. Apa-apaan ini !!! Saya memecahkan knalpot dalam versi rilis, dan memulai debugging? !!! Halo, mulai lagi ... Bagian Soooo musnah - oke! Menambah ukuran biner! Bagus !!! Kurangi ukuran bagian impor! Ada !!! Byte identik dengan bagian yang sama dalam pembuangan utilitas ini dari SDK!
Kami melihat ke dalam kode untuk membuat bagian ini. "sizeof (char *)" - sesuatu kembali ke artikel oleh Andrey Karpov, salah satu pengembang Pvs-studio, bahwa tipe dapat mengambil jumlah memori yang berbeda - dan berapa banyak ruang yang dibutuhkan? MinGW - 8 byte, Visual Studio - 4 !!! Kami membagi 8 byte ini menjadi dua, bisnis sesuatu. FFse! Dan bagaimana bagian kode? Dll ini tanpa variabel global. Tidak ada variabel global - tidak ada bagian ... Mari kita ambil sesuatu yang lebih berat - libcrypto.dll.
File pada output utilitas saya sekarang 100+ byte lebih kecil ... Apa ??? Bagian impor identik dengan byte - bagus. Bagian Kode - Tidak? !!
Secara mata, saya tidak dapat membandingkan dinding teks seperti itu ... Saya akan mencari perbedaan untuk perbandingan byte ...
Setelah beberapa hari, saya masih menemukan game dengan pencarian Google. vbindiff adalah utilitas konsol dengan antarmuka ala Norton Commander, menunjukkan perbedaan antara dua file dalam dua panel horizontal. Untuk pergi ke tempat perbedaan, tekan enter. Bagus! Anda dapat menyeret dua file ke ikon untuk perbandingan dan program akan membukanya! Hebat !!!
Bandingkan - soooo di header crc dan waktu pembuatannya berbeda. Tidak ada yang seperti itu. Di sini byte berbeda, ini seratus lagi ... Wow !!! Puluhan, ratusan, ribuan byte perbedaan? !!! Jadi, lihat, lihat bagian mana mereka berasal ... Kami melihat offset ... Ya, bagian data ...
Kami melakukan trik, seperti untuk bagian impor ... Kami mengatur ulang memset, ada. Tambah ukuran bagian ... Jatuh ... Tambah. Menawarkan tangan dan hati seorang debugger ... Sial. Kami membuka fungsi membuat bagian - bubur dari fungsi ... Grr.
... Ah, besok ... Sampai aku memperbaiki sesuatu yang lain ...
Misalnya, saya akan menambahkan tes, tetapi ada kekacauan sehingga tidak mungkin membagi program menjadi modul-modul kecil. Anda tidak dapat memasukkan tes langsung ke dalam kode - maka Anda akan memahami lobak. Idenya! Konstan meluncurkan program dengan argumen yang berbeda - Saya telah menguji program setiap saat ... Dan mari kita membuat semua ini sebagai skrip terpisah dengan python. Ya, ide bagus, bagus sekali. Skrip harus terus berfungsi saat melaporkan kesalahan pengujian, melaporkannya tetapi tidak mogok. Selesai!
Kami kembali ke domba jantan kami ... Fungsi ini memanggil ini, lalu ini, kami pergi ke sini ... Jadi, Pak, di mana ia membawa saya? Ugh, bingung ... ... Ah, besok ... Sampai aku memperbaiki sesuatu yang lain ...
Dan dua bulan berlalu ...
Sial, di mana bagian kode ini terbentuk? Saya harus cuti akademik, jadi setidaknya saya akan mengetahuinya !!! Soooo Di sini simbol untuk bagian menuju ke input ... Apa yang akan ditampilkan oleh printf? Semuanya tidak sesuai dengan buffer konsol ... Mari kita simpan knalpot ke file ... Sooo, sejauh ini tidak ada yang istimewa ... Berhenti! Garis yang sama !!! Banyak garis identik !!! Dari mana ?! Tambahkan printf ke setiap sumber data (ada cukup kesabaran untuk 3 dari lima, ha). Itu kosong! Kami melihat salah satu dari panggilan fungsi yang tersisa ... Taak. Peningkatan Iterator setelah loop ??? Dan peringatan kode todo? Kami mentransfer ke siklus. Luncurkan !!! Ada kecocokan ukuran! Ada pertandingan byte !!! Diperbaiki !!! git menyalahkan menolak menyebutkan nama pahlawan ... Kami melihat aslinya - ini bukan apa yang saya lakukan. Atau mungkin itu adalah "bom" bagi pengembang yang tidak berafiliasi dengan Nokia? Grrr.
Hati-hati memeriksa tes buang, periksa file byte. Semuanya berfungsi sebagaimana mestinya! Dalam rilis!
Olya! Saatnya untuk Pembersihan Hebat !!! Sudah waktunya untuk mencabut pohon UseCaseBase dengan root !!!
Sebagian besar keturunan sudah aus, kami menghapus fungsi yang berguna untuk kelas generator. Hanya UseCaseBase dan turunannya ElfFileSupplied yang tersisa. UseCaseBase - adalah pembungkus kelas yang memproses parameter perintah dan mendeklarasikan beberapa fungsi virtual murni untuk kelas ElfFileSupplied. Singkatnya, pemain biola tidak diperlukan ... Langitnya biru, bagus ... Satu jam lagi ... Saya akan berurusan dengan kelas ini dan Anda bisa berjalan-jalan ... Dan bernapas di udara, pemanasan, bagus ... Ayo pergi! Jadi, komentari fitur ini. Mengumpulkan! Soooo, Anda perlu memikirkan cara membuatnya kembali dengan indah ... Selesai !!! Fitur selanjutnya! Selesai! Selanjutnya! Selesai! Selesai! Ya! Ya! Ya! Fungsi terakhir ... Ufff. Jalankan setelah perakitan ... Akselerasi kerja tujuh kali lipat? !!! Knalpotnya benar ... Lucu. Versi debug juga menyusut 2 meter? !!! Wow !!! Anda bisa jalan-jalan. Di malam hari? !!! Kaak ??? Di mana hariku? !!! Saya akan meluncurkan tes dan bersantai ... Tes bekerja dengan tenang - Anda dapat bersantai ...
Biarkan saya menulis sesuatu sendiri sekarang ... Oh, kelas yang bekerja dengan fungsi dan variabel yang tersedia dari luar terlihat menyeramkan. Prinsip operasi: membaca dari file, mengurai baris dan menyimpan ke file. Untuk analisis garis, seluruh kelas mie terpilih diisolasi di S ... Sooooh ... Mari kita pikirkan ... Keindahan yang keluar:
kita membaca baris std :: getline (), menghapus spasi dari tepi garis dan parsim.
Untuk dilanjutkan ... Kode sumber - https://github.com/fedor4ever/elf2e32