Busan IT/Assembly2015. 9. 24. 09:27

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

기본 명령어

- 나눗셈 idev/dev

- 나눗셈 연산 준비 cbw, cwd, cdq, cwde

- 레지스터 확장 movezx, movesx

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

 

** 박스의 겉넓이를 구하는 공식에 대한 assembly 공식 문제 풀이

 


2{length(width + height) + width*height)

bx = width + height

cx = width * height


1. bx = width + height

2. cx = width * height

3. ax = bx * length   

4. dx = ax        // dx = length(width+height)

5. dx = dx + cx  // dx = length(width+height) + width * height

5. dx = dx + dx  // dx = 2{length(width+height) + width * height}


나눗셈 idev/dev

나눗셈에 대하여 알아보자. 나눗셈은 division의 약자인 div를 사용한다. div는 양수만을 나눌 때 사용되고 idiv는 음수와 양수 모두(정수)에 사용된다.

 

//imulsigned(정수)이다.

16비트로 나누면 8비트, 8비트 나누어진다.

 

Assembly에서는 나눗셈 연산을 수행하면 몫과 나머지가 동시에 저장된다. 즉 소수점 계산이 아닌 정수 계산으로 연산이 진행된다.

 

 

 

/헥사 값의 첫 수에 영어가 나왔을 때 반드시 0을 붙혀 주어야 한다.

 

 

 

pdf p/133, 134 예제 해보기

책에 나와 있는 그대로 예제를 사용하여 그 값을 확인하면 된다. 어렵지 않다.

 




idiv는 연산 중에 가장 많은 사이클을 소모함을 알 수 있다.

양수는 그나마 사이클을 덜 소모한다.

 

때문에 코딩 시 음수를 사용하지 않는 경우 양수를 사용하는 것이 프로그램 성능에 도움이 된다.

 

나눗셈 연산 준비 cbw, cwd, cdq, cwde


나눗셈을 하는 경우 결과 값은 몫과 나머지가 나오기 때문에 몫과 나머지가 출력되는 레지스터를 정리할 필요가 있다. 몫은 AX레지스터에 입력됨으로 따로 신경 쓸 필요가 없지만 2byte1byte로 나누는 경우 이외의 같은 용량의 바이트의 제수가 피제수를 나누는 경우 DX레지스터를 준비해 주어야 한다.

 

주의함 점은 양수인 경우 확장 레지스터를 0, 음수인 경우 1을 넣어주어야 하는데 이 작업을 수행해주는 명령어가 존재한다. 아래의 명령어들은 operand가 필요없다는 점은 알아야 한다.

 

cbw(convert byte to word): AL -> AX로 확장

cwd(convert word to double): AX -> DX로 확장

cdq(convert double to quardword): EAX -> EDX로 확장

cwde(convert word to double extended): AX -> EAX(일반적으로 나눗셈을 위해 사용되는 명령어이다)



 

//음수인 경우의 수는 오른쪽 쉬프트를 사용할 때 가장 왼쪽 자리의 수는 1로 채워진다.

//음수를 유지하기 위한 작업이다.

 

 

레지스터 확장 movezx, movesx 

 

 

movezx 레지스터가 2byte인 경우 4byte로 확장하면서 0으로 채워준다.

movesx의 경우에는 레지스터의 값이 음수인지 양수인지 판단 후 확장시켜 준다.

 

movesxcwde명령어와 비슷하지만 cwdeAX레지스터에 한정된다는 점이 다르다.

 





반응형
Posted by newind2000
Busan IT/Assembly2015. 9. 22. 17:42

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

 기본 명령어

- 증감 명령어 inc, dec

- 부호 변경 neg

- 곱셈 mul, imul

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

증감 명령어 inc, dec


 

최상위 비트는 부호 비트로 보기 때문에 맨 아래의 연산에서 SF1이 된다.


부호 변경 neg


 

neg2의 보수를 취해주는 연산이다.

 

곱셈 mul, imul


곱셉의 연산은 multiplication의 약자인 ‘mul'이다.

 


 

‘mul’ 명령어를 사용하면 accumulatoreax가 사용되게 된다.

 

곱하기를 하게 되면 곱셈을 사용한 연산레지스터의 두 배의 용량이 필요하기 때문에 (e)dx를 빌려오게 된다.

 

 

 

1byte 곱셈이기 때문에 AL에 있는 값과 곱하기가 된다. 때문에 dx레지스터를 빌려오지 않고 AH를 사용하여 2byte를 확보하게 된다.

 



 

2번을 작성하여 결과 값을 windbg로 확인해보자.


 

