Busan IT/Assembly2015. 10. 15. 16:46

[smart.c]
#include <stdio.h>

#define CMD_SIZE 20

typedef struct
{
  unsigned int efl;
  unsigned int eip;
  unsigned int edi;
  unsigned int esi;
  unsigned int ebp;
  unsigned int esp;
  unsigned int ebx;
  unsigned int edx;  
  unsigned int ecx;  
  unsigned int eax;
  
}context;

typedef struct
{
  char * cpCmd;
  void (*fp)();  
}comm;

static context stOld_state;
extern void stst(context *);
extern void ldst(context *);
void print_r();
void print_help();
comm stCmd_Map[] ={  //메세지 맵 기법
         {
        "R", print_r
         },
      {
        "H", print_help
      },      
         {
        00
         }        
      };

int main(void)
{
  char cInput[CMD_SIZE];
  comm * stpCmd;
  int iRet;  

  stst(&stOld_state);  
  printf("Moniter Program Start\n");
  while(1)
  {
    putchar('>');    
    iRet = read(0, cInput, CMD_SIZE);
    if(iRet < 2)
    {
      continue;  
    }  
      
    cInput[iRet-1= 0;
    
    stpCmd = stCmd_Map;
    while(0 != (stpCmd->fp))
    {
      if(0 == strcmp(strupr(cInput), stpCmd->cpCmd))
      {
        break;
      }      
      ++stpCmd;
    }
    if(0!= (stpCmd->fp))
    {
      ((stpCmd->fp)());      
      
    }
    else
    {
      print_help();
    }    
  }
  return 0;
}

void print_r()
{
  printf("main    : %08X\n", main);
  printf("stOld_state: %08X\n"&stOld_state);
  printf("EAX = %08X  EBX = %08X\nECX = %08X  EDX = %08X\nESI = %08X  EDI = %08X\nEBP = %08X  ESP = %08X\nEIP = %08X  EFL = %08X\n\n",stOld_state.eax, stOld_state.ebx, stOld_state.ecx, stOld_state.edx, stOld_state.esi, stOld_state.edi, stOld_state.ebp, stOld_state.esp, stOld_state.eip, stOld_state.efl);

}

void print_help()
{
  printf("Memory Debugging Prompt\n\n");
  printf("R: Print Register Info.\n");
  printf("H: Print Command List.\n");

    
}

[main.asm]

.386

.MODEL FLAT

PUBLIC _stst
PUBLIC _ldst    ; '_stst''_ldst'함수 외부 접근 허용 코드

.code

_start:  

_stst   PROC   NEAR32  ;store status

    ; - entry code -
    push  ebp    
    mov   ebp, esp

    pushfd
    mov esp, [ebp+8]  ;esp obj로 이동
    add esp, 40    ;esp obj 가장 아래로 이동

    pushad      ;eip와 efl을 제외한 모든 레지스터 구조체에 삽입
    push [ebp+4] ; eip삽입
    push [ebp-4] ; eflags삽입
    add esp, 20  ; 구조체의 esp자리로 내려온다.

    mov eax, ebp ; main의 esp를 구조체의 넣기 위해 레지스터 eax를 사용한다.
    add eax, 8   ; eax를 main의 esp가 있는 자리로 옮겨준다.
     ;12가 아닌 8인 이유는 esp는 마지막 변수를 가리키고 있기 때문이다.
    mov [esp], eax ; 구조체 esp에 main의 esp를 넣어준다.
    push [ebp]     ; 구조체 ebp자리에 main의 ebp를 넣어준다.

    
    ;mov eax, [esp+20] eax에는 return값이 들어감으로 복구시킬 필요가 없다.


    ; - exit code -
    mov  esp, ebp
    pop  ebp
    ret ;pop eip
    
    ;메인 함수에서의 복구
    ;add esp, 4 ;함수의 인자 자리를(&obj) 복구 시키기 위해 esp 사용한 인자의 크기만큼 옮긴다.

  
  _stst ENDP

  _ldst   PROC   NEAR32  ;
      
    ;mov esp, [esp+4]  ;esp를 구조체로 이동
    ;popfd    ;구조체 efl값을 레지스터 efl로 이동
    ;pop eax    ;eax값에 구조체 eip값을 이동
    ;mov ebx, esp  ;현재 esp값(구조체에 edi를 가리킨다)을 백업
    ;mov esp, [esp+12]  ;구조체 esp값을 esp에 저장한다.
    ;push eax    ;구조체eip값을 구조체 esp에 저장
    ;mov esp, ebx  ;esp를 구조체에 edi를 가리키는 값으로 이동시킨다.
    ;popad    ;스택에 있는 내용을 레지스터에 채운다.
    ;mov esp, [esp-20]  ;esp를 구조체 esp가 가리키는 곳으로 이동시킨다.
    ;sub esp, 4    ;esp - 4

    mov esp, [esp+4]
    popfd
    pop eax
    mov ebx, [esp+12]
    mov [ebx-4], eax
    popad
    mov esp, [esp-20]
    sub esp, 4


    ret ;pop eip

  _ldst ENDP


반응형
Posted by newind2000
Busan IT/Assembly2015. 10. 15. 09:13

.386

.MODEL FLAT

PUBLIC _stst
PUBLIC _ldst    ; '_stst''_ldst'함수 외부 접근 허용 코드

.code

_start:  

_stst   PROC   NEAR32  ;store status

    ; - entry code -
    push  ebp    
    mov   ebp, esp

    pushfd
    mov esp, [ebp+8]  ;esp obj로 이동
    add esp, 40    ;esp obj 가장 아래로 이동

    pushad      ;eip와 efl을 제외한 모든 레지스터 구조체에 삽입
    push [ebp+4] ; eip삽입
    push [ebp-4] ; eflags삽입
    add esp, 20  ; 구조체의 esp자리로 내려온다.

    mov eax, ebp ; main의 esp를 구조체의 넣기 위해 레지스터 eax를 사용한다.
    add eax, 8   ; eax를 main의 esp가 있는 자리로 옮겨준다.
     ;12가 아닌 8인 이유는 esp는 마지막 변수를 가리키고 있기 때문이다.
    mov [esp], eax ; 구조체 esp에 main의 esp를 넣어준다.
    push [ebp]     ; 구조체 ebp자리에 main의 ebp를 넣어준다.

    
    ;mov eax, [esp+20] eax에는 return값이 들어감으로 복구시킬 필요가 없다.


    ; - exit code -
    mov  esp, ebp
    pop  ebp
    ret ;pop eip
    
    ;메인 함수에서의 복구
    ;add esp, 4 ;함수의 인자 자리를(&obj) 복구 시키기 위해 esp 사용한 인자의 크기만큼 옮긴다.

  
  _stst ENDP

  _ldst   PROC   NEAR32  ;
      
    ;mov esp, [esp+4]  ;esp를 구조체로 이동
    ;popfd    ;구조체 efl값을 레지스터 efl로 이동
    ;pop eax    ;eax값에 구조체 eip값을 이동
    ;mov ebx, esp  ;현재 esp값(구조체에 edi를 가리킨다)을 백업
    ;mov esp, [esp+12]  ;구조체 esp값을 esp에 저장한다.
    ;push eax    ;구조체eip값을 구조체 esp에 저장
    ;mov esp, ebx  ;esp를 구조체에 edi를 가리키는 값으로 이동시킨다.
    ;popad    ;스택에 있는 내용을 레지스터에 채운다.
    ;mov esp, [esp-20]  ;esp를 구조체 esp가 가리키는 곳으로 이동시킨다.
    ;sub esp, 4    ;esp - 4

    mov esp, [esp+4]
    popfd
    pop eax
    mov ebx, [esp+12]
    mov [ebx-4], eax
    popad
    mov esp, [esp-20]
    sub esp, 4


    ret ;pop eip

  _ldst ENDP


마지막 연산을 통해서 efl값이 변동된다. efl값이 변동하지 않도록 다시 코딩을 해보자.

반응형
Posted by newind2000
Busan IT/Assembly2015. 10. 13. 09:07

==================================Outline====================================

EFL값 보존 후 레지스터 출력

테스크 스위칭을 위한 레지스터 값 보존

----------------------------------------------------------------------------


EFL값 보존 후 레지스터 출력

 

가장 먼저 ‘pushfd’명령어를 사용하여 eflags를 보존시킨 후 obj구조체에 EFL을 삽입하여 보자.

 

어셈블리코드는 한 줄이라도 짧게 코딩해야 한다.

 

12줄이 사용된다.


.386

.MODEL FLAT

PUBLIC _smart    ; '_smart'함수 외부 접근 허용 코드

.code

_start:
  _smart   PROC   NEAR32

    ; - entry code -
    push  ebp    
    mov   ebp, esp

    pushfd
    mov esp, [ebp+8]  ;esp obj로 이동
    add esp, 40    ;esp obj 가장 아래로 이동

    pushad      ;eip와 efl을 제외한 모든 레지스터 구조체에 삽입
    push [ebp-4] ; eflags삽입
    push [ebp+4] ; eip삽입
    add esp, 20  ; 구조체의 esp자리로 내려온다.

    mov eax, ebp ; main의 esp를 구조체의 넣기 위해 레지스터 eax를 사용한다.
    add eax, 8   ; eax를 main의 esp가 있는 자리로 옮겨준다.
     ;12가 아닌 8인 이유는 esp는 마지막 변수를 가리키고 있기 때문이다.
    mov [esp], eax ; 구조체 esp에 main의 esp를 넣어준다.
    push [ebp]     ; 구조체 ebp자리에 main의 ebp를 넣어준다.

    
    ;mov eax, [esp+20] eax에는 return값이 들어감으로 복구시킬 필요가 없다.


    ; - exit code -
    mov  esp, ebp
    pop  ebp
    ret ;pop eip
    
    ;메인 함수에서의 복구
    ;add esp, 4 ;함수의 인자 자리를(&obj) 복구 시키기 위해 esp 사용한 인자의 크기만큼 옮긴다.

  
  _smart ENDP


 

테스크 스위칭을 위한 레지스터 값 보존 

 

테스크 스위칭(Task Switching): 프로그램간의 변경을 일컫는다.

 

CPU가 하나일 경우 여러 가지 프로그램을 동작시키기 위해서는 이전 프로그램의 CPU정보를 저장해야 한다. 이 때 CPU의 정보를 가능한한 간단하게 저장시켜야 한다.


레지스터를 출력하는 함수를 따로 만들어 보자.


'_smart'함수를 '_stst'함수, store state로 바꾸고 '_ldst' 함수를 만들어 entry code와 exit code를 적어 놓는다. 또한 레지스터가 한 줄에 두줄 씩 출력되도록 코딩한다.


.386

.MODEL FLAT

PUBLIC _stst
PUBLIC _ldst    ; '_stst''_ldst'함수 외부 접근 허용 코드

.code

_start:  

_stst   PROC   NEAR32  ;store status

    ; - entry code -
    push  ebp    
    mov   ebp, esp

    pushfd
    mov esp, [ebp+8]  ;esp obj로 이동
    add esp, 40    ;esp obj 가장 아래로 이동

    pushad      ;eip와 efl을 제외한 모든 레지스터 구조체에 삽입
    push [ebp-4] ; eflags삽입
    push [ebp+4] ; eip삽입
    add esp, 20  ; 구조체의 esp자리로 내려온다.

    mov eax, ebp ; main의 esp를 구조체의 넣기 위해 레지스터 eax를 사용한다.
    add eax, 8   ; eax를 main의 esp가 있는 자리로 옮겨준다.
     ;12가 아닌 8인 이유는 esp는 마지막 변수를 가리키고 있기 때문이다.
    mov [esp], eax ; 구조체 esp에 main의 esp를 넣어준다.
    push [ebp]     ; 구조체 ebp자리에 main의 ebp를 넣어준다.

    
    ;mov eax, [esp+20] eax에는 return값이 들어감으로 복구시킬 필요가 없다.


    ; - exit code -
    mov  esp, ebp
    pop  ebp
    ret ;pop eip
    
    ;메인 함수에서의 복구
    ;add esp, 4 ;함수의 인자 자리를(&obj) 복구 시키기 위해 esp 사용한 인자의 크기만큼 옮긴다.

  
  _stst ENDP

  _ldst   PROC   NEAR32  ;

    ; - entry code -
    push  ebp    
    mov   ebp, esp

    ; - exit code -
    mov  esp, ebp
    pop  ebp
    ret ;pop eip

  _ldst ENDP




반응형
Posted by newind2000
Busan IT/Assembly2015. 10. 12. 08:56

==================================Outline====================================

pushad를 활용한 레지스터 출력

----------------------------------------------------------------------------

 

pushad를 사용하여 레지스터들의 값을 출력해보자.

 

 

 

; Line 21

push ebp

mov ebp, esp

sub esp, 44 ; 0000002cH

mov eax, DWORD PTR ___security_cookie

xor eax, ebp

mov DWORD PTR __$ArrayPad$[ebp], eax

 

ESPEBP의 차는 44이다.

 

EFL 값은 216이다.

 


코드를 최적화 시켜보자.

 

/*** 코드 ***/

main.asm


.386

.MODEL FLAT

PUBLIC _smart    ; '_smart'함수 외부 접근 허용 코드

.code

_start:
  _smart   PROC   NEAR32

    ; - entry code -
    push  ebp    
    mov   ebp, esp

    mov esp, [ebp+8]  ;esp obj로 이동
    add esp, 40    ;esp obj 가장 아래로 이동
    pushad      ;eip와 efl을 제외한 모든 레지스터 구조체에 삽입

    push [ebp+4]    ;eip 구조체에 삽입
    pushfd      ;efl 구조체에 삽입


    mov eax, ebp        
    add eax, 12    

    add esp, 20
    mov [esp], eax

    push [ebp]    ;main의 ebp를 삽입
    

    ; - exit code -
    mov  esp, ebp
    pop  ebp
    ret  
  
  _smart ENDP

 

반응형
Posted by newind2000
Busan IT/Assembly2015. 10. 6. 16:35

==================================Outline====================================

Procedure 필수코드 

C의 obj파일과 asm의 obj파일 합치기

----------------------------------------------------------------------------

Procedure 필수코드 


교재 p/213

 

Using parameter values passed on stack 예제

함수의 인자를 삽입한 코드를 다시 보자.

 

push 300 ;함수에 넣는 인자, cdecl형식임으로 우에서 좌로 스택에 담긴다.

push 200

push 100

 

call _smart ;함수의 호출

 

push ebp ;스택에 main의 ‘ebp'주소 삽입

 

/*** 변수가 있을 때만 적용되는 코드 ***/

mov ebp, esp ;ebp == esp

sub esp, 12 ;변수선언, 4*3byte 공간 확보

 

//C언어의 함수가 Assembly로 옮겨지면 되면 ‘_’를 붙혀 이를 구분한다.

 

스택은 끝번지에서 시작번지로 영역이 확장되기 때문에 지역변수를 만들 때 먼저 만들어진 변수가 끝번지에 가까운 곳에 위치해 있다.

 

entry codeexit code의 함수가 종료될 때 스택을 복구하기 위해서이다.

 

함수를 호출하면 최소 8byte의 스택을 사용하게 된다. 이를 오버헤드(overhead)라고 한다.

 

//overhead간접비라는 뜻을 가진다. 즉 함수를 사용하기 위한 부대비용이다.

 

//아래는 함수의 overhead code

//push esp

//mov ebp, esp

 

때문에 짧은 코드를 함수로 만드는 것은 프로그램의 효율성을 떨어뜨린다.

 

mov esp, ebp

pop esp

ret 0

 

 

_cdecl은 호출한 함수에서 스택을 복구 시키기 때문에 아래의 코드가 추가된다.

 

add esp, '(양수)빠져나온 함수에서 사용한 스택의 크기

 

이에 반해 _stdcall'ret'을 사용하여 호출된 함수에서 스택을 복구 한다.

 

ret '스택함수 크기

 

 

enter 명령어

enter localBytes, nestingLevel

 

[해석]

push ebp

mov ebp, esp

sub esp, localBytes

 

INVOKE ExitProcess, 0

 

[해석]

push +00000000h

call ExitProcess


C의 obj파일과 asm의 obj파일 합치기 


C에서 작성한 프로그램과 어셈블리에서 작성한 프로그램을 합치는 작업을 해보겠다.

 

asm 파일에서 함수의 기본형

C에서 return 값은 어셈블리의 레지스터 EAX에 들어간다.

 

어셈블리 파일과 C파일을 합쳐서 프로그램을 만들어보자.

[main.asm]

.386

.MODEL FLAT

PUBLIC _smart    ; '_smart'함수 외부 접근 허용 코드

.code
  ; ***함수 기본형***
  _smart   PROC   NEAR32

    ; - entry code -
    push  ebp    
    mov   ebp, esp
    
    mov eax, 100

    ; - exit code -
    mov  esp, ebp
    pop  ebp
    ret  

  

  _smart ENDP




END


[smart.c]

#include <stdio.h>

int smart(void);



int main(void)
{
  int A = smart();
  printf("A의 값은 %d입니다.\n", A);  

  return 0;
}


반응형
Posted by newind2000
Busan IT/Assembly2015. 10. 5. 17:40

==================================Outline====================================

함수의 호출과 작동 원리 

----------------------------------------------------------------------------

'Initialize'라는 함수를 만들 수 디버깅 모드를 활용하여 각 레지스터들의 변화를 살펴보자.

우선 살펴보아야 할 메모리의 주소 값들을 보존시켜둔다.

 

EIP = 0040103E

ESP = 0012FF8C

ESP - 10h = 0012FF7C(스택 레지스터의 변화를 알아보기 위한 설정이다)

Initialize = 00401010

 

함수 호출

 

EIP는 명령어를 가리키는 레지스터이다. 00401043h 주소로 이동하면 ‘Initialize’의 주소로 이동하게 된다.

 

'call Initialize'를 해석 아래와 같다.

 

push ‘return address'(eip)

jmp Initialize

 

 

ret은 개념상 아래와 같다.

 

pop eip

 

eip에 간접적으로 값을 넣을 수 있는 방법은 두 가지인데 ‘call' 혹은 ’ret'명령어를 사용하는 것이다.

 

//cracking - 조건문을 조작하여 eip를 원하는 위치로 점프 시킨다.

 

return문 다음에 숫자를 적을 수도 있다. 이 경우는 나중에 배운다.

 

 



 

‘PUBLIC’ 명령어를 사용하면 다른 파일에서 접근이 가능해진다.

'PUBLIC'을 사용하지 않으면 기본적으로 외부에서 접근이 불가능하다.

 

‘extern’ 다른 파일에서 만들어진 함수를 호출하는 기능을 한다.

 

'NEAR32'4giga byte내에 코드가 존재한다는 뜻이다.

 

 

스택을 사용하는 변수들(지역변수들)

 

//6.3까지 배우고 나서부터는 C언어와 혼용하여 어셈블리를 배운다.

 

 

C에서는 함수를 사용할 때 인자를 입력하여 그 값을 달리하는 것이 가능하였다. CPU레지스터에는 용량의 한계가 있기 때문에 stack을 활용하면 된다. ARM core를 사용할 때 함수의 인자 4개 이상 만들게 되면 메모리에 값을 넣어야 하기 때문에 속도가 느려진다.

 

_stdcall: 함수의 인자를 좌측에서 우측으로 스택에 쌓는다.

_cdecl: 함수의 인자를 우측에서 좌측으로 쌓는다.(기본)

 

//주소보안 옵션 해제 - /DYNAMICBASE:NO

//asm파일 생성 옵션 - /Fa

//makfile에서 ‘@’은 명령어를 화면 창에 표시하지 않는 것이다.

push 300 ; 0000012cH

push 200 ; 000000c8H

push 100 ; 00000064H

call _smart

add esp, 12 ; 0000000cH

 

300, 200, 100순서임으로 _cdecl 형식임을 알 수 있다.

 

함수의 호출이 끝나면 stack은 다시 원래의 자리로 돌아와야 한다. 함수 내에 있던 지역변수는 함수가 종료됨으로써 사라지기 때문이다.

 

_cdecl call에서는 함수를 호출한 함수에서 스택의 값을 되돌려주는 것이다. 반면에 _stdcall은 호출된 함수 자체에서 사용한 변수를 스택에서 삭제한다.

 

aseeembly에서는 'ret'문을 사용하지 않으면 함수가 종료되지 않는다. C언어에서도 return을 삽입하는 습관을 들이자.




//소스


<main.c>

#include <stdio.h>

void smart(int a, int b, int c)
{
  int d=100;
  int e=200;
  int f=300;

  return;
}

int main(void)
{
  
  smart(100200300);
  return 0;
}

<main.asm>

; Listing generated by Microsoft (R) Optimizing Compiler Version 18.00.31101.0 

  TITLE  D:\윤재희\실습\Assembly\20151005\main.c
  .686P
  .XMM
  include listing.inc
  .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _smart
PUBLIC  _main
; Function compile flags: /Odtp
_TEXT  SEGMENT
_main  PROC
; File d:\윤재희\실습\assembly\20151005\main.c
; Line 13
  push  ebp
  mov  ebp, esp
; Line 15
  push  300          ; 0000012cH
  push  200          ; 000000c8H
  push  100          ; 00000064H
  call  _smart
  add  esp, 12          ; 0000000cH
; Line 16
  xor  eax, eax
; Line 17
  pop  ebp
  ret  0
_main  ENDP
_TEXT  ENDS
; Function compile flags: /Odtp
_TEXT  SEGMENT
_f$ = -12            ; size = 4
_e$ = -8            ; size = 4
_d$ = -4            ; size = 4
_a$ = 8              ; size = 4
_b$ = 12            ; size = 4
_c$ = 16            ; size = 4
_smart  PROC
; File d:\윤재희\실습\assembly\20151005\main.c
; Line 4
  push  ebp
  mov  ebp, esp
  sub  esp, 12          ; 0000000cH
; Line 5
  mov  DWORD PTR _d$[ebp], 100      ; 00000064H
; Line 6
  mov  DWORD PTR _e$[ebp], 200      ; 000000c8H
; Line 7
  mov  DWORD PTR _f$[ebp], 300      ; 0000012cH
; Line 10
  mov  esp, ebp
  pop  ebp
  ret  0
_smart  ENDP
_TEXT  ENDS
END

<go.bat>

@echo off

@cls 
  cl /Fa %1.c /DYNAMICBASE:no

 


 

 

 

반응형

'Busan IT > Assembly' 카테고리의 다른 글

pushad를 활용한 레지스터 출력  (0) 2015.10.12
Procedure 필수코드, C의 obj파일과 asm의 obj파일 합치기  (0) 2015.10.06
pop, pushad 명령어  (0) 2015.10.02
확장/반복문, Procedures  (0) 2015.10.01
조건문의 사용  (4) 2015.09.30
Posted by newind2000
Busan IT/Assembly2015. 10. 2. 17:46

==================================Outline====================================

pop

pushad

----------------------------------------------------------------------------


pop

pop에 대해 알아보자.

 

pop명령어의 작업순서는,

 

1. 메모리에서 값 추출

2. 주소 값을 증가

 

리틀 엔디안을 빅 엔디안으로 변환하여 지정된 레지스터에 저장한다.

 

 

//처리에 메모리가 개입하게 되면 사이클이 증가한다.

 

 

pushad

 

모든 일반 레지스터를 pushpop을 할수 있는 명령어이다.

 

 


 

 

 

 

popad의 기능이 제대로 작동하는지 메모리에 값을 변경한 후 값을 확인해보자.

 

 

 

eflageip레지스터는 사용자가 직접적으로 조작할 수 없는 레지스터이다. 이것을 간접접근이 가능하다가 일컫는다.

 

eflag의 값을 조작하기 위해서는 pushpop을 사용해야 한다.

eip는 간접접근 조차도 사용하지 못하게 보호해 놓았다.

 

 

프로시져의 본문, 요청과 반환

 

 

함수 호출은 'call' 명령어와 주소를 사용함으로써 해당 주소에 있는 프로시져를 수행하게 된다. 하지만 함수의 주소를 알기 위해서는 메모리를 살펴보아야 하기 때문에 함수의 주소 값의 라벨인 함수의 이름을 입력한다.

 

eip는 다음에 실행될 코드의 메모리 주소를 가리킨다.

 

//esp : 0012ff8c

 

//00 40 10 43

 

_start의 주소: 0x0040103E

Initialize의 주소: 0x00401010

call 이전의 esp : 0012ff8c

call 이전의 eip : 0040103e

 

_start : e8 FF FF FF CD

 

call 명령어는 opCode8e이다. call 명령어는 1bytemnemonic4byte의 주소 총 5byte이다.

 

initialize라는 함수를 호출하는 코드를 살펴보자.

 

e8 FF FF FF CD 라는 코드를 해석해보면, 현재 코드가 끝난 값으로부터 -51바이트가 된 곳에 있는 코드를 실행하라는 내용이다.




반응형
Posted by newind2000
Busan IT/Assembly2015. 10. 1. 17:41

==================================Outline====================================

확장, 반복문

- ECX 점검 명령어 jecxz

- 배열

- 주소 값 복사 명령어 lea

- Pipe의 개념 

Procedures

- 80X86 Stack

----------------------------------------------------------------------------

 

ECX 점검 명령어 jecxz

 

교재 p/175

 

loop문에서 ECX0일 경우 -1 연산이 적용되면 값이 FFFFFFFF되어 버린다.(loop문이 아주 오래 동안 실행된다.)

 

je endFor

 

때문에 ECX0인지 확인을 해주어야 한다. 이때 사용 되는 명령어가 jecxz이다.

 

컴파일러는 프로그래머가 작성한 코드를 효율적으로 기계어로 변환해준다. 현재의 컴파일러는 성능이 향상 되어서 어셈블러 지식이 애매한 프로그래머보다는 최적화된 코드를 제공해준다.

 

C는 컴파일을 거치게 되면 assembly language가 나오게 된다. C를 사용함으로써 기계어와 대응하는 어셈블리어가 나오기 때문에 C언어는 40년째 사용되고 있다.

 

배열

 

교재 p/180, 

 

배열은 프로그래밍에 많이 사용된다. 배열 사용을 지원해주는 명령어에 대해 알아보자.

 

배열 복사를 위한 레지스터

 

ESI(Extended Source Index)

EDS(Extended Dest. Index)

 

주소 값 복사 명령어 lea

 

lea 명령어는 주소 값을 레지스터에 담는 명령어이다.

 

ex) lea ebx, nbrArray

 

 

