मैं जानना चाहूंगा कि इन निर्देशों में क्या अंतर है:
MOV AX, [TABLE-ADDR]
तथा
LEA AX, [TABLE-ADDR]
मैं जानना चाहूंगा कि इन निर्देशों में क्या अंतर है:
MOV AX, [TABLE-ADDR]
तथा
LEA AX, [TABLE-ADDR]
जवाबों:
LEA
लोड प्रभावी पता का मतलब हैMOV
लोड मूल्य का मतलब हैसंक्षेप में, LEA
उस पॉइंटर को एक पॉइंटर लोड करता है जिसे आप संबोधित कर रहे हैं जबकि एमओवी उस पते पर वास्तविक मूल्य को लोड करता है।
इसका उद्देश्य LEA
गैर-तुच्छ पता गणना करने और बाद में उपयोग के लिए परिणाम को संग्रहीत करने की अनुमति देना है।
LEA ax, [BP+SI+5] ; Compute address of value
MOV ax, [BP+SI+5] ; Load value at that address
जहां बस स्थिरांक शामिल हैं, MOV
(असेंबलर की निरंतर गणना के माध्यम से) कभी-कभी उपयोग के सरलतम मामलों के साथ ओवरलैप करने के लिए प्रकट हो सकते हैं LEA
। यदि आपके पास कई आधार पते आदि के साथ एक बहु-भाग गणना है तो यह उपयोगी है।
LAHF
है: एएच रजिस्टर में लोड फ्लैग । सीएलआर के सीआईएल में (जो एक उच्च स्तरीय स्टैक आधारित एब्सट्रैक्ट मशीन है, टर्म लोड का अर्थ है कि क्रमागत स्टैक पर मान लगाना और सामान्य रूप से l
..., और s
... समतुल्य व्युत्क्रम करता है)। ये नोट: cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/load.html ) सुझाव देते हैं कि वास्तव में ऐसे आर्किटेक्चर हैं जहां आपका अंतर लागू होता है।
NASM सिंटैक्स में:
mov eax, var == lea eax, [var] ; i.e. mov r32, imm32
lea eax, [var+16] == mov eax, var+16
lea eax, [eax*4] == shl eax, 2 ; but without setting flags
MASM सिंटैक्स में, OFFSET var
लोड के बजाय एक mov-तत्काल प्राप्त करने के लिए उपयोग करें।
mov eax, var
एक लोड होता है, जैसा कि mov eax, [var]
, और आपको mov eax, OFFSET var
एक लेबल का उपयोग तत्काल स्थिरांक के रूप में करना होगा।
lea
आरआईपी-सापेक्ष पते के लिए 64-बिट मोड को छोड़कर सबसे खराब विकल्प है। mov r32, imm32
अधिक बंदरगाहों पर चलती है। lea eax, [edx*4]
एक कॉपी-और-शिफ्ट है जो एक निर्देश में नहीं किया जा सकता है अन्यथा, लेकिन उसी रजिस्टर में एलईए को सांकेतिक शब्दों में बदलना अधिक बाइट्स लेता है क्योंकि [eax*4]
इसके लिए ए की आवश्यकता होती है disp32=0
। (यह पाली की तुलना में विभिन्न बंदरगाहों पर चलता है।) agner.org/optimize और stackoverflow.com/tags/x86/nfo देखें ।
निर्देश MOV रेग, एड्र का मतलब है कि रजिस्टर एड में एड्रेस एड्र पर संग्रहीत एक चर पढ़ें। अनुदेश LEA reg, addr का मतलब है रजिस्टर में पता (पते पर संग्रहीत चर नहीं) पता पढ़ें।
MOV निर्देश का एक अन्य रूप MOV reg, immdata है जिसका अर्थ है कि तत्काल डेटा (अर्थात स्थिर) immdata को रजिस्टर reg में पढ़ें। ध्यान दें कि अगर LEA reg में Addr, addr सिर्फ एक स्थिर (यानी एक निश्चित ऑफसेट) है, तो LEA निर्देश अनिवार्य रूप से समतुल्य MOV reg के समान ही है, immdata निर्देश जो तत्काल डेटा के समान ही लोड करता है।
यदि आप केवल एक शाब्दिक निर्दिष्ट करते हैं, तो कोई अंतर नहीं है। LEA में अधिक क्षमताएं हैं, हालांकि, और आप उनके बारे में यहां पढ़ सकते हैं:
http://www.oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-1.html#HEADING1-136
leal TextLabel, LabelFromBssSegment
जब आप smth मिला। जैसे .bss .lcomm LabelFromBssSegment, 4
, आपको यह करना होगा movl $TextLabel, LabelFromBssSegment
, है न?
lea
एक रजिस्टर गंतव्य की आवश्यकता होती है, लेकिन mov
एक imm32
स्रोत और एक स्मृति गंतव्य हो सकता है। यह सीमा निश्चित रूप से GNU कोडांतरक के लिए विशिष्ट नहीं है।
MOV AX, [TABLE-ADDR]
, जो एक लोड है। इसलिए एक बड़ा अंतर है। बराबर निर्देश हैmov ax, OFFSET table_addr
यह इस्तेमाल किए गए कोडांतरक पर निर्भर करता है, क्योंकि
mov ax,table_addr
के रूप में काम करता है
mov ax,word ptr[table_addr]
तो यह पहले बाइट्स को लोड करता है table_addr
और ऑफसेट को नहीं table_addr
। आपको इसके बजाय उपयोग करना चाहिए
mov ax,offset table_addr
या
lea ax,table_addr
जो काम करता है।
lea
संस्करण भी ठीक काम करता है अगर table_addr
एक स्थानीय चर उदाहरण है
some_procedure proc
local table_addr[64]:word
lea ax,table_addr
पिछले जवाबों में से कोई भी मेरे अपने भ्रम की तह तक नहीं गया, इसलिए मैं अपना खुद का जोड़ना चाहूंगा।
मुझे जो याद आ रहा था, वह यह है कि lea
ऑपरेशन कोष्ठक के उपयोग को कैसे mov
करता है की तुलना में अलग है।
सी। के बारे में सोचो चलो कहते हैं कि मेरे पास एक सरणी है long
जिसे मैं कहता हूं array
। अब एक्सप्रेशन [1] array[i]
पर मेमोरी से वैल्यू लोड करते हुए एक एक्सप्रेशन करता है array + i * sizeof(long)
।
दूसरी ओर, अभिव्यक्ति पर विचार करें &array[i]
। यह अभी भी उप-अभिव्यक्ति समाहित करता है array[i]
, लेकिन कोई भी डीफ्रेंसिंग नहीं किया जाता है! का अर्थ array[i]
बदल गया है। इसका मतलब अब एक प्रदर्शन करना नहीं है, बल्कि एक प्रकार के विनिर्देश के रूप में कार्य करता है , &
जो यह बताता है कि हम किस मेमोरी एड्रेस की तलाश कर रहे हैं। यदि आप चाहें, तो आप वैकल्पिक &
रूप से "रद्द करना" के रूप में सोच सकते हैं ।
क्योंकि दो उपयोग-मामले कई मायनों में समान हैं, वे सिंटैक्स को साझा करते हैं array[i]
, लेकिन &
उस सिंटैक्स की व्याख्या कैसे की जाती है , इसके अस्तित्व या अनुपस्थिति । इसके बिना &
, यह एक शर्त है और वास्तव में सरणी से पढ़ता है। के साथ &
, यह नहीं है। मूल्य array + i * sizeof(long)
की गणना अभी भी की जाती है, लेकिन इसे सीमित नहीं किया जाता है।
स्थिति बहुत समान है mov
और lea
। के साथ mov
, एक विक्षेप होता है जो साथ नहीं होता है lea
। यह उन दोनों में होने वाले कोष्ठक के उपयोग के बावजूद है। उदाहरण के लिए, movq (%r8), %r9
और leaq (%r8), %r9
। के साथ mov
, इन कोष्ठकों का अर्थ है "डीरेफेरेंस"; के साथ lea
, वे नहीं। यह समान है कि array[i]
जब कोई नहीं है तो केवल "डीरेफेरेंस" का मतलब क्या है &
।
एक उदाहरण क्रम में है।
कोड पर विचार करें
movq (%rdi, %rsi, 8), %rbp
यह %rdi + %rsi * 8
रजिस्टर में मेमोरी लोकेशन पर वैल्यू लोड करता है %rbp
। वह है: रजिस्टर %rdi
में मूल्य और रजिस्टर में मूल्य प्राप्त करें %rsi
। उत्तरार्द्ध को 8 से गुणा करें, और फिर इसे पूर्व में जोड़ें। इस स्थान पर मान प्राप्त करें और इसे रजिस्टर में रखें %rbp
।
इस कोड को सी लाइन से मेल खाती है x = array[i];
, जहां array
हो जाता है %rdi
और i
हो जाता है %rsi
और x
हो जाता है %rbp
। 8
सरणी में निहित डेटा प्रकार की लंबाई है।
अब समान कोड का उपयोग करने पर विचार करें lea
:
leaq (%rdi, %rsi, 8), %rbp
जिस तरह movq
डेरेफ्रेंसिंग के लिए पत्राचार का उपयोग किया जाता है, उसी तरह leaq
यहां का उपयोग डीरेफरेंसिंग के अनुरूप नहीं है। असेंबली की यह रेखा C रेखा से मेल खाती है x = &array[i];
। याद रखें कि केवल एक स्थान निर्दिष्ट करने के लिए dereferencing से &
अर्थ बदल जाता है array[i]
। इसी तरह, किसी स्थान को निर्दिष्ट करने के लिए डेरेफेरिंग से leaq
अर्थ के परिवर्तन का उपयोग (%rdi, %rsi, 8)
।
कोड की इस पंक्ति के शब्दार्थ इस प्रकार हैं: रजिस्टर %rdi
में मूल्य और रजिस्टर में मूल्य प्राप्त करें %rsi
। उत्तरार्द्ध को 8 से गुणा करें, और फिर इसे पूर्व में जोड़ें। इस मान को रजिस्टर में रखें %rbp
। मेमोरी से कोई लोड शामिल नहीं है, बस अंकगणितीय संचालन [2]।
नोट के अपने विवरण के बीच फर्क सिर्फ इतना है कि leaq
और movq
वह यह है कि movq
एक भिन्नता है, और leaq
नहीं करता है। वास्तव में, leaq
विवरण लिखने के लिए , मैंने मूल रूप से इसके विवरण को कॉपी + पेस्ट किया movq
और फिर "इस स्थान पर मान ढूंढें" को हटा दिया।
संक्षेप में: movq
बनाम leaq
मुश्किल है क्योंकि वे कोष्ठक के उपयोग के इलाज के रूप में, (%rsi)
और (%rdi, %rsi, 8)
, अलग ढंग से। में movq
(और को छोड़कर अन्य सभी अनुदेश lea
), इन कोष्ठकों एक वास्तविक भिन्नता निरूपित, जबकि leaq
वे नहीं है और विशुद्ध रूप से सुविधाजनक वाक्य रचना कर रहे हैं।
[१] मैंने कहा है कि जब array
कोई सरणी होती है long
, तो अभिव्यक्ति array[i]
पते से मूल्य लोड करती है array + i * sizeof(long)
। यह सच है, लेकिन एक सूक्ष्मता है जिसे संबोधित किया जाना चाहिए। अगर मैं C कोड लिखता हूँ
long x = array[5];
यह टाइपिंग जैसा नहीं है
long x = *(array + 5 * sizeof(long));
ऐसा लगता है कि यह मेरे पिछले बयानों पर आधारित होना चाहिए , लेकिन ऐसा नहीं है।
क्या चल रहा है कि सी पॉइंटर जोड़ के पास एक चाल है। कहें कि मेरे पास एक पॉइंटर है p
जो टाइप के मूल्यों की ओर इशारा करता है T
। अभिव्यक्ति p + i
करता है नहीं मतलब है "में स्थिति p
के साथ साथ i
बाइट्स"। इसके बजाय, अभिव्यक्ति p + i
वास्तव में " p
प्लस i * sizeof(T)
बाइट्स में स्थिति" का मतलब है ।
इसकी सुविधा यह है कि "अगला मूल्य" प्राप्त करने के लिए हमें केवल p + 1
इसके बजाय लिखना होगा p + 1 * sizeof(T)
।
इसका मतलब है कि सी कोड long x = array[5];
वास्तव में इसके बराबर है
long x = *(array + 5)
क्योंकि C स्वचालित रूप से 5
द्वारा गुणा करेगा sizeof(long)
।
तो इस StackOverflow सवाल के संदर्भ में, यह सब कैसे प्रासंगिक है? इसका मतलब है कि जब मैं "पता array + i * sizeof(long)
" कहता हूं , तो मेरा मतलब सी अभिव्यक्ति के रूप में व्याख्या करने के लिए " " नहीं है array + i * sizeof(long)
। मैं sizeof(long)
अपने उत्तर को और अधिक स्पष्ट करने के लिए अपने आप से गुणा कर रहा हूं, लेकिन यह समझें कि उसके कारण, इस अभिव्यक्ति को सी के रूप में नहीं पढ़ा जाना चाहिए। सामान्य गणित जो सी सिंटैक्स का उपयोग करता है।
[२] साइड नोट: क्योंकि सभी lea
अंकगणितीय संक्रियाएँ हैं, इसके तर्कों को वास्तव में मान्य पतों का उल्लेख नहीं करना है। इस कारण से, इसका उपयोग अक्सर उन मूल्यों पर शुद्ध अंकगणित प्रदर्शन करने के लिए किया जाता है, जिनका इरादा शायद ही हो। उदाहरण के लिए, अनुकूलन अनुवाद के cc
साथ-O2
long f(long x) {
return x * 5;
}
निम्नलिखित में (अप्रासंगिक लाइनें हटा दी गई हैं):
f:
leaq (%rdi, %rdi, 4), %rax # set %rax to %rdi + %rdi * 4
ret
&
ऑपरेटर एक अच्छा सादृश्य है। शायद यह इंगित करने के लायक है कि एलईए विशेष मामला है, जबकि एमओवी हर दूसरे निर्देश की तरह है जो मेमोरी ले सकता है या ऑपरेंड कर सकता है। उदाहरण के add (%rdi), %eax
लिए, स्मृति को संबोधित करने के लिए केवल संबोधन मोड का उपयोग करता है, उसी तरह MOV। यह भी संबंधित: उन पते पर LEA का उपयोग करना जो पते / संकेत नहीं हैं? इस स्पष्टीकरण को और आगे ले जाता है: LEA यह है कि आप पता गणित के लिए मनमाने ढंग से गणना करने के लिए CPU के HW समर्थन का उपयोग कैसे कर सकते हैं।
%rdi
" - यह अजीब शब्द है। आपका मतलब है कि रजिस्टर में मूल्य काrdi
उपयोग किया जाना चाहिए। आपके "पर" के उपयोग का अर्थ स्मृति विचलन है जहाँ कोई नहीं है।
%rdi
या" मूल्य " में %rdi
"। आपका "रजिस्टर में मूल्य %rdi
" लंबा है, लेकिन ठीक है, और शायद रजिस्टर बनाम मेमोरी को समझने में संघर्ष करने वाले किसी व्यक्ति की मदद कर सकता है।
मूल रूप से ... "रेज में प्रवेश करें ... कंप्यूटिंग के बाद ..." यह अन्य प्रयोजनों के लिए भी अच्छा लगता है :)
यदि आप भूल जाते हैं कि मूल्य एक सूचक है तो आप इसे कोड अनुकूलन / न्यूनता के लिए उपयोग कर सकते हैं ... कभी भी ..
MOV EBX , 1
MOV ECX , 2
;//with 1 instruction you got result of 2 registers in 3rd one ...
LEA EAX , [EBX+ECX+5]
EAX = 8
मूल यह होगा:
MOV EAX, EBX
ADD EAX, ECX
ADD EAX, 5
lea
एक शिफ्ट-एंड-ऐड निर्देश है जो मेमोरी-ऑपरैंड मशीन एन्कोडिंग और सिंटैक्स का उपयोग करता है, क्योंकि हार्डवेयर पहले से ही जानता है कि मॉडआर / एम + एसआईबी + डिस्पो / 8/32 को कैसे डीकोड करना है।
जैसा कि अन्य उत्तरों में कहा गया है:
MOV
कोष्ठक के अंदर पते पर डेटा को पकड़ो और उस डेटा को गंतव्य ऑपरेंड में रखें।LEA
प्रदर्शन करेंगे गणना कोष्ठकों में पता की और जगह है कि पता गणना गंतव्य संकार्य में। यह वास्तव में मेमोरी में जाने और डेटा प्राप्त किए बिना होता है। द्वारा किया गया कार्य LEA
"प्रभावी पते" की गणना में है।क्योंकि मेमोरी को कई अलग-अलग तरीकों से संबोधित किया जा सकता है (नीचे दिए गए उदाहरण देखें), LEA
कभी-कभी एक स्पष्ट ADD
या MUL
निर्देश (या समकक्ष) का उपयोग किए बिना रजिस्टर को एक साथ जोड़ने या गुणा करने के लिए उपयोग किया जाता है ।
चूंकि हर कोई इंटेल सिंटैक्स में उदाहरण दिखा रहा है, यहाँ एटी एंड टी सिंटैक्स में कुछ हैं:
MOVL 16(%ebp), %eax /* put long at ebp+16 into eax */
LEAL 16(%ebp), %eax /* add 16 to ebp and store in eax */
MOVQ (%rdx,%rcx,8), %rax /* put qword at rcx*8 + rdx into rax */
LEAQ (%rdx,%rcx,8), %rax /* put value of "rcx*8 + rdx" into rax */
MOVW 5(%bp,%si), %ax /* put word at si + bp + 5 into ax */
LEAW 5(%bp,%si), %ax /* put value of "si + bp + 5" into ax */
MOVQ 16(%rip), %rax /* put qword at rip + 16 into rax */
LEAQ 16(%rip), %rax /* add 16 to instruction pointer and store in rax */
MOVL label(,1), %eax /* put long at label into eax */
LEAL label(,1), %eax /* put the address of the label into eax */
lea label, %eax
निरपेक्ष [disp32]
संबोधन मोड के लिए नहीं चाहते हैं । mov $label, %eax
इसके बजाय उपयोग करें । हां यह काम करता है, लेकिन यह कम कुशल है (बड़ा मशीन कोड और कम निष्पादन इकाइयों पर चलता है)। चूंकि आप एटीएंडटी का उल्लेख करते हैं, उन पते पर LEA का उपयोग करना जो पते / संकेत नहीं हैं? एटी एंड टी का उपयोग करता है, और मेरे जवाब में कुछ अन्य एटी एंड टी उदाहरण हैं।
इसे एक उदाहरण से समझते हैं।
Mov eax, [ebx] और
lea eax, [ebx] मान लीजिए कि ebx में मूल्य 0x400000 है। फिर mov 0x400000 के पते पर जाएगा और 4 बाइट डेटा कॉपी करेगा जो उनके ईएक्सएक्स रजिस्टर में मौजूद होगा। उसके बाद पता 0x400000 को ईएक्सएक्स में कॉपी करेगा। तो, प्रत्येक मामले में ईएक्स के प्रत्येक अनुदेश मूल्य के निष्पादन के बाद होगा (स्मृति 0x400000 समाहित है 30 है)।
eax = 30 (mov के मामले में) eax = 0x400000 (लीकेज के मामले में) परिभाषा के लिए mov rm32 से गंतव्य तक डेटा की प्रतिलिपि बनाएँ (mov dest rm32) और lea (लोड प्रभावी पता) गंतव्य के पते को कॉपी करेगा (mov dest rm32) )।
MOV LEA [लेबल] के रूप में एक ही काम कर सकता है, लेकिन MOV निर्देश में निर्देश के अंदर एक प्रभावी स्थिरांक (कोडांतरक द्वारा अग्रिम में गणना) के रूप में प्रभावी पता होता है। LEA निर्देश के निष्पादन के दौरान प्रभावी पते की गणना करने के लिए पीसी-सापेक्ष का उपयोग करता है।
lea [label
में, बाइट्स बनाम एक अधिक कॉम्पैक्ट का एक बेकार कचरा है mov
, इसलिए आपको उन शर्तों को निर्दिष्ट करना चाहिए जिनके बारे में आप बात कर रहे हैं। इसके अलावा, कुछ [label]
असेंबलरों के लिए RIP- रिलेटेड एड्रेसिंग मोड के लिए सही सिंटैक्स नहीं है। लेकिन हां, यह सही है। जीएनयू असेंबलर में फ़ंक्शन या लेबल के पते को रजिस्टर में कैसे लोड करना है, इसके बारे में अधिक विस्तार से बताते हैं।
अंतर सूक्ष्म लेकिन महत्वपूर्ण है। MOV निर्देश एक 'MOVe' प्रभावी रूप से उस पते की एक प्रति है जो TABLE-ADDR लेबल के लिए है। LEA निर्देश एक 'लोड प्रभावी पता' है जो एक अप्रत्यक्ष निर्देश है, जिसका अर्थ है कि TABLE-ADDR एक मेमोरी स्थान पर इंगित करता है जिस पर लोड करने के लिए पता मिला है।
LEA का प्रभावी रूप से C जैसी भाषाओं में संकेत का उपयोग करना समान है, क्योंकि यह एक शक्तिशाली निर्देश है।