imul은 곱셈 때 양수만 취급한다. mul은 형식이 한가지이지만 imul은 세가지이다.

 

 

1. imul source

mul과 동일하다.

 

2. imul register, source

Opcode2byte임을 알 수 있다.

 

 

3. register, source, immediate

소스와 상수가 곱해진 값이 레지스터에 입력된다.

imul은 양수만 취급하기 때문에 싸인플래그(SF)가 변하지 않는다.

 

imul은 확장 레지스터가 없기 때문에 레지스터를 넘어가는 값은 버려진다.

 

mul보다 add가 클럭 사이클이 적게 소모되기 때문에 곱하는 수가 낮을 경우 add연산을 사용하는 것이 효율적이다.

 

pdf/127쳐보기

숙제 pdf p/130 exercise 4.3 2

반응형
Posted by newind2000
Busan IT/Assembly2015. 9. 21. 17:33

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

mov 명령어

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

mov 명령어

 

mov 명령어에 대하여 공부해보자.

 

 

mov 명령어의 문법은 mov destination, source이다.

 

 

메모리에 있는 변수끼리의 mov 명령어는 실행 불가능하다.

 

ex) mov Count, Number //illegal for two memory operands

 

CPU 레지스터를 거쳐서 데이터가 이동해야 한다.

 

 

 

Opcodecpu가 이해할 수 있는 언어이기 때문에 exe파일 자체를 assembly language로 고칠 수 있다.

 

AL100을 넣는 assembly를 작성해보자.

 

mov AL, 64h //assembly language

B0 64 //기계어

 

 

C8, 10, 16진수만 사용 가능하지만 assembly2진수도 가능하다.

 

 

어셈블러를 기계어로 변환시켜보자.

 

mov CH, 10

 

-> B5 0A

 

mov EDX, 64

 

-> BA 40 00 00 00 //little endian

direct는 메모리에 직접 집어넣기 때문에 메모리 주소가 필요하다.

변수가 아닌 주소를 사용하기 때문에 주소 값 4byte가 필요하다. 값을 이동시키기 위해서는 원본과 복사본이 필요한데 두 개의 크기는 같아야 한다. 때문에 원본과 복사본의 용량이 각 각 4byte로써 8byte. opcode1byte를 사용한다.

 

immediate(상수) 값은 cpu에 있다.

 

register indirect

 

mov EDX, 64 //EDX64를 넣는다.

 

mov [EDX], 64 //EDX가 가리키는 주소에 64를 넣는다. 포인터와 같은 기능

 

 

아래 표에서 C72개이기 때문에 이를 구별하기 위한 1byte가 필요하다.

AL, AX, EAX에 데이터를 복사하는 기계어는 따로 분리되어 있다. accumulate는 가장 많이 사용하는 명령어이기 때문이다.

 

mov AL, 100 //A0

mov BL, 100 //8A

mov CL, 100 //8A

mov BH, 100 //8A

 

 

//segment register들은 사용하지 않는다.

//굳이 op코드를 외울 필요 없이 표를 보는 방법을 습득해야 한다.

 

 

xchg eax, ebx ; eaxebx값을 바꾼다.

레지스터에 데이터 값은 빅엔디안, 메모리의 값은 리틀 엔디안으로 저장되어 있다.

 

 

AL, AH는 따로 지원하지 않고 EAX부터 따로 opcode가 나뉜다.

 

movxchg를 사용할 때의 클럭 수의 차이를 살펴보자.

 

mov AL, AH ;1 clock

mov AH, BH ;1 clock

mov BH, AL ;1 clock

 

xchg AH, BH ;3 clock

 

 

어셈블리어 코드는 작성자가 용량과 효율을 고려하여 코드를 작성하여야 한다.

 

컴파일러는 assembly 언어를 기계어로 바꿀 때 용량과 효율을 고려하여 컴파일 한다.

컴파일러보다 assembly 언어를 최적화 시킬 수 없다면 assembly어는 손대지 않는 것이 낫다.

 

 

 

 

 

 

 

정수의 덧셈/뺄셈 명령어

 

 

 

덧셈 : add dest., source

뺄셈 : sub dest., source

 

결과는 dest.에 저장된다.

 

 

 

연산을 하는 명령어는 다른 레지스터에 영향을 미친다.


EFL(Extended Flag) 은 비트들의 플래그만 모아 놓은 레지스터이다.

 

//책에 틀린 내용이 존재함으로 위의 연산을 일일이 확인해 보아야 한다.

Windbg를 사용하여 EFL의 값을 확인할 수 있다.

