답변:
다른 사람들이 지적했듯이 LEA (부하 유효 주소)는 종종 특정 계산을 수행하기위한 "트릭"으로 사용되지만 이는 기본 목적이 아닙니다. x86 명령어 세트는 Pascal 및 C와 같은 고급 언어를 지원하도록 설계되었으며, 특히 배열 int 또는 작은 구조체 배열이 일반적입니다. 예를 들어 (x, y) 좌표를 나타내는 구조체를 고려하십시오.
struct Point
{
int xcoord;
int ycoord;
};
이제 다음과 같은 진술을 상상해보십시오.
int y = points[i].ycoord;
points[]
의 배열은 어디 입니까 Point
? 어레이의 기본 가정은 이미 EBX
한 변수 i
이다 EAX
하고 xcoord
그리고 ycoord
각각 32 비트 (너무되어 ycoord
구조체 오프셋 4 바이트로된다),이 문에 컴파일 될 수있다 :
MOV EDX, [EBX + 8*EAX + 4] ; right side is "effective address"
이는 토지됩니다 y
에 EDX
. 8의 스케일 팩터는 각각 Point
크기가 8 바이트 이기 때문 입니다. 이제 "주소"연산자와 함께 사용 된 것과 동일한 표현을 고려하십시오 :
int *p = &points[i].ycoord;
이 경우의 값이 ycoord
아니라 주소를 원합니다 . 곳이다 LEA
(부하 효과적인 주소)에서 제공됩니다. 대신의 MOV
컴파일러는 생성 할 수 있습니다
LEA ESI, [EBX + 8*EAX + 4]
에 주소를로드합니다 ESI
.
mov
명령 을 확장 하고 브래킷을 제거하는 것이 더 깨끗하지 않았 습니까? MOV EDX, EBX + 8*EAX + 4
MOV
간접 소스 만있는 것과 비슷하지만 간접적으로 만 수행하고 MOV
. 실제로 계산 된 주소 에서 읽지 않고 단지 계산합니다.
로부터 "총회의 선" Abrash의 :
LEA
메모리 어드레싱 계산을 수행하지만 실제로 메모리를 어드레싱하지는 않는 유일한 명령어입니다.LEA
표준 메모리 주소 지정 피연산자를 허용하지만 계산 된 메모리 오프셋을 지정된 레지스터에 저장하는 것 외에는 범용 레지스터 일 수 있습니다.그것은 우리에게 무엇을 제공합니까?
ADD
제공하지 않는 두 가지 :
- 2 개 또는 3 개의 피연산자로 덧셈을 수행하는 기능
- 결과를 임의의 레지스터 에 저장하는 능력 ; 소스 피연산자 중 하나만이 아닙니다.
그리고 LEA
플래그를 변경하지 않습니다.
예
LEA EAX, [ EAX + EBX + 1234567 ]
계산 EAX + EBX + 1234567
(세 피연산자)LEA EAX, [ EBX + ECX ]
결과 EBX + ECX
를 무시하지 않고 계산 합니다.LEA EAX, [ EBX + N * EBX ]
(N은 1,2,4,8이 될 수 있음) 처럼 사용하면 상수로 곱하기 (2, 3, 5 또는 9 ).다른 유스 케이스는 루프에 편리합니다 : 차이 LEA EAX, [ EAX + 1 ]
와는 INC EAX
그 후자의 변화입니다 EFLAGS
하지만 전자는하지 않습니다; 이것은 CMP
상태를 유지 합니다.
LEA EAX, [ EAX + EBX + 1234567 ]
의 합을 계산 EAX
, EBX
및 1234567
(즉, 세 개의 오퍼랜드이다). LEA EAX, [ EBX + ECX ]
결과 EBX + ECX
를 무시 하지 않고 계산 합니다. 세 번째 LEA
로 (Frank에 나열되지 않음 ) 사용하는 경우 ( 1,2,4,8 일 수 있음) 상수를 사용하여 곱하기 (2, 3, 5 또는 9 )입니다. 다른 유스 케이스는 루프에 편리합니다 : 차이 와는 그 후자의 변화입니다 하지만 전자는하지 않습니다; 이것은 상태를 유지 합니다LEA EAX, [ EBX + N * EBX ]
N
LEA EAX, [ EAX + 1 ]
INC EAX
EFLAGS
CMP
LEA
( ") LEA (부하 효과적인 주소 종종 사용"을 참조하십시오 위의 IJ 케네디의 인기 대답은 "특정 계산을 할 수있는"트릭)에 대한 ... 사용할 수 있습니다
의 또 다른 중요한 기능 LEA
명령은 같은 조건 코드를 변경하지 않는다는 것입니다 CF
와 ZF
같은 산술 명령어로 주소를 계산하는 동안, ADD
또는 MUL
한다. 이 기능은 명령어 간의 종속성 수준을 낮추므로 컴파일러 또는 하드웨어 스케줄러에 의해 추가 최적화를위한 공간을 만듭니다.
lea
때로는 컴파일러 (또는 인간 코더)가 플래그 결과를 방해하지 않고 수학을 수행하는 데 유용합니다. 그러나 lea
보다 빠르지 않습니다 add
. 대부분의 x86 명령어는 플래그를 작성합니다. 고성능 x86 구현은 EFLAGS의 이름을 바꾸거나 일반 코드가 빠르게 실행될 수 있는 쓰기 후 쓰기 위험 을 피해야합니다. 따라서 플래그 쓰기를 피하는 명령어는 그로 인해 좋지 않습니다. ( 부분 플래그 문제는 문제를 일으킬 수 있습니다. INC 명령 vs ADD 1 : 문제가됩니까? )
모든 설명에도 불구하고 LEA는 산술 연산입니다.
LEA Rt, [Rs1+a*Rs2+b] => Rt = Rs1 + a*Rs2 + b
단지 shift + add 연산의 이름이 멍청하다는 것입니다. 그 이유는 이미 최고 등급의 답변에서 설명되었습니다 (즉, 높은 수준의 메모리 참조를 직접 매핑하도록 설계되었습니다).
LEA
일반 정수 ALU에서 실행하도록 선택했습니다 . 요즘 CPU 사양을 아주 자세히
LEA
메모리 관련 주소 지정 모드에서 발생하는 주소를 제공합니다. 시프트 및 추가 작업이 아닙니다.
LEA 교육에 관한 또 다른 것. 레지스터에 3, 5 또는 9를 빠르게 곱하기 위해 LEA를 사용할 수도 있습니다.
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
레지스터에 2,4,8,16을 곱하는 명령 처럼 왼쪽으로 시프트를 사용할 수 있습니다 ... 더 빠르고 짧습니다. 그러나 2의 거듭 제곱과 다른 숫자를 곱하기 위해 우리 mul
는 일반적으로 더 소박하고 느린 명령을 사용 합니다.
lea eax,[eax*3]
의 동등한 번역 것이다 lea eax,[eax+eax*2]
.
lea
"로드 유효 주소"의 약어입니다. 소스 피연산자가 위치 참조의 주소를 대상 피연산자로로드합니다. 예를 들어, 다음과 같은 용도로 사용할 수 있습니다.
lea ebx, [ebx+eax*8]
단일 명령 으로 ebx
포인터 eax
항목을 64 비트 / 요소 배열로 더 이동 합니다. 기본적으로 x86 아키텍처에서 지원하는 복잡한 주소 지정 모드의 이점을 활용하여 포인터를 효율적으로 조작 할 수 있습니다.
LEA
a 를 사용하는 가장 큰 이유 MOV
는 주소를 계산하는 데 사용하는 레지스터에서 산술을 수행해야하는 경우입니다. 효과적으로, "무료"에 대해 효과적으로 여러 레지스터에서 포인터 산술 연산을 수행 할 수 있습니다.
실제로 혼란스러워하는 것은 일반적으로 LEA
비슷하게 작성 MOV
하지만 실제로 메모리를 역 참조하지는 않는다는 것입니다. 다시 말해:
MOV EAX, [ESP+4]
그러면가 ESP+4
가리키는 내용이로 이동합니다 EAX
.
LEA EAX, [EBX*8]
이렇게하면 유효 주소 EBX * 8
가 해당 위치에있는 주소 가 아닌 EAX로 이동합니다 . 보시다시피, a MOV
는 더하기 / 빼기로 제한되는 반면 두 가지 요인 (확장)을 곱하는 것이 가능합니다 .
LEA
.
8086에는 레지스터 피연산자와 유효 주소를 허용하고, 계산을 수행하여 해당 유효 주소의 오프셋 부분을 계산하고, 레지스터 및 계산 된 주소가 참조하는 메모리와 관련된 일부 연산을 수행하는 명령 제품군이 있습니다. 실제 메모리 작업을 건너 뛰는 것을 제외하고 해당 제품군의 명령 중 하나를 위와 같이 동작시키는 것은 매우 간단했습니다. 이 지침은 다음과 같습니다.
mov ax,[bx+si+5]
lea ax,[bx+si+5]
내부적으로 거의 동일하게 구현되었습니다. 차이점은 건너 뛴 단계입니다. 두 명령 모두 다음과 같이 작동합니다.
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
인텔이이 교육에 포함시킬 가치가 있다고 생각한 이유는 확실하지 않지만, 구현하기에 비용이 적게 든다는 사실이 큰 요인이었습니다. 또 다른 요인은 인텔의 어셈블러가 BP 레지스터를 기준으로 심볼을 정의 할 수 있다는 사실이었습니다. fnord
BP 기준 기호 (예 : BP + 8)로 정의 된 경우 다음과 같이 말할 수 있습니다.
mov ax,fnord ; Equivalent to "mov ax,[BP+8]"
stosw와 같은 것을 사용하여 BP 상대 주소에 데이터를 저장하려는 경우
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
보다 편리했다 :
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
세계 "오프셋"을 잊어 버리면 값 8 대신 위치 [BP + 8]의 내용이 DI에 추가됩니다. 죄송합니다.
기존 답변에서 언급했듯이 LEA
메모리에 액세스하지 않고 메모리 주소 지정 연산을 수행하여 간단한 형태의 add 명령어 대신 다른 레지스터에 산술 결과를 저장하는 이점이 있습니다. 실제 기본 성능 이점은 최신 프로세서에 효과적인 주소 생성 ( LEA
및 기타 메모리 참조 주소 포함)을위한 별도의 LEA ALU 장치 및 포트가 있다는 것입니다. 이는 ALU 의 산술 연산 LEA
및 기타 일반 산술 연산이 하나의 병렬로 수행 될 수 있음을 의미합니다. 핵심.
LEA 장치에 대한 자세한 내용은 Haswell 아키텍처의이 기사를 확인하십시오. http://www.realworldtech.com/haswell-cpu/4/
다른 답변에서 언급되지 않은 또 다른 중요한 점은 LEA REG, [MemoryAddress]
명령입니다 MemoryAddress
. 이 명령에서 PC 상대 주소를 참조하도록 인코딩하는 PIC (위치 독립적 인 코드)입니다 . 이는 MOV REG, MemoryAddress
상대 가상 주소를 인코딩하는 것과 다르며 최신 운영 체제에서 재배치 / 패치를 요구합니다 (ASLR이 일반적인 기능). 따라서 LEA
이러한 비 PIC를 PIC로 변환하는 데 사용할 수 있습니다.
lea
다른 산술 명령어를 실행 하는 하나 이상의 동일한 ALU에서 실행됩니다 (그러나 일반적으로 다른 산술보다 적습니다). 예를 들어, 언급 된 Haswell CPU 는 4 개의 서로 다른 ALU에서 실행 add
되거나 sub
대부분의 다른 기본 산술 연산을 수행 할 수 있지만 1 (복잡 ) 또는 2 (단순 ) 에서만 실행할 수 있습니다 . 더 중요한 것은,이 2 개의 가능 ALU는 다른 명령을 실행할 수있는 4 개 중 2 개일 뿐이므로 청구 된 병렬 처리 이점은 없습니다. lea
lea
lea
lea
LEA 명령어는 CPU에 의한 유효 주소 계산에 시간이 걸리는 것을 피하기 위해 사용될 수 있습니다. 주소를 반복해서 사용하는 경우 주소를 사용할 때마다 유효 주소를 계산하는 대신 레지스터에 저장하는 것이 더 효과적입니다.
[esi]
말하는 [esi + 4200]
것보다 거의 저렴하지 않습니다 [esi + ecx*8 + 4200]
.
[esi]
는보다 저렴하지 않습니다 [esi + ecx*8 + 4200]
. 그러나 왜 귀찮게 비교합니까? 그것들은 동등하지 않습니다. 전자가 후자와 동일한 메모리 위치를 지정하려면 추가 지침이 필요 esi
합니다. 값 ecx
에 8 을 곱 해야 합니다. 어, 곱셈은 CPU 플래그를 방해합니다! 그런 다음 4200을 추가해야합니다. 이러한 추가 명령어는 코드 크기에 추가됩니다 (명령 캐시의 공간 확보, 페치주기).
[esi + 4200]
명령 시퀀스에서 반복적으로 같은 것을 사용 하려면 먼저 유효 주소를 레지스터에로드하고 사용하는 것이 좋습니다. 예를 들어을 쓰는 대신 add eax, [esi + 4200]; add ebx, [esi + 4200]; add ecx, [esi + 4200]
을 선호해야합니다 lea edi, [esi + 4200]; add eax, [edi]; add ebx, [edi]; add ecx, [edi]
. 적어도이 답변에 대한 명확한 해석입니다.
[esi]
하고 있는 이유는 [esi + 4200]
(또는 [esi + ecx*8 + 4200]
이것이 OP가 제안한 단순화이기 때문에) (복잡한 주소를 가진 N 개의 명령어는 간단한 (하나의 reg) 주소 지정과 하나의 lea
, 복잡한 주소 지정은 "시간이 많이 걸리므로"실제로는 최신 x86에서도 속도가 느리지 만 지연 시간 만 적용되므로 동일한 주소를 가진 연속 명령어에는 문제가되지 않을 것입니다.
lea
. 일반적으로 중간체를 저장하는 것은 레지스터 압력의 원인이며 해결책은 아닙니다. 그러나 대부분의 상황에서는 세척이라고 생각합니다. @Kaz
LEA (Load Effective Address) 명령어는 인텔 프로세서의 메모리 주소 지정 모드에서 발생하는 주소를 얻는 방법입니다.
즉, 다음과 같이 데이터가 이동하면
MOV EAX, <MEM-OPERAND>
지정된 메모리 위치의 내용을 대상 레지스터로 이동합니다.
MOV
by 를 대체하면 LEA
주소 <MEM-OPERAND>
지정 표현식 과 동일한 방식으로 메모리 위치의 주소가 계산됩니다 . 그러나 메모리 위치의 내용 대신 위치 자체를 대상으로 가져옵니다.
LEA
특정 산술 명령어가 아닙니다. 프로세서의 메모리 주소 지정 모드 중 하나에서 발생하는 유효 주소를 가로채는 방법입니다.
예를 들어 LEA
간단한 직접 주소로만 사용할 수 있습니다 . 산술이 전혀 필요하지 않습니다.
MOV EAX, GLOBALVAR ; fetch the value of GLOBALVAR into EAX
LEA EAX, GLOBALVAR ; fetch the address of GLOBALVAR into EAX.
유효합니다. Linux 프롬프트에서 테스트 할 수 있습니다.
$ 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
여기에는 스케일링 된 값이 추가되지 않으며 오프셋이 없습니다. 0은 EAX로 이동합니다. 우리는 즉각적인 피연산자와 함께 MOV를 사용하여 그렇게 할 수 있습니다.
이것이 대괄호 LEA
가 불필요 하다고 생각하는 사람들 이 심각하게 착각 하는 이유입니다 . 대괄호는 LEA
구문이 아니지만 주소 지정 모드의 일부입니다.
LEA는 하드웨어 수준에서 실제입니다. 생성 된 명령어는 실제 어드레싱 모드를 인코딩하고 프로세서는이를 주소 계산 지점까지 수행합니다. 그런 다음 메모리 참조를 생성하는 대신 해당 주소를 대상으로 이동합니다. (다른 명령어에서 주소 지정 모드의 주소 계산은 CPU 플래그에 LEA
영향을 미치지 않으므로 CPU 플래그에는 영향을 미치지 않습니다.)
주소 0에서 값을로드하는 것과 대조 :
$ as
movl 0, %eax
$ objdump -d a.out | grep mov
0: 8b 04 25 00 00 00 00 mov 0x0,%eax
매우 비슷한 인코딩입니다. 그냥 8d
의이 LEA
변경되었습니다 8b
.
물론이 LEA
인코딩은 즉시 0을 EAX
다음 으로 옮기는 것보다 깁니다 .
$ as
movl $0, %eax
$ objdump -d a.out | grep mov
0: b8 00 00 00 00 mov $0x0,%eax
LEA
대안이 더 짧기 때문에이 가능성을 배제 할 이유는 없습니다 . 사용 가능한 주소 지정 모드와 직교 방식으로 결합됩니다.
다음은 예입니다.
// 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;
}
컴파일러 옵션으로 -O (최적화)를 사용하면 gcc는 표시된 코드 행에 대한 lea 명령어를 찾습니다.
많은 답변이 이미 완료된 것 같습니다. lea 및 이동 명령이 동일한 표현 형식을 가질 때 다르게 작동하는 방법을 보여주는 예제 코드를 하나 더 추가하고 싶습니다.
간단히 말해서 lea 명령과 mov 명령은 명령의 src 피연산자를 둘러싸는 괄호와 함께 사용할 수 있습니다. 이들은 동봉 때 () 상기의 식 () 와 동일한 방식으로 계산되고; 그러나 두 명령어는 src 피연산자의 계산 된 값을 다른 방식으로 해석합니다.
lea 또는 mov와 함께 표현식을 사용하든 src 값은 다음과 같이 계산됩니다.
D (Rb, Ri, S) => (Reg [Rb] + S * Reg [Ri] + D)
그러나 mov 명령어와 함께 사용하면 위 식에서 생성 된 주소가 가리키는 값에 액세스하여 대상에 저장하려고합니다.
이와 달리, lea 명령어는 위의 식으로 실행될 때 생성 된 값을 대상에 그대로로드합니다.
아래 코드는 lea 파라미터와 mov 명령어를 동일한 파라미터로 실행합니다. 그러나 차이점을 포착하기 위해 mov 명령의 결과로 잘못된 주소에 액세스하여 발생하는 세그먼테이션 오류를 포착하는 사용자 수준 신호 처리기를 추가했습니다.
예제 코드
#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
);
}
실행 결과
Result of lea instruction: 14
inst at 0x4007b5 tries to access memory at 14, but failed
=d
컴파일러에게 결과가 EDX에 있음을 알리고를 저장하는 데 사용할 수 mov
있습니다. 또한 출력에서 초기 클로버 선언을 생략했습니다. 이것은 당신이 보여주고 자하는 것을 보여 주지만, 다른 상황에서 사용될 경우 깨지는 인라인 asm의 잘못된 예입니다. 그것은 스택 오버플로 답변에 대한 나쁜 것입니다.
%%
Extended asm에서 모든 레지스터 이름 을 쓰지 않으려면 입력 제한 조건을 사용하십시오. 처럼 asm("lea 4(%%ebx, %%eax, 8), %%edx" : "=d"(result_of_lea) : "a"(1), "b"(2));
. 컴파일러에서 레지스터를 초기화하면 클로버를 선언 할 필요가 없습니다. mov-immediate가 전체 레지스터를 덮어 쓰기 전에 xor-zeroing으로 문제를 지나치게 복잡하게 만듭니다.
mov 4(%ebx, %eax, 8), %edx
가 무효 라고 말 합니까? 어쨌든, 예를 들어, 컴파일러에게 64 비트 값을 가지고 있다고 알리기 mov
위해 작성 "a"(1ULL)
하는 것이 합리적 이므로 전체 레지스터를 채우려면 확장해야합니다. mov $1, %eax
컴파일러가 RAX = 0xff00000001
또는 무언가 라는 것을 알고있는 주변 코드의 이상한 상황이 없으면 EAX를 작성하면 RAX로 0 확장되므로 실제로는 여전히을 사용 합니다. 의 경우 lea
여전히 32 비트 피연산자 크기를 사용하고 있으므로 입력 레지스터의 스트레이 하이 비트는 32 비트 결과에 영향을 미치지 않습니다.
LEA : 단지 "산술"명령 ..
MOV는 피연산자간에 데이터를 전송하지만 lea는 계산 중입니다.
mov eax, offset GLOBALVAR
대신. LEA 를 사용할 수 는 있지만 주소 계산 프로세스를 거치기 때문에 코드 크기가 약간 크고 mov r32, imm32
포트 수가 적습니다 . 낮은 32 비트 외부의 PIC 및 / 또는 주소가 필요한 경우 RIP 기준 LEA의 경우 64 비트에서만 유용합니다. 32 비트 또는 16 비트 코드에서는 이점이 없습니다. LEA는 CPU가 어드레싱 모드를 디코딩 / 계산하는 능력을 노출시키는 산술 명령어입니다. lea reg, symbol
imul eax, edx, 1
계산되지 않는다고 말할 수 있습니다 : 그것은 단지 edx를 eax로 복사합니다. 그러나 실제로는 3주기 대기 시간으로 승수를 통해 데이터를 실행합니다. 또는 rorx eax, edx, 0
그냥 복사합니다 (0으로 회전).
곱셈 추가, 배타적 추가 또는 상태 플래그 0과 같은 모든 일반적인 "계산"명령어는 부호입니다. 복잡한 주소를 사용 AX xor:= mem[0x333 +BX + 8*CX]
하면 xor 연산에 따라 플래그가 설정됩니다.
이제 주소를 여러 번 사용할 수 있습니다. 이러한 주소를 레지스터에로드하는 것은 결코 상태 플래그를 설정하기위한 것이 아니며 운 좋게도 설정하지 않습니다. "로드 유효 주소"라는 문구는 프로그래머가이를 인식하도록합니다. 그것은 이상한 표현이 나오는 곳입니다.
일단 프로세서가 복잡한 주소를 사용하여 컨텐츠를 처리 할 수 있으면 다른 목적으로 계산할 수 있음이 분명합니다. 실제로 x <- 3*x+1
하나의 명령 으로 변환을 수행하는 데 사용할 수 있습니다 . 이것은 어셈블리 프로그래밍의 일반적인 규칙입니다 . 그러나 지침을 사용하여 보트를 흔들어주십시오.
중요한 것은 명령에 의해 구현 된 특정 변환이 유용한 지 여부입니다.
결론
MOV, X| T| AX'| R| BX|
과
LEA, AX'| [BX]
상태 플래그에는 영향을 미치지 않지만 AX 에는 동일한 영향을 미칩니다 . 이것은 ciasdis 표기법입니다.
call lbl
lbl: pop rax
의 가치를 얻는 방법으로 기술적으로 "작동하는"것과 같은 이유로 개인적으로 그 조언 을 전하지는 rip
않겠지 만 분기 예측은 매우 불행하게 만듭니다. 그러나 원하는 지침을 사용하십시오. 그러나 까다로운 일을하더라도 예상하지 못한 결과가 발생하더라도 놀라지 마십시오
누군가 이미 언급했다면 용서하십시오. 그러나 메모리 세분화가 여전히 관련되어있는 x86 시대에는 다음 두 지침에서 동일한 결과를 얻지 못할 수 있습니다.
LEA AX, DS:[0x1234]
과
LEA AX, CS:[0x1234]
seg:off
쌍 의 "오프셋"부분 일뿐 입니다. LEA는 세그먼트베이스의 영향을받지 않습니다. 이 두 가지 지침은 모두 비효율적 0x1234
으로 AX에 적용됩니다. x86은 불행히도 전체 선형 주소 (유효 + 세그먼트 기준)를 레지스터 또는 레지스터 쌍으로 쉽게 계산할 수있는 방법이 없습니다.