mov [ebx], eax ;register indirect, 포인터 개념

; &ebx = eax;

 

C에서는 변수의 주소를 1 증가 시키면 변수의 크기만큼 증가하게 되지만 어셈블리에서는 주소는 전부 1byte로 취급하기 때문에 이동시키고 싶은 크기만큼 값을 더해주어야 한다.

 

 

lealoop를 배울 수 있는 예제 교제 p/182 [Program using array]

; p/182 program using array

.386
.MODEL FLAT

INCLUDE io.h            ; header file for input/output


ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD

cr   EQU 0dh  ; carriage return
Lf   EQU 0ah  ; linefeed
maxNbrs  EQU 100  ; size of number array

.STACK 4096    ; reserver 4096-byte stack


.DATA 

directions   BYTE  cr, Lf, "You may enter up to 100 numbers"
    BYTE  " one at a time. ", cr, Lf
    BYTE  "Use any negative number to terminate"
    BYTE  "input.", cr, Lf, Lf
    BYTE  "This Program will then report the average and" 
    BYTE  "list", cr, Lf
    BYTE  "those numbers which are above the"
    BYTE  "average.", cr, Lf, Lf, Lf, 0
Prompt    BYTE  "Number?  ",0
number    BYTE  20 DUP (?)
nbrArray  DWORD  maxNbrs DUP (?)
nbrElts    DWORD  ?
avgLabel  BYTE  cr, Lf, Lf, "The average is"
outValue  BYTE  11 DUP(?), cr, Lf, 0
aboveLabel  BYTE  cr, Lf, "Above Average:", cr,Lf,Lf,0