표에 나와 있는 내용을

 

00 00 02 06

 

 

-> 0(SF)0(ZF)10 0110(CF)

 

 

계산 결과가 부호비트를 넘었을 때도 overflow가 발생한다.


 

 

반응형
Posted by newind2000
Busan IT/Assembly2015. 8. 21. 17:31

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

디버깅

명령어의 표현과 구조

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

디버깅

 

asm 파일 컴파일 시 디버그 기능 추가

 

- 컴파일

ml /c /coff /Zi *.asm

 

- 링크

link /debug /subsystem:console /entry:start /out:*.exe *.obj kernel32.lib

 

 

디버그를 위한 툴 'windbg'

 

 

 

새창으로 windbg가 열리면 메뉴에서 File -> Open Excutable...

실행 파일을 선택한다.

 

실행 창과 command 창이 뜬다.

F8 또는 'step into' 아이콘을 눌러 프로그램을 진행 시킨다.

이 때 메모리와 레지스터의 상태를 보고 싶다면 메뉴->View에서 원하는 것을 선택한다.

 

 

프로그램이 실행되면 소스가 적힌 코드 창이 뜬다. 여기에 노란줄로 실행되고 있는 코드 영역이 표시 된다.

 

 

 

메모리를 볼 때 원하는 변수명을 앞에 ‘&’와 같이 붙혀 주면 해당 변수의 시작점부터 메모리를 볼 수 있다.

'step into' 버튼을 눌러가며 메모리와 레지스터의 변화를 살펴본다.

 

//EIP는 실행되고 있는 명령어 주소를 가리키는 레지스터이다.

 

 

 

 

명령어의 표현과 구조

 

 

컴파일 시 '/Fl' 옵션을 추가하면 ‘lts'파일이 생성된다.

 

lst파일은 가장 좌측에는 메모리 시작점에서 떨어진 주소를 16진수 8자리 숫자로 표시하고,

그 다음 숫자는 기계어를 나타낸다.

 

//어셈블리에서는 대소문자를 구분하지 않는다.

 

mask BYTE 7dh -> char mask = 125;


변수에 값을 직접적으로 넣는 것을 direct 방식, 간접적으로 넣는 방식을 indirect방식이라고 한다.

 

indirect 방식을 사용할 때 ‘[]’를 사용한다. C에서 포인터 방식이라고 생각하면 된다. indirect 방식은 레지스터에만 사용 가능하다.

 

데이터 복사 명령어

 

number of Byte는 컴파일 후 생성되는 명령어의 길이다.

//immediate는 레지스터 혹은 변수에 들어가는 실제 값


/*** lst 코드 ***/


Microsoft (R) Macro Assembler Version 6.11        08/21/15 16:17:23
sample1.asm                 Page 1 - 1


        ; Sample code for dummy

        .386
        .MODEL FLAT

        ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD

        INCLUDE io.h
            C ; IO.H -- header file for I/O macros
            C ; 32-bit version for flat memory model
            C ; R. Detmer   last revised 8/2000
            C .NOLIST     ; turn off listing
            C .LIST        ; begin listing
            C 

 = 0000000D      cr EQU 0dh
 = 0000000A      Lf EQU 0ah

        .STACK 4096

 00000000      .DATA
 00000000 00000000    number1   DWORD  ?
 00000004 00000000    number2   DWORD  ?
 00000008 45 674 65 72  prompt1   BYTE  "Enter first number: "0
     20 66 69 72 73
     74 20 675 6D
     62 65 72 320
     00
 000000145 674 65 72  prompt2   BYTE  "Enter second number: "0
     20 73 65 63 6F
     664 20 675
     662 65 72 3A
     20 00
 00000033  00000028 [    string    BYTE  40 DUP (?)
      00
     ]
 00000050054 68 65  labell    BYTE  cr, Lf, "The sum is "
     20 73 75 620
     69 73 20
 00000068  0000000B [    sum     BYTE  11 DUP (?)
      00
     ]
 00000073  0000        BYTE  cr, Lf, 0

 00000000      .CODE

        ;entry point
 00000000      _start:
          output  prompt1    ;a printf call in C, output is a function made from the provider
          input  string, 40  ;a scanf call in C, percieve as ASCII code
          atod  string    ;convert ASCII to DWORD and store to eax
 0000002E  A3 00000000 R    mov  number1, eax  ;number1 = eax

          output  prompt2
          input  string, 40
          atod  string
 00000061  A3 00000004 R    mov  number2, eax  

 00000066  A1 00000000 R    mov  eax, number1
 0000006B  03 05 00000004 R    add  eax, number2  ; eax = eax + number2 // result of algebric operation is stored at eax
          dtoa  sum, eax
          output  labell

          INVOKE  ExitProcess, 0

        PUBLIC _start

        END



