본문 바로가기
프로그래밍/SYSTEM HACKING

[SYSTEM HACKING] 어셈블리 반복문( jmp )

by B T Y 2017. 10. 24.
반응형

어셈블리 반복문( jmp )에 대해서 정리한다.




반복문 : for, while, do-while


    - 어셈블리에서 분기문과 반복문의 차이jmp를 이용해서 코드를 반복 시켜주느냐 마느냐의 차이이다.



// for문

int i;


for(i = 0; i <= 10; i++) {

  printf("%d", i);

}


// while문

int i = 1;

while( i <= 10) {

  printf("%d", i);

  i++;

}


// do while문

int i = 1;

do {

  printf("%d", i);

  i++;

} while(i <= 10)


    * 어셈블리에서 inc 명령어를 이용하면 레지스터나 모리의 값을 1씩 증가시켜 줄 수 있다.

         ( 반대로 dec 명령어를 이용하면 값을 레지스터나 메모리의 1씩 감소 시킬 수 있다.. )


    * 어셈블리에서는 for, while, do while 모두 표현하는 방법은 똑같다.

        ( 단지 do while의 경우에는 코드가 한번 먼저 실행 된다는 차이가 있을 뿐이다.. )




( 반복문과 분기문의 차이는 코드가 반복된다는 차이가 있을뿐 사용하는 명령어는 똑같다.. )



( 반복문을 이용할때는 무한 루프에 빠지지 않도록 조건을 설정해서 해당 조건이 되었을때 레이블 이동과 같은 

코드를 작성해줘야 코드가 무한루프 되는걸 막을 수 있다.. )



[실습]


  - 키보드로부터 입력받은 문자열을 거꾸로 출력하는 C와 어셈블리 프로그램을 작성

  - 표준입력 함수: scanf, gets, fgets

  - 문자열 길이는 최대 1024byte




[C 코드]


char buffer[1024];

int len = 0;

int i = 0;


int main() {

  gets ( buffer );


  while( buffer[len] != '\0' ) {

    len++;

  }

  len--;


  for( i = len; i >= 0; i-- ) {

    printf("%c", buffer[i]);

  }

  printf("\n");


  return 0;

}



[어셈블리 코드]


extern printf

extern gets


section .data

print_chr db '%c', 00

print_new db 10, 00


section .bss

buffer resb 1024

len resd 1

i resd 1


section .text

global main


main:

push buffer

call gets

while:

mov edx, dword [len]

cmp byte [buffer + edx], 0

jz while_end

inc dword [len]

jmp while

while_end:

dec dword [len]


mov edx, dword [len]

mov dword [i],               edx

for:

mov edx, dword [i]

cmp dword [i], 0

jl end


mov edx, dword [i]

mov eax, [buffer + edx]


push eax

push print_chr

call printf


dec dword [len]


jmp for

end:

push print_new

call printf


    * 여기서 주의할점은 유효주소를 이용한 연산을 할때 [ ] 안에서 메모리와 메모리는 +를 이용한 연산이 불가능하기 때문에 문자열의 길이를 담고 있는 len 레이블의 값을 

      레지스터(edx)에 할당시킨다음 연산을 해줘야 한다.


    * 위 어셈블리 코드에서는 문자열 입력을 scanf 대신에 gets 함수를 이용해서 입력을 받았다.

       ( gets는 해당 변수의 주소값을 인자로 갖는다 )


    * 리눅스에서는 표준 입/출력을 할때 일정 크기가 될때까지 cache 계속 모아둔다. 그렇기 때문에 일정 크기가 되지 전에 입/출력을 하려면 

      '\n' 줄바꿈, 즉 엔터키 값을 줘야 해당 값들을 입/출력한다.



반응형

댓글