.CODE    

_start :

; input numbers into array
    
  output   directions
  mov  nbrElts, 0
  lea  ebx, nbrArray
  
whilePos:  output  prompt
    input  number, 20
    atod  number
    jng  endWhile
    mov  [ebx], eax
    inc  nbrElts
    add   ebx, 4
    jmp   whilePos
endWhile:

    mov  eax, 0
    lea   ebx, nbrArray
    mov  ecx, nbrElts

    jecxz  quit

forCount1:  add  eax, [ebx]
    add  ebx, 4
    loop  forCount1

    cdq
    idiv  nbrElts
    dtoa  outValue, eax
    output   avgLabel
    output  aboveLabel
    
    lea  ebx, nbrArray
    mov  ecx, nbrElts

forCount2:  cmp  [ebx], eax
    jng  endIfBig
    dtoa  outValue, [ebx]

    output  outValue

endIfBig:  
    add  ebx, 4
    loop  forCount2

quit:    INVOKE ExitProcess, 0  ; exit with return code 0

PUBLIC _start    ; make entry point public
END      ; end of source code



  


** lea 명령어는 활용도가 높음으로 잘 익혀두는 것이 좋다.

 

Pipe의 개념

 

교재 p/189,

 

 

CPU의 기본 운영 사이클은 다음과 같다.

 

