Saya ingin tahu apa perbedaan antara instruksi ini:
MOV AX, [TABLE-ADDR]
dan
LEA AX, [TABLE-ADDR]
assembly
x86
instruction-set
naveen
sumber
sumber
Jawaban:
LEA
berarti Muat Alamat EfektifMOV
berarti Nilai BebanSingkatnya,
LEA
muat penunjuk ke item yang Anda tangani sedangkan MOV memuat nilai sebenarnya di alamat itu.Tujuannya
LEA
adalah untuk memungkinkan seseorang melakukan penghitungan alamat non-sepele dan menyimpan hasilnya [untuk penggunaan nanti]Jika hanya ada konstanta yang terlibat,
MOV
(melalui kalkulasi konstanta assembler) terkadang terlihat tumpang tindih dengan kasus penggunaan yang paling sederhanaLEA
. Ini berguna jika Anda memiliki kalkulasi multi-bagian dengan beberapa alamat dasar, dll.sumber
LAHF
: Muat BENDERA ke register AH . Dalam CLR's CIL (yang merupakan mesin abstrak berbasis tumpukan tingkat yang lebih tinggi, istilah beban mengacu pada meletakkan nilai ke tumpukan nosional dan biasanyal
..., dans
... setara melakukan kebalikannya). Catatan ini: cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/load.html ) menunjukkan bahwa memang ada arsitektur di mana perbedaan Anda berlaku.Dalam sintaks NASM:
Dalam sintaks MASM, gunakan
OFFSET var
untuk mendapatkan mov-segera alih-alih memuat.sumber
mov eax, var
is a load, sama denganmov eax, [var]
, dan Anda harusmov eax, OFFSET var
menggunakan label sebagai konstanta langsung.lea
adalah pilihan yang lebih buruk kecuali dalam mode 64-bit untuk pengalamatan relatif RIP.mov r32, imm32
berjalan di lebih banyak port.lea eax, [edx*4]
adalah copy-and-shift yang tidak dapat dilakukan dalam satu instruksi sebaliknya, tetapi dalam register yang sama LEA hanya membutuhkan lebih banyak byte untuk dikodekan karena[eax*4]
membutuhkandisp32=0
. (Ini berjalan pada port yang berbeda dari shift.) Lihat agner.org/optimize dan stackoverflow.com/tags/x86/info .Instruksi MOV reg, addr berarti membaca variabel yang disimpan di address addr ke register reg. Instruksi LEA reg, addr artinya membaca alamat (bukan variabel yang disimpan di alamat) ke register reg.
Bentuk lain dari instruksi MOV adalah MOV reg, immdata yang berarti membaca data langsung (yaitu konstan) immdata ke register reg. Perhatikan bahwa jika addr dalam LEA reg, addr hanyalah sebuah konstanta (yaitu offset tetap) maka instruksi LEA itu pada dasarnya persis sama dengan instruksi MOV reg yang setara, instruksi immdata yang memuat konstanta yang sama dengan data langsung.
sumber
Jika Anda hanya menentukan literal, tidak ada perbedaan. LEA memiliki lebih banyak kemampuan, dan Anda dapat membacanya di sini:
http://www.oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-1.html#HEADING1-136
sumber
leal TextLabel, LabelFromBssSegment
ketika Anda mendapatkan sesuatu. seperti.bss .lcomm LabelFromBssSegment, 4
, Anda harusmovl $TextLabel, LabelFromBssSegment
, bukan?lea
memerlukan tujuan register, tetapimov
dapat memilikiimm32
sumber dan tujuan memori. Batasan ini tentu saja tidak spesifik untuk perakit GNU.MOV AX, [TABLE-ADDR]
, yaitu beban. Jadi ada perbedaan besar. Instruksi yang setara adalahmov ax, OFFSET table_addr
Itu tergantung assembler yang digunakan, karena
di MASM bekerja sebagai
Jadi itu memuat byte pertama dari
table_addr
dan BUKAN offset ketable_addr
. Anda harus menggunakan sebagai gantinyaatau
yang berfungsi sama.
lea
versi juga berfungsi dengan baik jikatable_addr
variabel lokal misalnyasumber
Tak satu pun dari jawaban sebelumnya yang benar-benar membingungkan saya, jadi saya ingin menambahkan jawaban saya sendiri.
Apa yang saya lewatkan adalah
lea
operasi memperlakukan penggunaan tanda kurung berbeda dari bagaimanamov
.Pikirkan C. Katakanlah saya memiliki array
long
yang saya sebutarray
. Sekarang ekspresiarray[i]
melakukan dereferensi, memuat nilai dari memori di alamatarray + i * sizeof(long)
[1].Di sisi lain, pertimbangkan ekspresinya
&array[i]
. Ini masih berisi sub-ekspresiarray[i]
, tetapi tidak ada dereferensi yang dilakukan! Artiarray[i]
telah berubah. Ini tidak lagi berarti melakukan penghormatan tetapi bertindak sebagai semacam spesifikasi , memberi&
tahu alamat memori apa yang kita cari. Jika Anda suka, Anda dapat menganggapnya&
sebagai "membatalkan" dereferensi.Karena dua kasus penggunaan serupa dalam banyak hal, keduanya berbagi sintaks
array[i]
, tetapi ada atau tidaknya&
perubahan cara interpretasi sintaks tersebut. Tanpa&
, itu dereferensi dan benar-benar membaca dari array. Dengan&
, tidak. Nilainyaarray + i * sizeof(long)
masih dihitung, tetapi tidak dideferensiasi.Situasinya sangat mirip dengan
mov
danlea
. Denganmov
, terjadi dereferensi yang tidak terjadi denganlea
. Ini terlepas dari penggunaan tanda kurung yang terjadi di keduanya. Misalnya,movq (%r8), %r9
danleaq (%r8), %r9
. Denganmov
, tanda kurung ini berarti "dereferensi"; denganlea
, mereka tidak. Ini mirip dengan bagaimanaarray[i]
hanya berarti "dereferensi" jika tidak ada&
.Contohnya adalah dalam urutan.
Pertimbangkan kodenya
Ini memuat nilai di lokasi memori
%rdi + %rsi * 8
ke dalam register%rbp
. Yaitu: dapatkan nilai di register%rdi
dan nilai di register%rsi
. Kalikan yang terakhir dengan 8, lalu tambahkan ke yang pertama. Temukan nilainya di lokasi ini dan tempatkan ke dalam register%rbp
.Kode ini sesuai dengan baris C
x = array[i];
, di manaarray
menjadi%rdi
dani
menjadi%rsi
danx
menjadi%rbp
. Ini8
adalah panjang tipe data yang terdapat dalam larik.Sekarang pertimbangkan kode serupa yang menggunakan
lea
:Sama seperti penggunaan
movq
terkait dengan dereferensi, penggunaan dileaq
sini terkait dengan tidak dereferensi. Baris ini dari perakitan sesuai dengan jalur Cx = &array[i];
. Ingatlah bahwa&
mengubah artiarray[i]
dari dereferensi menjadi sekadar menentukan lokasi. Demikian pula penggunaanleaq
mengubah arti(%rdi, %rsi, 8)
dari dereferensi menjadi menentukan lokasi.Semantik dari baris kode ini adalah sebagai berikut: dapatkan nilai di register
%rdi
dan nilai di register%rsi
. Kalikan yang terakhir dengan 8, lalu tambahkan ke yang pertama. Tempatkan nilai ini ke dalam register%rbp
. Tidak ada beban dari memori yang terlibat, hanya operasi aritmatika [2].Perhatikan bahwa satu-satunya perbedaan antara uraian saya tentang
leaq
danmovq
adalahmovq
perbedaan pendapat, danleaq
tidak. Sebenarnya, untuk menulisleaq
deskripsi, saya pada dasarnya menyalin + menempelkan deskripsimovq
, dan kemudian menghapus "Temukan nilai di lokasi ini".Untuk meringkas:
movq
vs.leaq
rumit karena mereka memperlakukan penggunaan tanda kurung, seperti dalam(%rsi)
dan(%rdi, %rsi, 8)
, berbeda. Dalammovq
(dan semua instruksi lain kecualilea
), tanda kurung ini menunjukkan dereferensi asli, sedangkan di dalamnyaleaq
tidak dan merupakan sintaks murni yang nyaman.[1] Saya telah mengatakan bahwa when
array
adalah sebuah arraylong
, ekspresiarray[i]
memuat nilai dari alamatnyaarray + i * sizeof(long)
. Ini benar, tetapi ada sedikit kehalusan yang harus diatasi. Jika saya menulis kode C.ini tidak sama dengan mengetik
Tampaknya itu harus didasarkan pada pernyataan saya sebelumnya, tetapi sebenarnya tidak.
Apa yang terjadi adalah bahwa penambahan penunjuk C memiliki trik untuk itu. Katakanlah saya memiliki pointer yang
p
menunjuk ke nilai-nilai tipeT
. Ekspresip + i
tersebut tidak berarti "posisi padap
plusi
byte". Sebaliknya, ekspresip + i
sebenarnya berarti "posisi padap
plusi * sizeof(T)
byte".Kenyamanan ini adalah bahwa untuk mendapatkan "nilai berikutnya" kita hanya perlu menulis
p + 1
bukanp + 1 * sizeof(T)
.Ini berarti bahwa kode C
long x = array[5];
sebenarnya setara dengankarena C secara otomatis akan mengalikan
5
dengansizeof(long)
.Jadi dalam konteks pertanyaan StackOverflow ini, bagaimana semua ini relevan? Artinya ketika saya mengatakan "alamat
array + i * sizeof(long)
", saya tidak bermaksud untuk "array + i * sizeof(long)
" diartikan sebagai ekspresi C. Saya melakukan perkaliansizeof(long)
sendiri untuk membuat jawaban saya lebih eksplisit, tetapi memahami bahwa karena itu, ungkapan ini tidak boleh dibaca sebagai C. Sama seperti matematika biasa yang menggunakan sintaks C.[2] Catatan tambahan: karena semua yang
lea
dilakukannya adalah operasi aritmatika, argumennya sebenarnya tidak harus merujuk ke alamat yang valid. Untuk alasan ini, ini sering digunakan untuk melakukan aritmatika murni pada nilai yang mungkin tidak dimaksudkan untuk dideferensi. Misalnya,cc
dengan-O2
terjemahan pengoptimalanmenjadi berikut (baris yang tidak relevan dihapus):
sumber
&
operator C adalah analogi yang bagus. Mungkin perlu ditunjukkan bahwa LEA adalah kasus khusus, sedangkan MOV sama seperti setiap instruksi lain yang dapat mengambil memori atau mendaftarkan operan. misalnyaadd (%rdi), %eax
hanya menggunakan mode pengalamatan ke memori alamat, sama seperti MOV. Juga terkait: Menggunakan LEA pada nilai yang bukan merupakan alamat / pointer? mengambil penjelasan ini lebih jauh: LEA adalah bagaimana Anda dapat menggunakan dukungan HW CPU untuk matematika alamat untuk melakukan perhitungan sewenang-wenang.%rdi
" - Ini adalah kata yang aneh. Maksud Anda, nilai dalam registerrdi
harus digunakan. Penggunaan "at" oleh Anda tampaknya berarti dereferensi memori yang sebenarnya tidak ada.%rdi
" atau "nilai di%rdi
". "Nilai dalam register%rdi
" Anda panjang tapi bagus, dan mungkin bisa membantu seseorang yang kesulitan memahami register vs. memori.Seperti yang dinyatakan dalam jawaban lain:
MOV
akan mengambil data di alamat di dalam tanda kurung dan menempatkan data itu ke dalam operan tujuan.LEA
akan melakukan perhitungan alamat di dalam tanda kurung dan menempatkan alamat yang dihitung ke dalam operan tujuan. Ini terjadi tanpa benar-benar keluar ke memori dan mendapatkan data. Pekerjaan yang dilakukanLEA
adalah dalam menghitung "alamat efektif".Karena memori dapat dialamatkan dengan beberapa cara berbeda (lihat contoh di bawah),
LEA
terkadang digunakan untuk menambah atau mengalikan register bersama-sama tanpa menggunakan eksplisitADD
atauMUL
instruksi (atau setara).Karena setiap orang menunjukkan contoh dalam sintaks Intel, berikut beberapa dalam sintaks AT&T:
sumber
lea label, %eax
absolut[disp32]
. Gunakanmov $label, %eax
sebagai gantinya. Ya, ini berfungsi, tetapi kurang efisien (kode mesin lebih besar dan berjalan pada unit eksekusi yang lebih sedikit). Karena Anda menyebutkan AT&T, Menggunakan LEA pada nilai yang bukan merupakan alamat / penunjuk? menggunakan AT&T, dan jawaban saya di sana memiliki beberapa contoh AT&T lainnya.Pada dasarnya ... "Pindah ke REG ... setelah menghitungnya ..." sepertinya bagus untuk tujuan lain juga :)
jika Anda lupa bahwa nilainya adalah penunjuk, Anda dapat menggunakannya untuk pengoptimalan / minimisasi kode ... apa pun ..
EAX = 8
aslinya akan menjadi:
sumber
lea
adalah instruksi shift-and-add yang menggunakan encoding dan sintaks mesin operan memori, karena hardware sudah mengetahui cara mendekode ModR / M + SIB + disp0 / 8/32.Mari kita pahami ini dengan sebuah contoh.
mov eax, [ebx] dan
lea eax, [ebx] Misalkan nilai di ebx adalah 0x400000. Kemudian mov akan menuju ke alamat 0x400000 dan menyalin 4 byte data yang ada ke register eax. Sedangkan lea akan menyalin alamat 0x400000 ke eax. Jadi, setelah dieksekusi setiap nilai instruksi eax di tiap kasus akan menjadi (asumsi pada memori 0x400000 berisi adalah 30).
eax = 30 (dalam kasus mov) eax = 0x400000 (dalam kasus lea) Untuk definisi mov salin data dari rm32 ke tujuan (mov tujuan rm32) dan lea (muat alamat efektif) akan menyalin alamat ke tujuan (mov tujuan rm32 ).
sumber
MOV dapat melakukan hal yang sama seperti LEA [label], tetapi instruksi MOV berisi alamat efektif di dalam instruksi itu sendiri sebagai konstanta langsung (dihitung sebelumnya oleh assembler). LEA menggunakan PC-relative untuk menghitung alamat efektif selama pelaksanaan instruksi.
sumber
lea [label
adalah pemborosan byte vs. yang lebih kompakmov
, jadi Anda harus menentukan kondisi yang Anda bicarakan. Juga, untuk beberapa assembler[label]
bukanlah sintaks yang tepat untuk mode pengalamatan relatif RIP. Tapi ya, itu akurat. Bagaimana cara memuat alamat fungsi atau label ke register di GNU Assembler menjelaskan lebih detail.LEA (Load Effective Address) adalah instruksi shift-and-add. Itu ditambahkan ke 8086 karena perangkat keras ada di sana untuk memecahkan kode dan menghitung mode alamat.
sumber
Perbedaannya halus tapi penting. Instruksi MOV adalah 'MOVe' yang secara efektif merupakan salinan alamat yang diwakili oleh label TABLE-ADDR. Instruksi LEA adalah 'Load Effective Address' yang merupakan instruksi tak terarah, yang berarti TABLE-ADDR menunjuk ke lokasi memori di mana alamat yang akan dimuat ditemukan.
Secara efektif menggunakan LEA setara dengan menggunakan pointer dalam bahasa seperti C, karena itu adalah instruksi yang ampuh.
sumber