프로그래밍 일반 2014. 6. 24. 17:11

디스어셈블리

컴파일러 최적화 기술은 나날이 발전하고 있고 예전에 공부했던 최적화 내용은 지금과 다를 수도 있다.


최근 서버 코드를 리팩토링하면서 당연히 문제가 있을거라 생각했던 코드들[각주:1]도 아주 훌륭하게 컴파일러는 처리를 해주고 있었다.


아... 내가 알고 있는 지식이 지금도 유효한가 묘한 경험.. 뭐 어셈을 알면 코드를 검증하기도 쉽고 디버깅에도 도움이되고 무엇보다 


프로그램을 이해하는데 도움이 되니 기회가 될때마다 학습을해두는게 좋다.


VS2008 에서 Disassembly 단축키 Alt + 8


어셈코드를 읽기위해 숙지하고 있어야할 정보들..



- 범용 레지스터 (32비트)

EAX : 확장 누산기, 대부분 입출력과 산술, 논리 연산 수행


EAX 32비트, AX 16비트, AH 상위 영역(SUB 16bit), AL 하위 영역  -> 범용 레지스터 공통적으로 적용가능


EBX : 주소 지정을 확장하기 위해 인덱스로 사용, 특정 주소 지정을 위한 베이스 레지스터로서 DI, SI와 결합될 수 있다.

         산술 연산에도 사용한다.

ECX : 반복 수행할 때 횟수를 지정하는데 사용, 루프나 시프트 등에서 사용

EDX : 64비트 값들의 상위 32비트를 담는 용도로 사용

ESP : 스택포인터, 스택의 꼭대기를 가리킨다(offset, x86은 스택이 아래로 자라므로 실제로는 바닥이다).

   스택에 데이터가 push 되거나 pop 될 때마다 증감된다.

EBP : 스택프레임, 프로시저나 함수에 대한 스택프레임을 담는 용도로 사용된다. 스택의 데이터에 접근하기 위해 사용

ESI : 메모리 이동이나 비교시에 원본주소를 담는 용도로 사용

EDI : 메모리 이동이나 비교시에 대상의 주소를 담는 용도로 사용




- EIP 레지스터

EIP : 인스트럭션[각주:2] 포인트, 다음에 실행할 코드의 주소를 가지고 있다.



- 세그먼트 레지스터

cs : 코드세그먼트, 코드영역의 세그먼트를 지닌다. 32비트 어드레싱에서는 별의미가 없다.

ds : 데이터세그먼트, 데이터영역의 세그먼트를 지닌다. 역시 32비트 어드레싱에서는 별의미가 없다.

ss : 스택 세그먼트, 

es : extra segment, 데이터 전송을 받은 수신측에서의 시작 부분을 가리키고 있다.

스트링 명령에 보조적으로 사용되기도 한다.

fs, gs - es 처럼 데이터를 가리키는 역활을 하지만 보조적으로 쓰이는 역활



- 명령어

LEA - 메모리 주소값 (세그먼트 + 오프셋) 을 추출

CMP - 두 값을 비교 (깊은 의미 - 두 값의 차이 계산, 둘다 같은 값이면 차가 0 이므로 ZF가 1로 셋팅)

JMP : 비교 점프

above 크다, below 작다, greater (부호 포함 크다), less 부호 포함 작다

JNE - Jump not equal

JE - (Jump if equal) : ZF = 1

JA - Jump if (unsigned) above) : CF = 0 and ZF = 0

      앞에서 수행한 비교문 (cmp) 에서 앞에 것이 클때만 점프

JB - (Jump if below) : CF = 1 앞에서 수행한 비교문에서 앞에 것이 작을 때만 점프

JG - (Jump if greater) : ZF = 0 and SF = 0 , 앞의 것이 크거나 같다면 점프한다.

JL - (Jump if less)

LOOP - 반복

LOOPE - 같다면 반복

LOOPNE - 같지 않다면 반복

CALL - 서브루틴으로 분기

RET - 원래의 루틴으로 복귀

IRET - 인터럽트 복귀

JE/JZ - 결과가 0이면 분기

JNE/JNZ - 결과가 0이 아니면 분기

JL/JNGE  - 결과가 작으면 분기

JO - 오버플로우가 발생하면 분기

JNLE/JG  - 결과가 크면 분기


movzx - (move zero extend : 무브 제로 확장) 

movsx - (Move sign extend : 무브 부호 확장)


mov -  


int iValue = 10;

00F724FE  mov         dword ptr [iValue],0Ah    // 의미 iValue 라는 dword형 변수에 16진수 0A (10진수 10) 를 넣는다. 



- 스트링 명령어

LODS - 메모리로부터 레지스터에 데이터를 로드, ESI(포인터)의 내용을 EAX로 로드

STOP - 메모리에 데이터를 저장, EAX의 값을 EDI가 가리키는 곳에 저장

MOVS - ESI가 가리키는 곳의 값을 EDI가 가리키는 곳에 복사

CMPS - 메모리와 메모리를 비교, ESI와 EDI의 내용을 비교한 결과에 따라 플래그 설정

SCAS - 레지스터와 메모리의 내용을 비교, EDI

REP - REP 뒤에 오는 스트링 명령을 ECX가 0이 될 때까지 반복

   REP 명령과 조합하여 사용하면 ECX 레지스터가 지정하는 횟수만큼 반복하여 데이터를 전송한다.

   이때 주소는 자동으로 갱신되지 때문에 한 명령으로 연속된 여러 데이터를 전송할 수 있다.

REPE, PEPNE - 일치하는 데이터가 얻어질 때까지, 일치하지 않는 데이터가 얻어질 때까지 메모리상의 데이터를 탐색할 수 있다


우선 이정도만 알아도 왠만한 코드는 볼 수 있다..


계속 업데이트 예정..

  1. switch case 문이 점프테이블을 만드는 룰 위반 [본문으로]
  2. CPU를 동작 시키는 명령어. 인스트럭션 집한은 인스트럭션 셋이라한다. [본문으로]