월요일, 1월 09, 2017

[Assembly] C언어 반복문은 어셈블리어로 어떻게 변환될까?


C언어에서 for나 while을 통해 반복문을 많이 사용하는데, 이것을 하드웨어는 어떻게 이해하는지 탐구해보자.

실험은 MIPS instruction들을 사용하는 환경에서 진행하였으며, 컴파일러는 Cygwin에서 제공하는 MIPS용 gcc를 사용하였다.

우선 for문을 사용한 아주 간단한 C 코드를 다음과 같이 작성한다.
int main()
{
  int i;
  for (i=0; i<0xFFFF; i++);
  return 0;
main() 함수가 호출되면, i라는 정수형 변수를 선언하고 i의 값을 0부터 시작하여 0xFFFF가 될 때까지 1씩 증가시키다가 반복문을 빠져나가고 종료된다.

이 코드를 컴파일하면 다음과 같은 어셈블리 코드를 얻어낼 수 있다.
  1c: afc00000 sw zero,0(s8)
  20: 0800000e j 38
  24: 00000000 nop
  28: 8fc20000 lw v0,0(s8)
  2c: 00000000 nop
  30: 24420001 addiu v0,v0,1
  34: afc20000 sw v0,0(s8)
  38: 8fc20000 lw v0,0(s8)
  3c: 3403ffff li v1,0xffff
  40: 0043102a slt v0,v0,v1
  44: 1440fff8 bnez v0,28
  48: 00000000 nop
1c부터 차례차례 과정을 살펴보자. 쉽게 알아볼 수 있도록 "저장소 <= 저장할 값" 형식으로 표현하겠다.

1c:
0(s8) <= 0
메모리 주소 0(s8)에 값 0을 저장한다.

20:
38로 jump한다.

38:
v0 <= 0(s8)
v0 레지스터에 0(s8)에 저장되어 있는 0을 불러와서 저장한다.

3c:
v1 <= 0xffff
v1 레지스터에 값 0xffff을 저장한다.

40:
v0 <= 0 또는 1
v0과 v1의 값을 비교한다. 만약 v0이 v1보다 작을 경우 v0에 1을 저장하고, 그렇지 않은 경우에는 0을 저장한다. 즉, for문의 가운데 조건 부분 (i < 0xffff)을 검증하는 작업이다.
v0에는 현재의 i값인 0이 저장되어 있고, v1에는 0xffff가 저장되어 있기 때문에, v0은 1로 셋팅된다.

44:
v0에 저장되어 있는 값이 0이 아닐 경우 28로 이동한다. 바로 전 작업에서 i < 0xffff였기 때문에 v0이 1로 셋팅되어 있었다. 따라서 28로 이동한다.

28:
v0 <= 0(s8)
v0에 메모리 주소 0(s8)에 있는 값을 저장한다. 맨 처음 1c에서 0을 저장해두었으므로 v0에는 0이 저장된다.

2c:
Hazard를 피하기 위해 한 cycle을 쉰다.

30:
v0 <= v0 + 1
기존의 v0의 값에 1을 더해서 v0에 저장한다. 즉, i++를 하는 과정이다.

34:
0(s8) <= v0
30에서 더해진 결과를 메모리 주소 0(s8)에 저장해준다. 새로 변경된 i값을 업데이트 해주는 과정이다.

이후 38부터는 다시 위의 과정이 반복된다. 40에서 slt 인스트럭션에 의해 v0이 0으로 셋팅될 때까지 반복되다가 반복문을 빠져나와 프로그램이 종료된다.

댓글 없음:

댓글 쓰기