Busan IT/로봇제어2015. 10. 15. 09:15

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

라즈베리파이 커널 업데이트 내용 확인

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

 

'uname -r‘을 입력하여 현재의 버전 정보를 보자. 커널이 업그레이드 된 것을 알 수 있다.

 

3.18.7-7+ --> 4.1.10-v7+

 

커널을 업데이트한 이유는 커널 프로그램을 작성하기 위해서이다.

 

커널 프로그램은 운영체제에 속한 최상위 프로그램이기 때문에 오류가나면 전원을 뽑는 것 이외에는 방법이 없다.

 

레지스터는 CPU에 따라 모양이 바뀐다.

 

//porting작업은 기존의 같은 내용을 복사해 사용하고 수정된 내용만 덮어씌운다.

 

/usr/src/linux/arch에 들어가면 CPU의 소스들이 저장되어 있다.

 

intel : ia64, x86

 

arm 디렉토리에 들어오면 mach-'제조사로 된 디렉토리들을 볼 수 있다.

 

mach-bcm2709폴더 들어가서 파일들을 살펴보자. ARM CPU를 컴파일하게 되면 해당 폴더에 있는 파일들이 동작하게 된다.

 

make프로그램은 컴파일 시 변동된 부분만 컴파일하도록 해주는 프로그램이다.

 

menuconfig 창을 띄워보자.

 

'apt-get install ncurses-dev'

 

'make menuconfig'

 



 

config파일은 해당 설정을 저장해놓은 파일들이다.

 

joinc에서 Linux 커널에서의 디바이스 드라이버 작성

 

http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/Embedded/Documents/WritingDeviceDriversInLinux

 

linux에서 커널을 프로그램을 만드는 방법은 두 가지이다.

1. 직접 커널을 건드려 만든다.

2. 모듈을 사용하여 만든다.

 

이 모듈을 device driver라고 하고 linux에 사용되는 모듈을 lkm(Linux Kernel Module)이라고 한다.

 

CPU내에는 메모리를 관리해주는 MMU(Memory Management Unit)가 필요하다.

 

커널에서 프로그램을 작성하면 실제 메모리를 사용하게 된다. 이 실제 메모리를 kernel메모리라고 한다.

 

사용자가 장치에 내리는 모든 명령어는 커널을 통해 수행된다.

 

//키보드 보안 프로그램은 키보드 후킹을 감시하는 역할을 한다.

 

... 그래서 디바이스 드라이버를 배울 필요가 있다.

 

 

kernel에 모듈을 올리는 함수는 'insmod', 모듈을 삭제하는 함수는 ‘rmmod'이다.

 

 

반응형
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/로봇제어2015. 10. 15. 09:10

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

ARM 레지스터

gcc kernel 업데이트

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

ARM 레지스터 

로봇제어를 하겠다. 정규시간에는 로봇제어 비정규시간에는 어셈블리를 공부하겠다.

 

라즈베리파이에서 기본형에 간단한 함수를 만들어 넣고 에셈블리 파일이 나오도록 컴파일한다.

 

파일을 열어보면 기존에 배운 어셈블리 파일과 내용이 다른 것을 알 수 있다. 라즈베리 파이는 ARMCPU를 쓰기 때문이다.

 

- 'str' 저장 명령어

 

//embedded recipes 책의 ARM레지스터 부분 참조

레지스터들의 이름은 CPU마다 다르다. Inter사의 이름이 붙은 레지스터가 특이한 경우이다.

 

PCProgram Counter이다. 인텔 CPU 레지스터의 EIP와 같은 기능을 한다.

 

레지스터는 7가지 모드가 존재한다.

 

r13 - r15는 특수한 기능을 가지고 있다.

 

모드에 상관없이 r0 - r7에는 같은 값이 들어간다.

 

- SP는 스택 포인터의 약자이다.

 

r14link 레지스터로써 프로그램이 복귀할 주소를 저장해 놓는다.

 

인텔의 CPU와 달리 ARM은 함수의 인자와 리턴 어드레스를 저장하기 위해 스택을 사용하지 않고 CPU 레지스터를 사용한다.

 

ARM은 메모리를 적게 사용하기 때문에 Intel에 비해 속도가 빠르다.


gcc kernel 업데이트 

리눅스에 맞는 최신 커널을 다운받아 업데이트한다.

 

https://www.raspberrypi.org/documentation/linux/kernel/building.md

 

 

