Benim için korkak bir MOV gibi görünüyor. Amacı nedir ve ne zaman kullanmalıyım?
Benim için korkak bir MOV gibi görünüyor. Amacı nedir ve ne zaman kullanmalıyım?
Yanıtlar:
Diğerlerinin de belirttiği gibi, LEA (yüke etkili adres) genellikle belirli hesaplamaları yapmak için bir "hile" olarak kullanılır, ancak bu birincil amacı değildir. X86 komut seti, dizilerin - özellikle de dizilerin veya küçük yapıların dizilerinin - yaygın olduğu Pascal ve C gibi üst düzey dilleri desteklemek üzere tasarlanmıştır. Örneğin, (x, y) koordinatlarını temsil eden bir yapı düşünün:
struct Point
{
int xcoord;
int ycoord;
};
Şimdi şöyle bir ifade hayal edin:
int y = points[i].ycoord;
points[]
dizisi nerede Point
. Dizinin bir taban varsayıldığında zaten EBX
ve değişken i
olan EAX
ve xcoord
ve ycoord
her biri 32 bit (so ycoord
yapı ofset 4 bayt olduğunu), bu açıklama için derlenebilir:
MOV EDX, [EBX + 8*EAX + 4] ; right side is "effective address"
hangi girerler y
içinde EDX
. 8 ölçek faktörü, her Point
birinin 8 bayt boyutunda olmasıdır. Şimdi, "operatörünün" adresi "ile kullanılan ifadenin aynısını düşünün:
int *p = &points[i].ycoord;
Bu durumda, değerini ycoord
değil, adresini istersiniz . İşte burada LEA
(yük etkili adres) devreye girer. A yerine MOV
derleyici
LEA ESI, [EBX + 8*EAX + 4]
adresi yükler ESI
.
mov
Talimatı uzatmak ve destekleri bırakmak daha temiz olmaz mıydı ? MOV EDX, EBX + 8*EAX + 4
MOV
dolaylı bir kaynağı olan bir gibidir , ancak sadece dolaylı değil MOV
. Aslında hesaplanan adresten okunmaz , sadece hesaplar.
Gönderen "Meclis Zen" Abrash tarafından:
LEA
, bellek adresleme hesaplamaları yapan ancak gerçekte belleğe hitap etmeyen tek talimattır.LEA
standart bir bellek adresleme işlenenini kabul eder, ancak hesaplanan bellek ofsetini belirtilen kayıt defterinde saklamaktan başka bir şey yapmaz, bu herhangi bir genel amaçlı kayıt olabilir.Bu bize ne veriyor? Sağlanmayan iki şey
ADD
:
- iki veya üç işlenenle ekleme yapma yeteneği ve
- sonucu herhangi bir kayıtta saklama yeteneği ; sadece kaynak işlenenlerden biri değil.
Ve LEA
bayrakları değiştirmez.
Örnekler
LEA EAX, [ EAX + EBX + 1234567 ]
hesaplar EAX + EBX + 1234567
(bu üç işlenen)LEA EAX, [ EBX + ECX ]
EBX + ECX
sonucu ile geçersiz kılmadan hesaplar .LEA EAX, [ EBX + N * EBX ]
(N 1,2,4,8 olabilir).Diğer Usecase döngülerinde kullanışlıdır: arasındaki fark LEA EAX, [ EAX + 1 ]
ve INC EAX
bu ikinci bir değişiklik olduğunu EFLAGS
, ancak eski değildir; bu CMP
devleti korur .
LEA EAX, [ EAX + EBX + 1234567 ]
toplamını hesaplar EAX
, EBX
ve 1234567
(üç işlenen s). LEA EAX, [ EBX + ECX ]
hesaplar EBX + ECX
olmayan sonucu ile ya da geçersiz kılma. Üçüncü şey LEA
(Frank tarafından listelenmeyen) 'dir kullanılır sabiti ile çarpma (iki, üç, beş veya dokuz tarafından) sizin gibi kullanırsanız, LEA EAX, [ EBX + N * EBX ]
( N
1,2,4,8 olabilir). Diğer Usecase döngülerinde kullanışlıdır: arasındaki fark LEA EAX, [ EAX + 1 ]
ve INC EAX
bu ikinci bir değişiklik olduğunu EFLAGS
, ancak eski değildir; bu CMP
devleti korur
LEA
( ") LEA (yük etkili adresine genellikle olarak kullanılır 'bölümüne bakın yukarıdaki IJ Kennedy popüler cevap' belirli hesaplamaları yapmak için" hile) için ... kullanılabilir
Bir diğer önemli özelliği LEA
talimatı bu gibi durum kodlarını değiştirmek olmamasıdır CF
ve ZF
benzeri aritmetik talimatlarla adresini hesaplama sırasında, ADD
ya da MUL
yok. Bu özellik, talimatlar arasındaki bağımlılık seviyesini azaltır ve böylece derleyici veya donanım zamanlayıcı tarafından daha fazla optimizasyon için yer açar.
lea
bazen derleyicinin (veya insan kodlayıcısının) bir bayrak sonucunu sarsmadan matematik yapması için yararlıdır. Ama lea
bundan daha hızlı değil add
. Çoğu x86 talimatı bayrak yazar. Yüksek performanslı x86 uygulamaları, EFLAGS'ı yeniden adlandırmalı veya normal kodun hızlı çalışması için yazma sonrası yazma tehlikesinden kaçınmalıdır, bu nedenle bayrak yazmalarını önleyen talimatlar bundan dolayı daha iyi değildir. ( kısmi bayrak işleri sorun yaratabilir, bkz. INC talimat vs EKLE 1: Önemli mi? )
Tüm açıklamalara rağmen, LEA aritmetik bir işlemdir:
LEA Rt, [Rs1+a*Rs2+b] => Rt = Rs1 + a*Rs2 + b
Sadece bir vardiya + ekleme işlemi için adının aşırı aptalca olması. Bunun nedeni en yüksek puanlı cevaplarda zaten açıklanmıştı (yani, yüksek düzeyli bellek referanslarını doğrudan eşleştirmek için tasarlanmıştır).
LEA
ise AGU'larda değil, sıradan tamsayı ALU'larında yürütülmeyi seçmiştir . Biri "şeyler nerede çalışır" bulmak için bu gün CPU özelliklerini çok yakından okumak zorunda ...
LEA
bellekle ilgili herhangi bir adresleme modundan kaynaklanan adresi verir. Bir vardiya ve ekleme işlemi değildir.
Belki sadece LEA eğitimi hakkında başka bir şey. LEA'yı kayıtları 3, 5 veya 9 ile hızlı çarpmak için de kullanabilirsiniz.
LEA EAX, [EAX * 2 + EAX] ;EAX = EAX * 3
LEA EAX, [EAX * 4 + EAX] ;EAX = EAX * 5
LEA EAX, [EAX * 8 + EAX] ;EAX = EAX * 9
LEA EAX, [EAX*3]
?
shl
çarpmak için sola kaydırma gibi talimatlar kullanabilirsiniz ... daha hızlı ve daha kısa. Ancak 2'nin gücünden farklı sayılarla çarpmak için normalde mul
daha iddialı ve daha yavaş olan talimatları kullanırız .
lea eax,[eax*3]
eşdeğerine çevirir lea eax,[eax+eax*2]
.
lea
"etkin yükleme adresi" nin kısaltmasıdır. Kaynak işlenen tarafından konum referansının adresini hedef işlenene yükler. Örneğin, aşağıdakileri yapmak için kullanabilirsiniz:
lea ebx, [ebx+eax*8]
ebx
işaretçi eax
öğelerini (64 bit / öğe dizisinde) tek bir komutla daha ileriye taşımak için . Temel olarak, işaretçileri verimli bir şekilde değiştirmek için x86 mimarisi tarafından desteklenen karmaşık adresleme modlarından faydalanırsınız.
A LEA
üzerinde kullanmanızın en büyük nedeni MOV
, adresi hesaplamak için kullandığınız kayıtlarda aritmetik işlem yapmanız gerektiğidir. Etkili bir şekilde, bir çok kayıt üzerinde işaretçi aritmetiğinin ne kadar etkili olduğunu "serbest" olarak etkili bir şekilde gerçekleştirebilirsiniz.
Bu konuda gerçekten kafa karıştırıcı olan şey, LEA
tıpkı bir gibi bir MOV
şey yazmanızdır, ancak aslında belleği derefere etmiyorsunuzdur. Başka bir deyişle:
MOV EAX, [ESP+4]
Bu, neyi ESP+4
işaret ettiğinin içeriğini taşıyacaktır EAX
.
LEA EAX, [EBX*8]
Bu, etkin adresi EBX * 8
o konumda bulunanlara değil EAX'e taşır . Gördüğünüz gibi, a MOV
, toplama / çıkarma ile sınırlıyken , iki faktörle (ölçeklendirme) çarpmak mümkündür .
LEA
.
8086, bir kayıt işlenenini ve etkili bir adresi kabul eden, bu etkili adresin ofset kısmını hesaplamak için bazı hesaplamalar yapan ve hesaplanan adres tarafından atıfta bulunulan kayıt ve hafızayı içeren bazı işlemleri gerçekleştiren geniş bir talimat ailesine sahiptir. Bu ailenin talimatlarından birinin, gerçek hafıza işlemini atlamak dışında yukarıdaki gibi davranması oldukça basitti. Bu, talimatlar:
mov ax,[bx+si+5]
lea ax,[bx+si+5]
neredeyse aynı şekilde dahili olarak uygulandı. Fark atlanan bir adımdır. Her iki talimat da şu şekilde çalışır:
temp = fetched immediate operand (5)
temp += bx
temp += si
address_out = temp (skipped for LEA)
trigger 16-bit read (skipped for LEA)
temp = data_in (skipped for LEA)
ax = temp
Intel'in neden bu talimatın dahil edilmeye değer olduğunu düşündüğüne gelince, tam olarak emin değilim, ancak uygulamanın ucuz olması büyük bir faktör olurdu. Başka bir faktör, Intel'in toplayıcısının sembollerin BP kaydına göre tanımlanmasına izin vermesiydi. Eğer fnord
bir BP-nispi sembolü olarak tanımlandı (örneğin BP + 8) denebilir:
mov ax,fnord ; Equivalent to "mov ax,[BP+8]"
Bir kişi BP göreli bir adrese veri depolamak için stosw gibi bir şey kullanmak isterse,
mov ax,0 ; Data to store
mov cx,16 ; Number of words
lea di,fnord
rep movs fnord ; Address is ignored EXCEPT to note that it's an SS-relative word ptr
daha uygun:
mov ax,0 ; Data to store
mov cx,16 ; Number of words
mov di,bp
add di,offset fnord (i.e. 8)
rep movs fnord ; Address is ignored EXCEPT to note that it's an SS-relative word ptr
Dünya "ofset" inin unutulmasının DI değerine 8 değeri yerine [BP + 8] içeriğinin eklenmesine neden olacağını unutmayın. Hata.
Bahsedilen mevcut cevaplar, LEA
belleğe erişmeden bellek adresleme aritmetiği gerçekleştirmenin avantajlarına sahiptir, aritmetik sonucu basit ekleme talimatı yerine farklı bir kayıt defterine kaydeder. Temel performans avantajı, modern işlemcinin etkili adres üretimi için ayrı bir LEA ALU birimi ve bağlantı noktasına sahip olmasıdır ( LEA
ve diğer bellek referans adresi dahil), bu, ALU'daki LEA
aritmetik işlemin ve ALU'daki diğer normal aritmetik işlemin bir arada paralel olarak yapılabileceği anlamına gelir. çekirdek.
LEA birimi hakkında bazı ayrıntılar için Haswell mimarisinin bu makalesine bakın: http://www.realworldtech.com/haswell-cpu/4/
Diğer cevaplarda belirtilmeyen bir diğer önemli nokta, LEA REG, [MemoryAddress]
talimattır, bu talimattaki PC'nin göreceli adresini referans olarak kodlayan PIC'dir (konumdan bağımsız kod) MemoryAddress
. Bu, MOV REG, MemoryAddress
göreli sanal adresi kodlayandan farklıdır ve modern işletim sistemlerinde (ASLR ortak özelliktir) yer değiştirme / yama gerektirmektedir. Bu LEA
tür PIC olmayanları PIC'ye dönüştürmek için kullanılabilir.
lea
, diğer aritmetik talimatları yürüten aynı ALU'ların biri veya daha fazlasında yürütülür (ancak genellikle diğer aritmetik işlemlerden daha azdır). Örneğin, bahsedilen Haswell CPU dört farklı ALU üzerinde veya diğer temel aritmetik işlemleri gerçekleştirebilir add
veya sadece bir (karmaşık ) veya iki (basit ) işlem yapabilir. Daha da önemlisi, bu iki yetenekli ALU, diğer talimatları yürütebilecek olan dördünden sadece ikisidir, bu nedenle iddia edildiği gibi paralellik faydası yoktur. sub
lea
lea
lea
lea
LEA komutu, CPU tarafından etkili adreslerin zaman alıcı hesaplamalarını önlemek için kullanılabilir. Bir adres tekrar tekrar kullanılıyorsa, etkin adresi her kullanıldığında hesaplamak yerine bir kayıt defterinde saklamak daha etkilidir.
[esi]
söylemek nadiren daha ucuz [esi + 4200]
ve nadiren daha ucuzdur [esi + ecx*8 + 4200]
.
[esi]
daha ucuz değil [esi + ecx*8 + 4200]
. Ama neden karşılaştırma zahmetine giriyorsun? Eşdeğer değiller. Birincisinin ikincisi ile aynı bellek konumunu belirlemesini istiyorsanız, ek talimatlara ihtiyacınız vardır: 8 esi
ile ecx
çarpma değerine eklemeniz gerekir . Daha sonra 4200'ü eklemeniz gerekir. Bu ek talimatlar kod boyutuna eklenir (talimat önbelleğinde yer kaplar, getirilecek döngüler).
[esi + 4200]
bir dizi talimatta tekrar tekrar gibi bir şey kullanacaksanız , önce etkili adresi bir kayıt defterine yüklemek ve kullanmak daha iyi olduğunu söylüyor. Örneğin, yazmak yerine , nadiren daha hızlı olan add eax, [esi + 4200]; add ebx, [esi + 4200]; add ecx, [esi + 4200]
tercih etmelisiniz lea edi, [esi + 4200]; add eax, [edi]; add ebx, [edi]; add ecx, [edi]
. En azından bu cevabın açık yorumu.
[esi]
ve [esi + 4200]
(veya [esi + ecx*8 + 4200]
(Anladığım kadarıyla) bu OP önerdiği sadeleştirme olmasıdır: Aynı kompleks adresi ile N talimatları basit (tek reg) adresleme, artı bir N talimatları dönüşmelerini lea
, çünkü karmaşık adresleme "zaman alıcıdır" Aslında, modern
lea
, bu durumda basıncı arttırır. Genel olarak, ara maddelerin depolanması kayıt baskısının bir nedenidir, bunun için bir çözüm değildir - ancak çoğu durumda bir yıkama olduğunu düşünüyorum. @Kaz
LEA (Etkin Adres Yükle) talimatı, Intel işlemcinin bellek adresleme modlarından herhangi birinden kaynaklanan adresi almanın bir yoludur.
Yani, böyle bir veri taşıma işlemimiz varsa:
MOV EAX, <MEM-OPERAND>
belirlenen bellek konumunun içeriğini hedef yazmacıya taşır.
Biz değiştirirseniz MOV
biriminin by LEA
ardından hafıza yerin adresi ile aynı şekilde hesaplanır <MEM-OPERAND>
adresleme ifadesi. Ancak bellek konumunun içeriği yerine, konumun kendisini hedefe alırız.
LEA
spesifik bir aritmetik komut değildir; işlemcinin bellek adresleme modlarından herhangi birinden kaynaklanan etkili adresi yakalamanın bir yoludur.
Örneğin LEA
, sadece basit bir doğrudan adres üzerinde kullanabiliriz . Hiçbir aritmetik söz konusu değildir:
MOV EAX, GLOBALVAR ; fetch the value of GLOBALVAR into EAX
LEA EAX, GLOBALVAR ; fetch the address of GLOBALVAR into EAX.
Bu geçerlidir; Linux isteminde test edebiliriz:
$ as
LEA 0, %eax
$ objdump -d a.out
a.out: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 8d 04 25 00 00 00 00 lea 0x0,%eax
Burada ölçeklendirilmiş bir değer ve ofset yoktur. Sıfır EAX'a taşınır. Bunu anında bir işlenenle MOV kullanarak yapabiliriz.
Köşeli parantezlerin LEA
gereksiz olduğunu düşünen insanların ciddi şekilde yanlış olmasının nedeni budur ; köşeli ayraçlar LEA
sözdizimi değildir ancak adresleme modunun bir parçasıdır.
LEA donanım düzeyinde gerçektir. Oluşturulan talimat, gerçek adresleme modunu kodlar ve işlemci, adresi hesaplama noktasına kadar gerçekleştirir. Sonra bu adresi bir bellek başvurusu oluşturmak yerine hedefe taşır. (Başka bir talimatta adresleme modunun adres hesaplamasının CPU bayrakları LEA
üzerinde hiçbir etkisi olmadığından, CPU bayrakları üzerinde hiçbir etkisi yoktur.)
Sıfır adresinden değeri yükleme ile kontrast:
$ as
movl 0, %eax
$ objdump -d a.out | grep mov
0: 8b 04 25 00 00 00 00 mov 0x0,%eax
Çok benzer bir kodlama, anlıyor musunuz? Sadece 8d
of LEA
olarak değişti 8b
.
Tabii ki, bu LEA
kodlama hemen sıfırın içine taşınmasından daha uzundur EAX
:
$ as
movl $0, %eax
$ objdump -d a.out | grep mov
0: b8 00 00 00 00 mov $0x0,%eax
LEA
Ancak daha kısa bir alternatif olduğu için bu olasılığı dışlamak için hiçbir neden yoktur ; sadece mevcut adresleme modlarıyla dikey bir şekilde birleşiyor.
İşte bir örnek.
// compute parity of permutation from lexicographic index
int parity (int p)
{
assert (p >= 0);
int r = p, k = 1, d = 2;
while (p >= k) {
p /= d;
d += (k << 2) + 6; // only one lea instruction
k += 2;
r ^= p;
}
return r & 1;
}
Derleyici seçeneği olarak -O (optimizasyon) ile gcc, belirtilen kod satırı için lea komutunu bulacaktır.
Görünüşe göre çok sayıda cevap zaten tamamlandı, ben aynı ifade biçimine sahip olduğunda lea ve move komutunun nasıl farklı çalıştığını göstermek için bir örnek kod eklemek istiyorum.
Uzun bir hikaye kısaca anlatmak için, hem talimat hem de mov talimatları, talimatların src işlenenini içeren parantezlerle birlikte kullanılabilir. Bunlar bir arada yer alan zaman () , ekspresyon () aynı şekilde hesaplanır; ancak, iki komut src işlenenindeki hesaplanan değeri farklı bir şekilde yorumlar.
İfade, lea veya mov ile kullanıldığında, src değeri aşağıdaki gibi hesaplanır.
D (Rb, Ri, S) => (Reg [Rb] + S * Reg [Ri] + D)
Ancak, mov komutuyla birlikte kullanıldığında, yukarıdaki ifade tarafından üretilen adresin işaret ettiği değere erişmeye ve onu hedefe depolamaya çalışır.
Bunun aksine, lea komutu yukarıdaki ifadeyle yürütüldüğünde, üretilen değeri hedefe olduğu gibi yükler.
Aşağıdaki kod, lea komutunu ve mov komutunu aynı parametre ile yürütür. Ancak, farkı yakalamak için, mov komutunun bir sonucu olarak yanlış bir adrese erişmenin neden olduğu segmentasyon hatasını yakalamak için bir kullanıcı seviyesi sinyal işleyicisi ekledim.
Örnek kod
#define _GNU_SOURCE 1 /* To pick up REG_RIP */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
uint32_t
register_handler (uint32_t event, void (*handler)(int, siginfo_t*, void*))
{
uint32_t ret = 0;
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO;
ret = sigaction(event, &act, NULL);
return ret;
}
void
segfault_handler (int signum, siginfo_t *info, void *priv)
{
ucontext_t *context = (ucontext_t *)(priv);
uint64_t rip = (uint64_t)(context->uc_mcontext.gregs[REG_RIP]);
uint64_t faulty_addr = (uint64_t)(info->si_addr);
printf("inst at 0x%lx tries to access memory at %ld, but failed\n",
rip,faulty_addr);
exit(1);
}
int
main(void)
{
int result_of_lea = 0;
register_handler(SIGSEGV, segfault_handler);
//initialize registers %eax = 1, %ebx = 2
// the compiler will emit something like
// mov $1, %eax
// mov $2, %ebx
// because of the input operands
asm("lea 4(%%rbx, %%rax, 8), %%edx \t\n"
:"=d" (result_of_lea) // output in EDX
: "a"(1), "b"(2) // inputs in EAX and EBX
: // no clobbers
);
//lea 4(rbx, rax, 8),%edx == lea (rbx + 8*rax + 4),%edx == lea(14),%edx
printf("Result of lea instruction: %d\n", result_of_lea);
asm volatile ("mov 4(%%rbx, %%rax, 8), %%edx"
:
: "a"(1), "b"(2)
: "edx" // if it didn't segfault, it would write EDX
);
}
Yürütme sonucu
Result of lea instruction: 14
inst at 0x4007b5 tries to access memory at 14, but failed
=d
derleyiciye sonucun EDX'te olduğunu söylemek için kullanabilirsiniz , a mov
. Ayrıca çıktıda erken bir gecikme bildirimi bıraktınız. Bu, göstermeye çalıştığınız şeyi gösterir, ancak aynı zamanda diğer bağlamlarda kullanıldığında kırılacak olan yanıltıcı kötü bir inline asm örneğidir. Bir yığın taşması cevabı için bu Kötü Bir Şey.
%%
Tüm bu kayıt adlarına Genişletilmiş asm'de yazmak istemiyorsanız , giriş kısıtlamalarını kullanın. gibi asm("lea 4(%%ebx, %%eax, 8), %%edx" : "=d"(result_of_lea) : "a"(1), "b"(2));
. Derleyicinin kayıtlarını başlatmasına izin vermek, clobbers bildirmek zorunda olmadığınız anlamına da gelir. Mov-instant tüm kaydın üzerine yazmadan önce xor-zeroing ile işleri çok karmaşık hale getiriyorsunuz.
mov 4(%ebx, %eax, 8), %edx
geçersiz olduğunu nereden söylüyor ? Her neyse, evet, derleyiciye 64 bit değerine sahip olduğunuzu söylemek mov
için yazmak mantıklı olacaktır "a"(1ULL)
ve bu nedenle tüm kaydı doldurmak için genişletildiğinden emin olmalıdır. Pratikte yine de kullanacaktır mov $1, %eax
, çünkü derleyicinin RAX = 0xff00000001
veya başka bir şey bildiği çevreleyen kodun garip bir durumu yoksa, EAX yazmak sıfır olarak RAX'a uzanır . Çünkü lea
, hala 32 bit işlenen boyutu kullanıyorsunuz, bu nedenle giriş kayıtlarındaki yüksek bitlerin 32 bit sonucu üzerinde hiçbir etkisi yoktur.
LEA: sadece bir "aritmetik" talimat ..
MOV işlenenler arasında veri aktarıyor ancak lea sadece hesaplıyor
mov eax, offset GLOBALVAR
. Sen edebilirsiniz LEA kullanmak, ancak biraz daha büyük kod boyutu var mov r32, imm32
ve daha az bağlantı noktalarında çalışır hala adres hesaplama sürecinden geçer çünkü . lea reg, symbol
PIC ve / veya düşük 32 bitin dışındaki adreslere ihtiyacınız olduğunda, yalnızca RIP'ye bağlı LEA için 64 bit olarak kullanışlıdır. 32 veya 16 bit kodda sıfır avantaj vardır. LEA, CPU'nun adresleme modlarını çözme / hesaplama yeteneğini ortaya koyan aritmetik bir talimattır.
imul eax, edx, 1
bunun hesaplanmadığını söyleyebilirsiniz : sadece edx'i eax'a kopyalar. Ama aslında verilerinizi 3 döngü gecikmeli çarpandan geçirir. Ya da rorx eax, edx, 0
sadece kopyalar (sıfıra döndür).
Çarpma, özel veya sıfır gibi durum bayrakları ayarlamak gibi tüm normal "hesaplama" talimatları, işareti. Karmaşık bir adres kullanırsanız AX xor:= mem[0x333 +BX + 8*CX]
, bayraklar xor işlemine göre ayarlanır.
Şimdi adresi birden çok kez kullanmak isteyebilirsiniz. Böyle bir adresin bir kayıt defterine yüklenmesi hiçbir zaman durum bayraklarını ayarlamayı amaçlamaz ve neyse ki yapmaz. "Yükü etkin adres" ifadesi programcıyı bu konuda bilgilendirir. Tuhaf ifade buradan geliyor.
İşlemci, karmaşık adresi içeriğini işlemek için kullanabildiğinde, başka amaçlar için hesaplayabileceği açıktır. Gerçekten de, x <- 3*x+1
bir talimatta bir dönüşüm gerçekleştirmek için kullanılabilir . Bu, montaj programlamasında genel bir kuraldır: Talimatları kullanın, ancak teknenizi sallar.
Önemli olan tek şey, talimatın somutlaştırdığı dönüşümün sizin için yararlı olup olmadığıdır.
Sonuç olarak
MOV, X| T| AX'| R| BX|
ve
LEA, AX'| [BX]
AX üzerinde aynı etkiye sahiptir, ancak durum bayrakları üzerinde değil. (Bu ciasdis gösterimi.)
call lbl
lbl: pop rax
teknik olarak “çalışma” gibi şeylerden dolayı değerini elde etmenin bir yolu olarak vermem rip
, ancak şube tahminini çok mutsuz edersiniz. Talimatları istediğiniz gibi kullanın, ancak zor bir şey yaparsanız ve bunun öngörmediğiniz sonuçları olursa
Birisi daha önce bahsetmişse beni affet, ancak bellek segmentasyonunun hala alakalı olduğu x86 günlerinde, bu iki talimattan aynı sonuçları alamayabilirsiniz:
LEA AX, DS:[0x1234]
ve
LEA AX, CS:[0x1234]
seg:off
çiftin sadece "ofset" kısmıdır . LEA segment tabanından etkilenmez; her iki talimat da (verimsiz olarak) 0x1234
AX'a aktarılacaktır. x86 maalesef bir kayıt veya kayıt çiftine tam bir doğrusal adres (etkili + segment tabanı) hesaplamanın kolay bir yolu yoktur.