1. 메모리에서 명령어를 가져온다.(fetch)

2. 명령어를 해석한다.(decode)

3. 명령어를 실행한다.(execute)

 

 

각 연산자의 대한 클럭 사이클을 표에서 여러 번 보았다. 이 때의 한 사이클은 CPU1clock을 뜻한다.

 

CPU의 효율을 생각한다면 conditional jump는 좋지 않다. 때문에 조건문을 최소화 하는 것이 pipelining을 최적화하는 방법이다.

 

 

 

chapter에서는 if, 다양한 반복문과 배열에 대해서 배웠다. jmp명령어는 무조건 이동(c에서 goto문과 같은 역할), 조건이동은 플래그의 상태와 operand를 비교함으로써 반복문을 다시 수행할지 빠져나올지 아니면 표시된 자리로 이동할지를 결정한다. loop문은 ECX 레지스터에 들어있는 수에서 -1을 함으로써 ECX 값이 0이 될 때까지 수행하게 된다. 만약 ECX레지스터가 초기에 0이라면 jecxz 명령어를 사용하여 빠져 나올 수 있다. lea 명령어는 변수에 있는 주소 값을 ECX레지스터에 복사하는 역할을 한다. 파이프라이닝은 CPU의 사이클인 fetch-decode-execute가 수행되는 절차와 조건 문이 사용될 때 컴파일 시 파이프라이닝이 초기화됨을 보여줌으로써 효율적인 프로그램을 작성하는데 필요한 CPU 작동 원리를 알려준다.

 

 