Microsoft (R) Macro Assembler Version 6.11        08/21/15 16:17:23
sample1.asm                 Symbols 2 - 1




Macros:

                N a m e                 Type

atod . . . . . . . . . . . . . .  Proc
atoi . . . . . . . . . . . . . .  Proc
dtoa . . . . . . . . . . . . . .  Proc
input  . . . . . . . . . . . . .  Proc
itoa . . . . . . . . . . . . . .  Proc
output . . . . . . . . . . . . .  Proc


Segments and Groups:

                N a m e                 Size     Length   Align   Combine Class

FLAT . . . . . . . . . . . . . .  GROUP
STACK  . . . . . . . . . . . . .  32 Bit   00001000 DWord    Stack    'STACK'   
_DATA  . . . . . . . . . . . . .  32 Bit   00000076 DWord    Public  'DATA'  
_TEXT  . . . . . . . . . . . . .  32 Bit   00000097 DWord    Public  'CODE'  


Procedures,  parameters and locals:

                N a m e                 Type     Value    Attr

ExitProcess  . . . . . . . . . .  P Near   00000000 FLAT  Length= 00000000 External STDCALL


Symbols:

                N a m e                 Type     Value    Attr

@CodeSize  . . . . . . . . . . .  Number   00000000h   
@DataSize  . . . . . . . . . . .  Number   00000000h   
@Interface . . . . . . . . . . .  Number   00000000h   
@Model . . . . . . . . . . . . .  Number   00000007h   
@code  . . . . . . . . . . . . .  Text      _TEXT
@data  . . . . . . . . . . . . .  Text      FLAT
@fardata?  . . . . . . . . . . .  Text      FLAT
@fardata . . . . . . . . . . . .  Text      FLAT
@stack . . . . . . . . . . . . .  Text      FLAT
Lf . . . . . . . . . . . . . . .  Number   0000000Ah   
_start . . . . . . . . . . . . .  L Near   00000000 _TEXT  Public
atodproc . . . . . . . . . . . .  L Near   00000000 FLAT  External
atoiproc . . . . . . . . . . . .  L Near   00000000 FLAT  External
cr . . . . . . . . . . . . . . .  Number   0000000Dh   
dtoaproc . . . . . . . . . . . .  L Near   00000000 FLAT  External
inproc . . . . . . . . . . . . .  L Near   00000000 FLAT  External
itoaproc . . . . . . . . . . . .  L Near   00000000 FLAT  External
labell . . . . . . . . . . . . .  Byte   0000005B _DATA  
number1  . . . . . . . . . . . .  DWord   00000000 _DATA  
number2  . . . . . . . . . . . .  DWord   00000004 _DATA  
outproc  . . . . . . . . . . . .  L Near   00000000 FLAT  External
prompt1  . . . . . . . . . . . .  Byte   00000008 _DATA  
prompt2  . . . . . . . . . . . .  Byte   0000001D _DATA  
string . . . . . . . . . . . . .  Byte   00000033 _DATA  
sum  . . . . . . . . . . . . . .  Byte   00000068 _DATA  

     0 Warnings
     0 Errors

반응형
Posted by newind2000
Busan IT/Assembly2015. 8. 20. 17:39

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

어셈블리어의 구성요소

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

 

어셈블리어의 구성요소

 

에셈블리어 자체의 문법은 간단하지만 알고리즘 구현은 까다롭다.

 

 

 

Directive(.)는 행동을 명령할 때 사용된다.

 

 

 

에셈블리어는 name, mnemonic 그리고 operand로 구성된다.

 

//mov 데이터를 삽입할 때 사용한다. C에서 '='와 같은 연산자이다.

 

간단한 어셈블리어 코드를 보고 기본 문법을 익혀 보자.

 


/*** 코드 해석 ***/


.386 ; 386에서 수행되는 명령어를 사용, 일반적으로 코딩 시 386을 사용한다.

.MODEL FLAT ; 데이터가 구역 없이 메모리에 저장되는 방식 <-> SEGMENT

 

ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD ; Exit함수 호출: 원상복구 시키며 종료

 

INCLUDE io.h ; 헤더 파일 추가

 

 

cr EQU 0dh ; #define cr 0dh //16진수를 사용할 때, ‘0*h’로 표현해준다.

Lf EQU 0ah ; #define Lf 0ah

 

