[assembly] MOV와 LEA의 차이점은 무엇입니까?

이 지침의 차이점이 무엇인지 알고 싶습니다.

MOV AX, [TABLE-ADDR]

LEA AX, [TABLE-ADDR]



답변

  • LEA 로드 유효 주소를 의미
  • MOV 로드 값을 의미

즉, LEA주소를 지정할 항목에 대한 포인터를로드하는 반면 MOV는 해당 주소의 실제 값을로드합니다.

LEA사소한 주소 계산을 수행하고 결과를 [나중에 사용하기 위해] 저장하도록하는 것이 목적입니다 .

LEA ax, [BP+SI+5] ; Compute address of value

MOV ax, [BP+SI+5] ; Load value at that address

관련된 상수가있는 경우 MOV(어셈블러의 상수 계산을 통해) 때로는 가장 간단한 사용 사례와 겹치는 것처럼 보일 수 있습니다 LEA. 여러 기본 주소 등으로 여러 부분으로 구성된 계산이있는 경우 유용합니다.


답변

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-immediate를 얻는 데 사용하십시오 .


답변

명령 MOV reg, addr은 주소 addr에 저장된 변수를 register reg로 읽는 것을 의미합니다. LEA reg, addr 명령어는 주소에 저장된 변수가 아닌 주소를 레지스터 reg로 읽는 것을 의미합니다.

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


답변

사용 된 어셈블러에 따라 다릅니다.

mov ax,table_addr

MASM에서는

mov ax,word ptr[table_addr]

따라서 table_addr오프셋이 아닌 에서 첫 번째 바이트를로드합니다 table_addr. 대신 사용해야합니다

mov ax,offset table_addr

또는

lea ax,table_addr

같은 방식으로 작동합니다.

leatable_addr로컬 변수 인 경우 버전도 잘 작동합니다.

some_procedure proc

local table_addr[64]:word

lea ax,table_addr


답변

이전 답변 중 어느 것도 내 혼란의 바닥에 도달하지 못했기 때문에 내 자신을 추가하고 싶습니다.

내가 누락 된 것은 lea작업이 괄호 사용을 처리하는 방식과 다르게 처리한다는 것입니다 mov.

C를 생각해보십시오 . long내가 호출 하는 배열이 있다고 가정 해 봅시다 array. 이제 식은 array[i]주소 array + i * sizeof(long)[1]의 메모리에서 값을로드하여 역 참조를 수행합니다 .

반면에, 표현을 고려하십시오 &array[i]. 여기에는 여전히 하위 표현식이 포함되어 array[i]있지만 역 참조는 수행되지 않습니다! 의 의미 array[i]가 변경되었습니다. 더 이상 지연을 수행하는 것이 아니라 대신 일종의 사양 으로 작동하여 &찾고있는 메모리 주소를 알려줍니다 . 원한다면 &, 역 참조를 “취소” 한다고 생각할 수도 있습니다.

두 가지 유스 케이스는 여러면에서 유사하기 때문에 구문을 공유 array[i]하지만 &구문의 해석 방법 에 대한 변경 유무 . 가 없으면 &역 참조이며 실제로 배열에서 읽습니다. 로는 &그렇지 않습니다. 값 array + i * sizeof(long)은 여전히 ​​계산되지만 역 참조되지는 않습니다.

상황은 매우 유사하다 movlea. 을 사용하면 mov에는 발생하지 않는 역 참조가 발생합니다 lea. 이것은 두 가지 모두에서 발생하는 괄호 사용에도 불구하고 있습니다. 예를 들어, movq (%r8), %r9leaq (%r8), %r9. 로 mov괄호는 “역 참조”를 의미합니다. 와 함께 lea하지 않습니다. 이 array[i]없는 경우 “역 참조”만 의미 하는 것과 비슷합니다 &.

예를 들면 다음과 같습니다.

코드를 고려하십시오

movq (%rdi, %rsi, 8), %rbp

이것은 메모리 위치의 값을 %rdi + %rsi * 8레지스터로 로드합니다 %rbp. 즉, 레지스터 %rdi의 값과 레지스터의 값을 가져옵니다 %rsi. 후자에 8을 곱한 다음 전자에 더하십시오. 이 위치에서 값을 찾아 레지스터에 배치하십시오 %rbp.