p/193 Chapter 6. Procedures

 

1. 80X86 Stack

 

자주 언급해온 메모리의 5대 영역중의 하나인 stack영역은 메모리의 시작번지와 끝 번지가 있다고 치면 끝 번지에서 시작한다.(완전히 끝은 아니지만 개념상 끝이라고 한다.) 메모리의 끝 부분이 stackbase 포인트, 즉 출발 시점이 된다. 이 때 사용되는 레지스터 EBP는 스택 메모리의 시작점이고 스택이 커질수록 ESPbase에서 멀어진다.

 

 

** 프로시져에 관한 내용은 블로그에 비공개로 올려 놓아야 한다.

 

 

esp를 옮기는 명령어는 push이다. 1bytepush되지 않는다.

stack은 최소 2byte 단위로 표시된다. 메모리가 개입할 때 속도가 느려지는 것을 알 수 있다.

push한다는 것은,

 

1. 스택 주소 = 스택 주소 - push한 크기(스택의 크기를 늘리는 작업)

2. 현재 주소 = 값 대입

우선 stack을 확장하고 난 후에 확장된 stack 공간에 자료가 삽입되게 된다.


 

 

pop명령어는 stack에 있는 자료를 꺼내어 레지스터에 저장하기 때문에 immediateoperand로 올 수 없다.