GitHub는 프로그램을 버전별로 정리해주는 자료서버이다.

 

 

라즈베리파이2 회로도 정보 및 techrical reference manual을 다운 받아 저장한다.




반응형
Posted by newind2000
Busan IT/ARM Controller2015. 10. 13. 13:27

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

인터럽트 코드 분석

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

 

EXTI는 외부 인터럽트를 말한다.

 

인터럽트는 크게 내부 인터럽트(소프트웨어)와 외부 인터럽트로 나뉜다.

 

ARM에서 인터럽트를 설정할 때 인터럽트의 종류와 함께 인터럽트자체 설정을 해주는데 이때 사용하는 인터럽트 설정이 ‘NVIC’이다.

 

인터럽트의 종류가 바뀌면 핸들러의 이름을 바꾸어 주어야 한다.

 

void EXTI2_IRQHandler(void)

{

...

}

 

void NVIC_init(void)

{

/* Enable and set EXTI2 Interrupt to the lowest priority */

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;

...

}

 

우선 순위(priority)0 - 15까지 나뉜다. 숫자가 낮을수록 우선순위가 높다.

 

외부 인터럽트를 사용한다는 것은 GPIO의 특수기능을 사용한다는 것이다. 때문에 특수기능을 활성화 시키는 명령어를 추가해주어야 한다.

 



 

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);

외부 pin을 인터럽트로 활성화시키는 코드이다.

 

코드 속 내용을 하나씩 뜯어서 분석해보자.

 

 

반응형

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

Timer  (0) 2015.10.19
Advanced-control timers(TIM1&8)  (0) 2015.10.16
Interrupt  (0) 2015.10.12
ARM Clock 설정  (0) 2015.10.12
내부 LED 반전 프로그램 만들기  (0) 2015.10.08
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/ARM Controller2015. 10. 12. 12:59

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

Interrupt

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

 

 

인터럽트 사용에 대해 알아보자. 레지스터 데이터시트 p/196이다.

 

 




 

회색으로 표시된 인터럽트는 시스템 인터럽트이고 흰색으로 표시된 것들은 소프트웨어 인터럽트이다.

 

종류가 많다는 것을 알 수 있다.

 

이번 시간에 주로 살펴볼 인터럽트는 ‘EXTI’라는 인터럽트이다. 20개의 edge 감지기를 가지고 있다.

 

주요 특징을 살펴보자.




 

firmware 라이브러리 함수를 사용하여 설정해주면 된다.

 

원하는 인터럽트를 선택해야 한다.

 

 

주요 레지스터들을 살펴보자.




 

인터럽트 레지스터와 이벤트 마스크 레지스터에서 원하는 자리를 set해주면 해당 인터럽트가 작동하게 된다.

 

상승에지와 하강에지 인터럽트를 설정하는 레지스터

상승에지와 하강에지 인터럽트를 동시에 set하는 것도 가능하다.

 

‘EXTI_PR'은 인터럽트가 발생하면 ‘1’로 바뀌는 레지스터이다.



 

변수 생성 시 24가지 종류의 변수 타입을 참고한다.

 

** 4byte 변수는 int가 아니라 long임을 주의하자.





 

EXTI설정은 쉬우나 NVIC설정은 까다롭다.

 

 

PM0056 프로그래밍 매뉴얼 p/118




원하는 인터럽트 자리에 ‘1’를 입력해주면 해당 인터럽트가 활성화된다.

 






각 레지스터들의 기능을 참고하여 프로그래밍을 해보자.

firmware 라이브러리를 사용하면 간단하다. 

 

- 전원 ON LED(PA0)1초 간격으로 깜빡거리게 만든다.

- 스위치(PA2)를 누르면 깜빡거리는 기능이 멈춘다.

- 스위치(PA2)를 떼면 다시 정상 작동한다.

 








#include <stm32f10x.h>
#include <misc.h>


vu32 vulCnt;

#define Delay(x) for(vulCnt = 0; vulCnt < x; ++vulCnt)

//    EXTI2_IRQn
void EXTI2_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line2) != RESET)
    {
      //  처리할 내용  : while (A가 눌러진 상태)
      while0==(GPIOA->IDR & 0x04) )
      {
           ;
      }        
      
    }
    EXTI_ClearITPendingBit(EXTI_Line2);
}
void EXTI2_init(void)
{
  /* Enables external lines 2 interrupt generation on falling edge */
  EXTI_InitTypeDef EXTI_InitStructure;
  EXTI_InitStructure.EXTI_Line = EXTI_Line2;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}

