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 EBXve değişken iolan EAXve xcoordve ycoordher biri 32 bit (so ycoordyapı ofset 4 bayt olduğunu), bu açıklama için derlenebilir:
MOV EDX, [EBX + 8*EAX + 4] ; right side is "effective address"
hangi girerler yiçinde EDX. 8 ölçek faktörü, her Pointbirinin 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 ycoorddeğil, adresini istersiniz . İşte burada LEA(yük etkili adres) devreye girer. A yerine MOVderleyici
LEA ESI, [EBX + 8*EAX + 4]
adresi yükler ESI.
movTalimatı uzatmak ve destekleri bırakmak daha temiz olmaz mıydı ? MOV EDX, EBX + 8*EAX + 4
MOVdolaylı 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.LEAstandart 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 LEAbayrakları değiştirmez.
Örnekler
LEA EAX, [ EAX + EBX + 1234567 ]hesaplar EAX + EBX + 1234567(bu üç işlenen)LEA EAX, [ EBX + ECX ]EBX + ECXsonucu 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 EAXbu ikinci bir değişiklik olduğunu EFLAGS, ancak eski değildir; bu CMPdevleti korur .
LEA EAX, [ EAX + EBX + 1234567 ]toplamını hesaplar EAX, EBXve 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 ]( N1,2,4,8 olabilir). Diğer Usecase döngülerinde kullanışlıdır: arasındaki fark LEA EAX, [ EAX + 1 ]ve INC EAXbu ikinci bir değişiklik olduğunu EFLAGS, ancak eski değildir; bu CMPdevleti 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 LEAtalimatı bu gibi durum kodlarını değiştirmek olmamasıdır CFve ZFbenzeri aritmetik talimatlarla adresini hesaplama sırasında, ADDya da MULyok. 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.
leabazen derleyicinin (veya insan kodlayıcısının) bir bayrak sonucunu sarsmadan matematik yapması için yararlıdır. Ama leabundan 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).
LEAise 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 ...
LEAbellekle 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 muldaha 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]
ebxiş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, LEAtı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+4işaret ettiğinin içeriğini taşıyacaktır EAX.
LEA EAX, [EBX*8]
Bu, etkin adresi EBX * 8o 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 fnordbir 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, LEAbelleğ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 ( LEAve diğer bellek referans adresi dahil), bu, ALU'daki LEAaritmetik 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, MemoryAddressgöreli sanal adresi kodlayandan farklıdır ve modern işletim sistemlerinde (ASLR ortak özelliktir) yer değiştirme / yama gerektirmektedir. Bu LEAtü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 addveya 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. sublealealealea
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 esiile 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 MOVbiriminin by LEAardı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.
LEAspesifik 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 LEAgereksiz olduğunu düşünen insanların ciddi şekilde yanlış olmasının nedeni budur ; köşeli ayraçlar LEAsö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 8dof LEAolarak değişti 8b.
Tabii ki, bu LEAkodlama 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
LEAAncak 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
=dderleyiciye 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), %edxgeçersiz olduğunu nereden söylüyor ? Her neyse, evet, derleyiciye 64 bit değerine sahip olduğunuzu söylemek moviç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 = 0xff00000001veya 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, imm32ve daha az bağlantı noktalarında çalışır hala adres hesaplama sürecinden geçer çünkü . lea reg, symbolPIC 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, 1bunun 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, 0sadece 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+1bir 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 raxteknik 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) 0x1234AX'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.