; push instruction

.386
.MODEL FLAT



ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD



.STACK 4096    ; reserver 4096-byte stack


.DATA 




.CODE    

_start :

mov   eax, 83B5h
push   ax
push  0FFFFFF10h




; input numbers into array
    


quit:    INVOKE ExitProcess, 0  ; exit with return code 0

PUBLIC _start    ; make entry point public
END      ; end of source code



  





 

반응형
Posted by newind2000
Busan IT/Assembly2015. 9. 30. 17:45

==================================Outline====================================

조건문의 사용

----------------------------------------------------------------------------

 

 

if문은 jumpcompare의 조합이다.

 

if문 두 개와 if ~else문을 구분해보면 if ~else문이 효율적이지만 큰 차이는 나지 않는다.

embedded에서는 한 푼도 줄 수 없기 때문에 if ~else를 사용하는 것이 좋다.

 

mnemonic loop

 

ECX는 카운트 레지스터로써 loop문을 만나면 1씩 감소하게 된다.

 

mov ecx, number ; number of iterations

...

 

loop forIndex ; repeat body number times

 

loop문은 기준으로 앞으로 127byte 뒤로 128byte가 넘어가게 되면 loop으로 돌아갈 수 없다. 때문에 128byte가 초과할 경우는 jump문을 사용해야 한다.

 

