Chciałbym wiedzieć, jaka jest różnica między tymi instrukcjami:
MOV AX, [TABLE-ADDR]
i
LEA AX, [TABLE-ADDR]
assembly
x86
instruction-set
naveen
źródło
źródło
Odpowiedzi:
LEA
oznacza Załaduj efektywny adresMOV
oznacza wartość obciążeniaKrótko mówiąc,
LEA
ładuje wskaźnik do adresowanego elementu, podczas gdy MOV ładuje rzeczywistą wartość pod tym adresem.Celem
LEA
jest umożliwienie wykonania nietrywialnego obliczenia adresu i zapisanie wyniku [do późniejszego wykorzystania]Tam, gdzie w grę wchodzą tylko stałe
MOV
(poprzez stałe obliczenia asemblera), czasami może się wydawać, że nakładają się na najprostsze przypadki użyciaLEA
. Jest to przydatne, jeśli masz wieloczęściowe obliczenia z wieloma adresami podstawowymi itp.źródło
LAHF
to: Załaduj FLAGI do rejestru AH . W CIL CLR (który jest maszyną abstrakcyjną opartą na stosie wyższego poziomu, termin load odnosi się do umieszczenia wartości na stosie pojęciowym i jest normalniel
..., as
odpowiednik ... odwrotnie). Te uwagi: cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/load.html ) sugerują, że rzeczywiście istnieją architektury, w których twoje rozróżnienie ma zastosowanie.W składni NASM:
W składni MASM użyj,
OFFSET var
aby uzyskać natychmiastowe mov zamiast ładowania.źródło
mov eax, var
jest to obciążenie, to samo comov eax, [var]
i musiszmov eax, OFFSET var
użyć etykiety jako natychmiastowej stałej.lea
jest to gorszy wybór, z wyjątkiem trybu 64-bitowego dla adresowania względnego RIP.mov r32, imm32
działa na większej liczbie portów.lea eax, [edx*4]
jest kopiowaniem i przesuwaniem, którego nie można wykonać w jednej instrukcji w inny sposób, ale w tym samym rejestrze LEA zajmuje po prostu więcej bajtów do kodowania, ponieważ[eax*4]
wymaga rozszerzeniadisp32=0
. (Działa jednak na innych portach niż zmiany.) Zobacz agner.org/optimize i stackoverflow.com/tags/x86/info .Instrukcja MOV reg, addr oznacza odczyt zmiennej przechowywanej pod adresem addr do rejestru reg. Instrukcja LEA reg, addr oznacza odczyt adresu (a nie zmiennej przechowywanej pod adresem) do rejestru reg.
Inną formą instrukcji MOV jest MOV reg, immdata, co oznacza wczytanie natychmiastowych danych (tj. Stałych) immdata do rejestru reg. Zauważ, że jeśli addr w LEA reg, addr jest po prostu stałą (tj. Stałym przesunięciem), to ta instrukcja LEA jest zasadniczo dokładnie taka sama, jak równoważna instrukcja MOV reg, immdata, która ładuje tę samą stałą, co dane bezpośrednie.
źródło
Jeśli podasz tylko literał, nie ma różnicy. LEA ma jednak więcej umiejętności, o których możesz przeczytać tutaj:
http://www.oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-1.html#HEADING1-136
źródło
leal TextLabel, LabelFromBssSegment
możesz, kiedy coś masz. jakbyś.bss .lcomm LabelFromBssSegment, 4
musiałmovl $TextLabel, LabelFromBssSegment
, prawda?lea
wymaga miejsca docelowego rejestru, alemov
może miećimm32
źródło i miejsce docelowe pamięci. To ograniczenie oczywiście nie jest specyficzne dla asemblera GNU.MOV AX, [TABLE-ADDR]
obciążenia. Jest więc zasadnicza różnica. Równoważna instrukcja brzmimov ax, OFFSET table_addr
To zależy od używanego asemblera, ponieważ
w MASM działa jako
Więc ładuje pierwsze bajty zi
table_addr
NIE przesunięcie dotable_addr
. Zamiast tego powinieneś użyćlub
który działa tak samo.
lea
wersja działa również dobrze, jeślitable_addr
jest zmienną lokalną npźródło
Żadna z poprzednich odpowiedzi nie doprowadziła do końca mojego zamieszania, więc chciałbym dodać własną.
Brakowało mi tego, że
lea
operacje traktują użycie nawiasów inaczej niż w jakimov
sposób.Pomyśl o C. Powiedzmy, że mam tablicę
long
, którą nazywamarray
. Teraz wyrażeniearray[i]
wykonuje dereferencję, ładując wartość z pamięci pod adresemarray + i * sizeof(long)
[1].Z drugiej strony rozważ wyrażenie
&array[i]
. To nadal zawiera wyrażenie podrzędnearray[i]
, ale nie jest wykonywane żadne wyłuskiwanie! Znaczenie sięarray[i]
zmieniło. Nie oznacza już szacunku, ale działa jako rodzaj specyfikacji , mówiącej,&
jakiego adresu pamięci szukamy. Jeśli chcesz, możesz alternatywnie pomyśleć o&
„anulowaniu” wyłuskiwania.Ponieważ te dwa przypadki użycia są podobne pod wieloma względami, mają wspólną składnię
array[i]
, ale istnienie lub brak&
zmiany zmienia sposób interpretacji tej składni. Bez&
tego jest to dereferencja i faktycznie czyta z tablicy. Tak&
nie jest. Wartośćarray + i * sizeof(long)
jest nadal obliczana, ale nie jest odwoływana.Sytuacja jest bardzo podobna w przypadku
mov
ilea
. Wmov
przypadku występuje dereferencja, która nie ma miejsca w przypadkulea
. Dzieje się tak pomimo użycia nawiasów, które występują w obu przypadkach. Na przykładmovq (%r8), %r9
ileaq (%r8), %r9
. W przypadkumov
tych nawiasów oznacza „wyłuskiwanie”; zlea
, nie robią. Jest to podobne do sposobu, w jakiarray[i]
oznacza „wyłuskiwanie” tylko wtedy, gdy nie ma&
.Przykład jest w porządku.
Rozważ kod
Spowoduje to załadowanie wartości z lokalizacji pamięci
%rdi + %rsi * 8
do rejestru%rbp
. To znaczy: pobierz wartość w rejestrze%rdi
i wartość w rejestrze%rsi
. Pomnóż tę ostatnią przez 8, a następnie dodaj ją do pierwszej. Znajdź wartość w tej lokalizacji i umieść ją w rejestrze%rbp
.Ten kod odpowiada linii C
x = array[i];
, gdziearray
staje się%rdi
ii
staje się%rsi
ix
staje się%rbp
. Jest8
to długość typu danych zawartego w tablicy.Teraz rozważ podobny kod, który używa
lea
:Podobnie jak wykorzystaniu
movq
odzwierciedlał dereferencing, użycieleaq
tutaj odpowiada nie dereferencji. Ta linia montażowa odpowiada linii Cx = &array[i];
. Przypomnijmy, że&
zmienia to znaczeniearray[i]
z wyłuskiwania odwołań do prostego określenia lokalizacji. Podobnie użycieleaq
zmiany zmienia znaczenie(%rdi, %rsi, 8)
z wyłuskiwania odwołań do określania lokalizacji.Semantyka tego wiersza kodu jest następująca: pobierz wartość w rejestrze
%rdi
i wartość w rejestrze%rsi
. Pomnóż tę ostatnią przez 8, a następnie dodaj ją do pierwszej. Umieść tę wartość w rejestrze%rbp
. Nie jest wymagane żadne obciążenie z pamięci, tylko operacje arytmetyczne [2].Zauważ, że jedyna różnica między moimi opisami opcji
leaq
imovq
polega na tym, żemovq
dokonuje wyłuskiwania, aleaq
nie. Właściwie, aby napisaćleaq
opis, po prostu skopiowałem + wkleiłem opismovq
, a następnie usunąłem „Znajdź wartość w tej lokalizacji”.Podsumowując:
movq
vs.leaq
jest trudne, ponieważ traktują użycie nawiasów tak jak w(%rsi)
i(%rdi, %rsi, 8)
, inaczej. Wmovq
(i we wszystkich innych instrukcjach z wyjątkiemlea
) te nawiasy oznaczają autentyczną dereferencję, podczas gdy wleaq
nich nie mają i są czysto wygodną składnią.[1] Powiedziałem, że kiedy
array
jest tablicąlong
, wyrażeniearray[i]
ładuje wartość z adresuarray + i * sizeof(long)
. To prawda, ale należy się zająć pewną subtelnością. Jeśli napiszę kod C.to nie to samo, co pisanie
Wydaje się, że powinno być oparte na moich wcześniejszych wypowiedziach, ale tak nie jest.
Chodzi o to, że dodawanie wskaźnika C ma w sobie sztuczkę. Powiedzmy, że mam wskaźnik
p
wskazujący na wartości typuT
. Wyrażeniep + i
ma nie znaczyć „pozycja nap
plusi
bajtów”. Zamiast tego wyrażeniep + i
faktycznie oznacza „pozycję zp
plusemi * sizeof(T)
bajtów”.Wygoda polega na tym, że aby uzyskać „następną wartość”, po prostu musimy
p + 1
zamiast tego pisaćp + 1 * sizeof(T)
.Oznacza to, że kod C
long x = array[5];
jest faktycznie odpowiednikiemponieważ C automatycznie pomnoży
5
przezsizeof(long)
.Więc w kontekście tego pytania StackOverflow, jak to wszystko ma znaczenie? Oznacza to, że kiedy mówię „adres
array + i * sizeof(long)
”, ja nie myśli o „array + i * sizeof(long)
” należy interpretować jako wyrażenie C. Mnożęsizeof(long)
samodzielnie, aby uściślić moją odpowiedź, ale rozumiem, że z tego powodu wyrażenie to nie powinno być odczytywane jako C. Tak jak zwykła matematyka, która używa składni C.[2] Uwaga dodatkowa: ponieważ wszystko
lea
robi jest operacjami arytmetycznymi, jego argumenty nie muszą w rzeczywistości odnosić się do poprawnych adresów. Z tego powodu jest często używany do wykonywania czystej arytmetyki na wartościach, które mogą nie być wyłuskiwane. Na przykładcc
z-O2
optymalizacją przekłada siędo następującego (usunięto nieistotne wiersze):
źródło
&
operator C to dobra analogia. Być może warto zauważyć, że LEA jest przypadkiem specjalnym, podczas gdy MOV jest jak każda inna instrukcja, która może zająć operand pamięci lub rejestr. np.add (%rdi), %eax
po prostu używa trybu adresowania do adresowania pamięci, tak samo jak MOV. Również powiązane: Używanie LEA na wartościach, które nie są adresami / wskaźnikami? kontynuuje to wyjaśnienie: LEA to sposób, w jaki można wykorzystać wsparcie sprzętowe procesora dla matematyki adresowej do wykonywania dowolnych obliczeń.%rdi
” - to dziwnie sformułowane. Masz na myśli, że należy użyć wartości w rejestrzerdi
. Twoje użycie „at” wydaje się oznaczać wyłuskiwanie pamięci tam, gdzie jej nie ma.%rdi
” lub „wartości w%rdi
”. Twoja „wartość w rejestrze%rdi
” jest długa, ale w porządku i może pomóc komuś, kto ma problemy ze zrozumieniem rejestrów i pamięci.Zasadniczo ... "Przenieś się do REG ... po obliczeniu ..." wydaje się być również przydatne do innych celów :)
jeśli po prostu zapomnisz, że wartość jest wskaźnikiem, możesz jej użyć do optymalizacji / minimalizacji kodu ... cokolwiek ...
EAX = 8
pierwotnie byłoby to:
źródło
lea
jest to instrukcja przesuwania i dodawania, która używa maszynowego kodowania i składni operandów pamięci, ponieważ sprzęt już wie, jak dekodować ModR / M + SIB + disp0 / 8/32.Jak stwierdzono w innych odpowiedziach:
MOV
przechwyci dane na adres wewnątrz wsporników i miejscu, że dane do docelowego argumentu.LEA
wykona obliczenie adresu wewnątrz nawiasów i umieści obliczony adres w operandzie docelowym. Dzieje się to bez wychodzenia do pamięci i pobierania danych. Praca wykonywana przez programLEA
polega na obliczaniu „efektywnego adresu”.Ponieważ pamięć może być adresowana na kilka różnych sposobów (patrz przykłady poniżej),
LEA
czasami jest używana do dodawania lub mnożenia rejestrów razem bez użycia jawnej instrukcjiADD
lubMUL
instrukcji (lub równoważnej).Ponieważ wszyscy pokazują przykłady w składni Intela, oto kilka w składni AT&T:
źródło
lea label, %eax
absolutnego[disp32]
trybu adresowania. Użyjmov $label, %eax
zamiast tego. Tak, działa, ale jest mniej wydajne (większy kod maszynowy i działa na mniejszej liczbie jednostek wykonawczych). Skoro wspomniałeś o AT&T, używaniu LEA na wartościach, które nie są adresami / wskaźnikami? używa AT&T, a moja odpowiedź zawiera kilka innych przykładów AT&T.Zrozummy to na przykładzie.
mov eax, [ebx] i
lea eax, [ebx] Załóżmy, że wartość w ebx to 0x400000. Następnie mov przejdzie na adres 0x400000 i przekopiuje 4 bajty prezentowanych danych do rejestru eax, przy czym lea skopiuje adres 0x400000 do eax. Czyli po wykonaniu każdej instrukcji wartość eax w każdym przypadku będzie (zakładając, że w pamięci 0x400000 zawiera 30).
eax = 30 (w przypadku mov) eax = 0x400000 (w przypadku lea) W celu zdefiniowania mov skopiuj dane z rm32 do celu (mov dest rm32) a lea (załaduj efektywny adres) skopiuje adres do celu (mov dest rm32 ).
źródło
LEA (Load Effective Address) to instrukcja typu „przesuń i dodaj”. Został dodany do 8086, ponieważ sprzęt służy do dekodowania i obliczania trybów adresowania.
źródło
MOV może zrobić to samo co LEA [etykieta], ale instrukcja MOV zawiera efektywny adres wewnątrz samej instrukcji jako stałą natychmiastową (obliczoną z góry przez asemblera). LEA używa względem PC do obliczenia efektywnego adresu podczas wykonywania instrukcji.
źródło
lea [label
jest to bezcelowe marnowanie bajtów w porównaniu z bardziej zwartymmov
, więc powinieneś określić warunki, o których mówisz. Ponadto dla niektórych asemblerów[label]
składnia nie jest odpowiednia dla trybu adresowania względnego w protokole RIP. Ale tak, to prawda. Jak załadować adres funkcji lub etykiety do rejestru w GNU Assembler wyjaśnia bardziej szczegółowo.Różnica jest subtelna, ale ważna. Instrukcja MOV jest „MOVe” w rzeczywistości kopią adresu, który reprezentuje etykieta TABLE-ADDR. Instrukcja LEA jest „Load Effective Address”, która jest instrukcją pośrednią, co oznacza, że TABLE-ADDR wskazuje miejsce w pamięci, w którym znajduje się adres do załadowania.
Skuteczne używanie LEA jest równoważne używaniu wskaźników w językach takich jak C, ponieważ jest to potężna instrukcja.
źródło