void NVIC_init(void)
{
  /* Enable and set EXTI2 Interrupt to the lowest priority */
  NVIC_InitTypeDef NVIC_InitStructure;   
  NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void PA2_in(void)
{
    /* Configure all the GPIOA in Input Floating mode */
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
}

void PA0_out(void)
{
      /* Configure all the GPIOA in Input Floating mode */
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
}



void Init(void)
{
    EXTI2_init();
    NVIC_init();
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
    PA0_out();
    PA2_in();    
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);

}

int main(void)
{
    Init();
    while(1)
    {
      GPIO_SetBits(GPIOA, GPIO_Pin_0);
      Delay(1000000);
      GPIO_ResetBits(GPIOA, GPIO_Pin_0);
      Delay(1000000);        
    }
  
    return 0;
}


반응형

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

Advanced-control timers(TIM1&8)  (0) 2015.10.16
인터럽트 코드 분석  (0) 2015.10.13
ARM Clock 설정  (0) 2015.10.12
내부 LED 반전 프로그램 만들기  (0) 2015.10.08
ARM 3 Core Test, 내부 LED 동작 프로그래밍  (0) 2015.10.06
Posted by newind2000
Busan IT/ARM Controller2015. 10. 12. 09:16

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

ARM Clock 설정

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

 

manual p/90 Reset

 

Reset3가지 종류로 나눈다.

1. 시스템(system)

2. 파워(power)

3. 백업 도메인(backup domain)

 

리셋은 두 가지 볼 수 있다.

1. Low Active(/RST)

2. High Active(RST(bar))

 

회로에는 반드시 리셋이 존재해야 한다.

 

기존의 ARM의 클럭은 8MB이지만 이를 증폭하여 사용할 수 있다.

 

 

증폭을 활용하여 최대로 만들 수 있는 클럭은 72MHZ이다.

 


 

 

클럭을 증폭시키기 위해 사용하는 것이 PLL이다.

 

시스템 클럭은 MUX에서 존재하는 클럭 중 하나를 선택한 것이 된다.


해당 비트에 ‘1’을 삽입하면 해당 기능이 리셋되게 된다.

 

ENR레지스터는 리셋의 반대



 

반응형

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

인터럽트 코드 분석  (0) 2015.10.13
Interrupt  (0) 2015.10.12
내부 LED 반전 프로그램 만들기  (0) 2015.10.08
ARM 3 Core Test, 내부 LED 동작 프로그래밍  (0) 2015.10.06
ARM Core3 M3 프로그래밍 환경 설정  (0) 2015.10.05
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/ARM Controller2015. 10. 8. 08:34

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

내부 LED 반전 프로그램 만들기

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

 내부 LED 반전 프로그램 만들기



 

pull-up, pull-down은 주로 외부에서 설정해준다.

 

 

출력모드가 push-pullopen-drain으로 나누어져 있다.

push-pull은 내부의 신호를 그대로 전달하는 것이다. 내부 회로가 설계되어 있어 안정적이다.

 

open-drain은 전압불충분 현상을 해결하기 위한 방법이다. BJT는 전류 제어 형태의 트랜지스터이다. BJT는 전류가 많이 흘러 열이 발생하게 되는데 이를 보완하기 위해 만들어진 것이다 FET이다.

 

FET(FIELD EFFECTIVE TRANSISTOR)N채널과 P채널로 나누어진다.

 

MOS(METAL OXIDE SILICON)

 

전기/전자분야에서 Z는 임피던스 즉 FLOATING상태를 뜻한다.

 




 

코딩할 때 표를 보면서 설정하면 된다.

 

 

MCU에 있는 LED가 보드에 위치한 LED와 반전되도록 코딩을 해보자.

 

 

PORTC에 클럭을 공급해주고 PORTC 12번 핀에 highlow를 넣어주는 코딩만 하면 된다.






반응형

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

Interrupt  (0) 2015.10.12
ARM Clock 설정  (0) 2015.10.12
ARM 3 Core Test, 내부 LED 동작 프로그래밍  (0) 2015.10.06
ARM Core3 M3 프로그래밍 환경 설정  (0) 2015.10.05
ADC 전압측정  (0) 2015.09.18
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