loope/loopzzero 플래그가 0일 때 빠져 나가게 되는 것이고, loopne/loopnzzero 플래그가 0이 아닐 때 빠져나가게 된다.

 

 

1부터 10까지 더하는 프로그램 for문과 while문으로 작성해보자.

 



 

for문이 jmp명령어가 하나 더 있음을 알 수 있다. 현재 코드는 최적화보다는 for문과 while문의 코드 작성 순서에 따른 차이라고 볼 수 있다.

 

 

 

 

반응형
Posted by newind2000
Busan IT/Assembly2015. 9. 24. 16:23

==================================Outline====================================

div 명령어 숙제

큰 수의 덧셈과 뺄셈
- 캐리 플래그 변경 명령어

분기와 순환
- 무조건 이동 

----------------------------------------------------------------------------

 div 명령어 숙제

 

[답안]

 

C = (5/9) * (F - 32)

9C = 5(F-32)

C = 5(F-32)/9

 

mov esi, 70        //esi = F

sub esi, 32        //esi = F - 32

imul esi, 5        // esi = 5(F-32)


mov edi, 9        //edi = 9

mov eax, esi    //eax = 5(F-32)

cdq                //register setting for div.

idiv edi          // eax = 5(F-32)/9


mov edi, eax    //edi = 5(F-32)/9


