Saya mencoba memahami beberapa pertemuan.
Perakitan sebagai berikut, saya tertarik pada testl
baris:
000319df 8b4508 movl 0x08(%ebp), %eax
000319e2 8b4004 movl 0x04(%eax), %eax
000319e5 85c0 testl %eax, %eax
000319e7 7407 je 0x000319f0
Saya mencoba memahami titik testl
antara %eax
dan %eax
? Saya pikir secara spesifik apa kode ini tidak penting, saya hanya mencoba memahami tes dengan dirinya sendiri - bukankah nilainya selalu benar?
assembly
x86
instructions
maxpenguin.dll
sumber
sumber
test
dancmp
. Ya, saya mengerti bahwa keyakinan Anda berdasarkan komentar Anda kepada Cody. Namun, memasukkannya ke dalam posting saya adalah masalah yang berbeda; ini bukan pernyataan yang ingin saya pertahankan, hanya karena saya tidak tahu apakah itu identik dalam semua kasus.je
,jz
,cmp
, dantest
, dan tidak JE, JZ, CMP, atau UJI. Saya pilih-pilih seperti itu.test a,a
dancmp $0,a
menetapkan bendera secara identik; terima kasih telah menunjukkan bahwa itu adalah klaim yang tidak sepele. re: TEST vstest
.: baru-baru ini saya mulai menggunakan huruf besar semua seperti manual Intel. Tetapi ketika saya berbicara tentang mnemonik AT&T vs mnemonik Intel, saya menggunakantestb
gaya untuk AT&T. IDK jika itu membantu keterbacaan.Arti dari
test
adalah untuk DAN argumen bersama-sama, dan periksa hasilnya untuk nol. Jadi kode ini menguji apakah EAX adalah nol atau tidak.je
akan melompat jika nol.BTW, ini menghasilkan instruksi yang lebih kecil daripada
cmp eax, 0
yang merupakan alasan kompiler umumnya akan melakukannya dengan cara ini.sumber
Instruksi tes melakukan operasi AND yang logis antara operan tetapi tidak menulis hasilnya kembali ke register. Hanya bendera yang diperbarui.
Dalam contoh Anda, test eax, eax akan menyetel flag nol jika eax adalah nol, tanda-flag jika bit tertinggi disetel dan beberapa flag lain juga.
Instruksi Jump if Equal (je) melompat jika flag nol disetel.
Anda dapat menerjemahkan kode ke kode yang lebih mudah dibaca seperti ini:
Itu memiliki fungsi yang sama tetapi membutuhkan beberapa byte lebih banyak ruang kode. Itulah alasan mengapa kompilator mengeluarkan tes, bukan perbandingan.
sumber
test eax, eax
dancmp eax, 0
keduanya menyetel semua tanda, dan menyetelnya ke nilai yang identik. Kedua instruksi mengatur semua tanda "sesuai dengan hasil". Pengurangan0
tidak akan pernah menghasilkan carry atau overflow. Argumen Anda benar untuk jawaban langsung selain 0, tetapi tidak untuk angka 0.test
sepertiand
, kecuali hanya menulis BENDERA, membiarkan kedua inputnya tidak diubah. Dengan dua input yang berbeda , ini berguna untuk menguji apakah beberapa bit semuanya nol, atau jika setidaknya ada satu bit yang disetel. (misalnyatest al, 3
set ZF jika EAX adalah kelipatan 4 (dan dengan demikian keduanya memiliki 2 bit rendah yang nol).test eax,eax
menyetel semua flag dengan cara yang persis sama seperti yangcmp eax, 0
akan :a = a&a = a-0
).(PF seperti biasa hanya diset sesuai dengan low 8 bits )
Kecuali untuk AF yang sudah usang (auxiliary-carry flag, digunakan oleh instruksi ASCII / BCD). TEST membiarkannya tidak terdefinisi , tetapi CMP menetapkannya "sesuai dengan hasil" . Karena mengurangi nol tidak dapat menghasilkan carry dari bit ke-4 hingga ke-5, CMP harus selalu menghapus AF.
TEST lebih kecil (tidak langsung) dan terkadang lebih cepat (dapat melakukan fusi makro menjadi uop pembanding dan cabang pada lebih banyak CPU dalam lebih banyak kasus daripada CMP). Itu membuat
test
idiom yang disukai untuk membandingkan register dengan nol . Ini adalah pengoptimalan lubang intipcmp reg,0
yang dapat Anda gunakan terlepas dari arti semantiknya.Satu-satunya alasan umum untuk menggunakan CMP dengan 0 langsung adalah saat Anda ingin membandingkan dengan operan memori. Misalnya,
cmpb $0, (%esi)
untuk memeriksa penghentian byte nol di akhir string gaya-C dengan panjang implisit.AVX512F menambahkan
kortestw k1, k2
dan AVX512DQ / BW (Skylake-X tetapi bukan KNL) menambahkanktestb/w/d/q k1, k2
, yang beroperasi pada register topeng AVX512 (k0..k7) tetapi tetap mengatur BENDERA biasa sepertitest
halnya, seperti halnya integerOR
atauAND
instruksi. (Semacam seperti SSE4ptest
atau SSEucomiss
: masukan dalam domain SIMD dan menghasilkan BENDERA integer.)kortestw k1,k1
adalah cara idiomatis untuk mencabangkan / cmovcc / setcc berdasarkan hasil perbandingan AVX512, menggantikan SSE / AVX2(v)pmovmskb/ps/pd
+test
ataucmp
.Penggunaan
jz
vs.je
bisa membingungkan.jz
danje
secara harfiah merupakan instruksi yang sama , yaitu opcode yang sama dalam kode mesin. Mereka melakukan hal yang sama, tetapi memiliki arti semantik yang berbeda bagi manusia . Disassembler (dan biasanya output asm dari compiler) hanya akan menggunakan satu, sehingga perbedaan semantik hilang.cmp
dansub
atur ZF ketika kedua inputnya sama (yaitu hasil pengurangannya adalah 0).je
(lompat jika sama) adalah sinonim yang relevan secara semantik.test %eax,%eax
/and %eax,%eax
lagi menyetel ZF saat hasilnya nol, tetapi tidak ada uji "kesetaraan". ZF setelah pengujian tidak memberi tahu Anda apakah kedua operan itu sama. Jadijz
(lompat jika nol) adalah sinonim yang relevan secara semantik.sumber
test
bitwiseand
, mungkin tidak jelas bagi orang yang baru belajar perakitan (dan malas / tidak sadar untuk memeriksa panduan referensi instruksi setiap 60 detik;) :)).kortest*
danktest*
saat saya melakukannya.Potongan kode ini berasal dari subrutin yang diberikan penunjuk ke sesuatu, mungkin beberapa struct atau objek. Baris ke-2 membedakan penunjuk itu, mengambil nilai dari benda itu - mungkin itu sendiri penunjuk atau mungkin hanya int, disimpan sebagai anggota ke-2 (offset +4). Baris ke-3 dan ke-4 menguji nilai ini untuk nol (NULL jika itu pointer) dan lewati beberapa operasi berikut (tidak ditampilkan) jika nilainya nol.
Tes untuk nol terkadang dikodekan sebagai perbandingan dengan nilai nol literal langsung, tetapi kompiler (atau manusia?) Yang menulis ini mungkin mengira operasi test akan berjalan lebih cepat - dengan mempertimbangkan semua hal CPU modern seperti pipelining dan register mengganti nama. Ini dari sekumpulan trik yang sama yang memegang gagasan untuk membersihkan register dengan XOR EAX, EAX (yang saya lihat di plat nomor seseorang di Colorado!) Daripada MOV EAX yang jelas tapi mungkin lebih lambat, # 0 (saya menggunakan notasi yang lebih lama ).
Dalam asm, seperti perl, TMTOWTDI.
sumber
Jika eax nol maka akan melakukan lompatan bersyarat, jika tidak maka akan melanjutkan eksekusi pada 319e9
sumber
Dalam beberapa program, mereka dapat digunakan untuk memeriksa buffer overflow. Di bagian paling atas dari ruang yang dialokasikan, 0 ditempatkan. Setelah memasukkan data ke dalam tumpukan, ia mencari 0 di awal ruang yang dialokasikan untuk memastikan ruang yang dialokasikan tidak meluap.
Itu digunakan dalam latihan stack0 dari exploits-exercise untuk memeriksa apakah itu meluap dan jika tidak ada dan ada nol di sana, itu akan menampilkan "Coba lagi"
sumber
cmp DWORD PTR [esp+0x5c], 0
/jz 0x8048427 <main+51>
akan lebih efisien daripada MOV-load terpisah dan kemudian TEST. Ini bukan kasus penggunaan umum untuk memeriksa nol.kita bisa melihat jg,jle Jika
testl %edx,%edx. jle .L3
kita dapat dengan mudah menemukan jle cocok(SF^OF)|ZF
, jika% edx adalah nol, ZF = 1, tetapi jika% edx bukan nol dan -1, setelah testl, OF = 0, dan SF = 1, jadi benderanya = true, yang menerapkan jump. Maaf, bahasa Inggris saya buruksumber