이 코드는 C 선에 대응하고 x = array[i];, array해진다 %rdii하게 %rsi하고 x해진다 %rbp. 이 8어레이에 포함 된 데이터 유형의 길이이다.

이제 다음을 사용하는 유사한 코드를 고려하십시오 lea.

leaq (%rdi, %rsi, 8), %rbp

의 사용이 movq역 참조 에 해당하는 것처럼, leaq여기서 의 사용은 역 참조 가 아님에 해당합니다 . 이 조립 라인은 C 라인에 해당합니다 x = &array[i];. 역 참조에서 단순히 위치 지정으로 &의 의미 를 변경 한다는 점을 상기하십시오 array[i]. 마찬가지로, 참조를 사용하면 역 참조에서 위치 지정으로 leaq의 의미 가 변경 (%rdi, %rsi, 8)됩니다.

이 코드 줄의 의미는 다음과 같습니다. 레지스터 %rdi의 값과 레지스터 의 값을 가져옵니다 %rsi. 후자에 8을 곱한 다음 전자에 더하십시오. 이 값을 레지스터에 넣습니다 %rbp. 메모리에서로드되는 것이 아니라 산술 연산 만 수행됩니다 [2].

주 내 설명 사이의 유일한 차이 있음 leaqmovq즉이 movq역 참조를 수행하고 leaq있지 않습니다. 사실, leaq설명 을 작성하기 위해 기본적으로의 설명을 복사하여 붙여 넣은 movq다음 “이 위치에서 값 찾기”를 제거했습니다.

요약하면 : movq대는 leaq그들과 같이 괄호를 사용하여 치료하기 때문에 까다 롭습니다 (%rsi)(%rdi, %rsi, 8)다르게. 에서 movq(그리고 다른 모든 명령을 제외하고는 lea있는 반면)이 괄호는 진짜 역 참조를 나타내는 leaq그렇지 않은 순수하게 편리한 구문입니다.


[1] array의 배열 인 long경우 식은 array[i]주소에서 값을로드 한다고합니다 array + i * sizeof(long). 이것은 사실이지만 해결해야 할 미묘함이 있습니다. C 코드를 작성하면

long x = array[5];

이것은 입력과 동일 하지 않습니다

long x = *(array + 5 * sizeof(long));

그것은 이전의 진술에 근거 해야하는 것처럼 보이지만 그렇지 않습니다.

진행중인 것은 C 포인터 추가에 트릭이 있다는 것입니다. ptype 값을 가리키는 포인터가 있다고 가정 해보십시오 T. 이 표현 p + i은 ” 더하기 바이트 에서의 위치”를 의미 하지 않습니다 . 대신, 표현은 실제로 ” 플러스 바이트 에서의 위치”를 의미합니다 .pip + i pi * sizeof(T)

이것의 편리함은 “다음 값”을 얻기 위해 p + 1대신에 작성해야한다는 것입니다 p + 1 * sizeof(T).

이것은 C 코드 long x = array[5];가 실제로

long x = *(array + 5)

C 자동으로 곱 때문 5으로 sizeof(long).

따라서이 StackOverflow 질문의 맥락에서 이것이 어떻게 관련이 있습니까? “주소 array + i * sizeof(long)” 라고 말할 때 ” “가 C 표현식으로 해석 된다는 의미 는 아닙니다array + i * sizeof(long) . 나는 sizeof(long)대답을보다 명확하게하기 위해 스스로 곱셈을 하고 있지만 그로 인해이 표현은 C로 읽혀서는 안된다는 것을 이해합니다. C 구문을 사용하는 일반적인 수학처럼.

[2] 참고 : 모든 lea작업은 산술 연산이므로 인수가 실제로 유효한 주소를 참조 할 필요는 없습니다. 이러한 이유로 종종 역 참조되지 않는 값에 대해 순수한 산술을 수행하는 데 사용됩니다. 예를 들어, cc-O2최적화를 번역

long f(long x) {
  return x * 5;
}

다음과 같이 (관련없는 줄이 제거되었습니다) :

f:
  leaq (%rdi, %rdi, 4), %rax  # set %rax to %rdi + %rdi * 4
  ret


답변

기본적으로 … “계산 후 REG로 이동 … …”다른 목적으로도 좋은 것 같습니다 🙂

값이 포인터라는 것을 잊어 버린 경우 코드 최적화 / 최소화에 사용할 수 있습니다.

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