.STACK 4096 ; 4kbyte 스택를 확보한다.

 

.DATA ; 변수 선언. 데이터 영역 확보(전역변수)

number1 DWORD ? ; 4byte number1 초기화 없이 선언

number2 DWORD ? ; 4byte number2 초기화 없이 선언

 

prompt BYTE "Enter first number: ", 0; 문자열 선언 //어셈블리는 문자열에서 NULL을 포함시키지 않기 때문에 NULL을 추가시켜 주어야 한다.

prompt BYTE "Enter first number: ", 0;

 

string BYTE 40 DUP (?) ; 40BYTE 쓰레기 값을 복사하여 string에 넣어라.

labell BYTE cr, Lf, "The sum is " ; 13, 10, The sum islabell에 넣어라.

sum BYTE 11 DUP(?) ; 11BYTE 쓰레기 값을 복사하여 sum에 넣어라.

BYTE cr, Lf, 0 ; 1byte cr, Lf, 0 생성

 

 

컴파일 명령어 : ml /c /coff example.asm

 

 

링크 명령어 : link /subsystem:console /entry:start /out:example.exe example.obj io.obj kernel32.lib

 

//WORD = 2BYTE

//DWORD = double word, 4BYTE


/*** 코드 ***/

; Sample code for dummy

.386
.MODEL FLAT

ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD

INCLUDE io.h

cr EQU 0dh
Lf EQU 0ah

.STACK 4096

.DATA
number1   DWORD  ?
number2   DWORD  ?
prompt1   BYTE  "Enter first number: "0
prompt2   BYTE  "Enter second number: "0
string    BYTE  40 DUP (?)
labell    BYTE  cr, Lf, "The sum is "
sum     BYTE  11 DUP (?)
    BYTE  cr, Lf, 0

.CODE

;entry point
_start:
  output  prompt1    ;a printf call in C, output is a function made from the provider
  input  string, 40  ;a scanf call in C, percieve as ASCII code
  atod  string    ;convert ASCII to DWORD and store to eax
  mov  number1, eax  ;number1 = eax

  output  prompt2
  input  string, 40
  atod  string
  mov  number2, eax  

  mov  eax, number1
  add  eax, number2  ; eax = eax + number2 // result of algebric operation is stored at eax
  dtoa  sum, eax
  output  labell

  INVOKE  ExitProcess, 0

PUBLIC _start

반응형
Posted by newind2000
Busan IT/Assembly2015. 8. 17. 17:37

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

자료형과 컴퓨터 시스템

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

 

ARM이나 ATmegaI/O Mapped Memory 방식을 사용하여 C의 포인터로 메모리를 사용할 수 있었으나 I/O Mapped I/O방식은 포인터로 조작할 수 없음으로 어셈블러를 사용해야 한다.

 

데이터 레지스터 혹은 일반 레지스터는 EAX, EBX, ECX, EDX이다.

 

EAX(Extended Accumulator Register) 속도가 빠르기 때문에 계산에 사용되면 이를 누산기(accumulator)라고 부른다. EAX4byte이며 하위 2byteAX라고 부른다.

AX에서 가장 하위 비트를 AL 한 단계 상위 비트를 AH로 부른다.

 

유니온 구조체로 표현하자면,

 

union Reg

{

int EAX;

short AX;

char AH;

char AL;

}

 

EBX(Extended Base Register), ECX(Extended Count Register), EDX(Extended Data Register)

 

과거 2byte체제에서는 확장되지 않은 레지스터들이(AX, BX, CX, DX) 존재했다.

386체제부터는 4byte로 확장되었다.

 

추가적인 4개의 레지스터들이 존재한다.

 

ESIEDI는 인덱스 레지스터이다. 인덱스를 사용하여 데이터를 복사하는데 사용한다.

ESP는 스택 포인터이고 EBP는 베이스 포인터이다.

 

6개의 구역을 나누는 레지스터도 존재한다: CS, DS, ES, FS, GS, SS

 

4byte 명령어 포인터 EIP(Extended Instruction Pointer)

 

EIP = PC(Program Counter) -> 명령어가 수행되는 Code영역의 주소를 가지고 있다.

 

EFLAGS는 상태레지스터로 사용된다.

 

//위에 표는 다음에 사용될테니 잘 보아두자.

mnemonic은 특정한 명령어, 지시어 혹은 명령이다. 한 개 이상의 연산이 있을 때 연산은 쉼표(,)로 구분된다.

 

ex) add eax, 158 -> 05 00 00 00 9E






 

 

반응형
Posted by newind2000