edi = 15h

 

 

큰 수의 덧셈과 뺄셈(pdf p/130)

 

64bit길이의 숫자를 계산하려면 32bit인 두 개의 변수를 선언하여 하위 32bit와 상위 32bit를 더해준 후에 올림수만 처리해주면 된다. 이 때 adc 명령어를 사용한다.

 

adc = 올림수가 생기는 것까지 포함하여 덧셈을 해주는 연산

 

A B C

+ D E F

----------

 

add C + F ; 일의 자리수는 일반 덧셈 사용

adc B + E ; 올림수가 발생하는 자리는 adc 사용

adc A + D ; 올림수가 발생하는 자리는 adc 사용

 

 

 

덧셈이나 뺄셈 모두 뒤에서부터 올림 수나 빌림 수를 생각하여 계산해야 한다.

 

캐리 플래그 변경 명령어

 

clc: 클리어(0)

stc: (1)

cmc: 보수(0이면 1, 1이면 0)

 

 

 

분기와 순환(Branching and Looping)

 

 

무조건 이동

 

 

Cgoto문과 같은 기능을 한다. 명령어는 jmp이다. 실행 코드 안에서 이동하기 때문에 코드 영역의 주소를 알아야 한다. 때문에 코드 영역에 라벨을 표시하여 명령어가 실행되면 라벨이 표시된 곳으로 이동한다.

 

 

라벨을 표시하는 방법은 라벨:' //라벨은 사용자가 지정

 

 

pdf p/152 예제




jmp는 앞은 물론 뒤로도 가능하다.

 

jmp를 사용할 때 라벨은 문자임으로 어셈블러는 라벨을 숫자로 기억하고 라벨이 끝나는 자리를 기준으로 라벨이 붙혀진 곳을 계산하여 라벨점으로 이동하게 된다.

 

라벨 후 숫자의 용량을 뜻한다. short 1BYTE near4BYTE이다.

 

레지스터도 jmp명령어의 라벨이 될 수 있다. 이것을 레지스터 indirect라고 부른다.

또한 메모리에 저장된 값도 이동 기준이 될 수 있다.


반응형

'Busan IT > Assembly' 카테고리의 다른 글

확장/반복문, Procedures  (0) 2015.10.01
조건문의 사용  (4) 2015.09.30
기본 명령어(나눗셈, 나눗셈 연산 준비, 레지스터 확장)  (1) 2015.09.24
기본 명령어(inc, dec, neg, mul, imul)  (0) 2015.09.22
mov 명령어  (0) 2015.09.21
Posted by newind2000