c언어 코드를 goto 버전으로 향상시켜봄
.L2 == loop
jne : ZF 가 1이 아니면 jump를 한다. 즉, x가 0이 아니라면 점프를 한다.
while 문이 do-while 보다 비효율적이다!
while 문 동작과정 : 아래 그림을 보듯이, 맨 처음부터 아무것도 안했는데 test 로 goto 를 하고(jump 를 하고) test 과 통과하면 loop 로 또 goto 를 하고 그제서야 body 를 수행한다.
이러한 while 문르 동작 구조를 "jump - to - middle" 이라고 한다.
1) 아래와 같은 c언어 while문 코드가 있을떄,
2) 컴파일러와 아래와 같이 do-while 문으로 바꿔버린다.
3) 위의 do-while 문을 컴파일하면 어셈블리의 goto 버전으로 바꾸면 아래와 같다.
코드 실행 초기에 jump 를 여러번 뛰던 기존의 while문 보다 효율적인 코드로 개선되었음을 알 수 있다!
향상된 while문은 맨 처음에 if문을 통해 Test 과정을 맨 앞에서 걸쳐감으로써 jump 을 할 필요가 없게 만들어졌다!
for(init; Test; Update) // == for(초기값; 조건문; 증감문)
Body
예제
for문의 컴파일 과정
1 ) while 문으로 변환
2 ) do-while 문으로 변환
3 ) goto 문으로 변환
1) 컴파일러가 컴파일시 for 문을 보자마자 while 문으로 변환한다.
위 그림에 대한 예제를 보면 아래와 같다.
2) 위에서 설명했듯이 while 문은 do-while 문에 비해 비효율적이라서,
컴파일러가 기존의 while 문을 do-while 문으로 변환하고 또 컴파일에서 어셈블리의 goto 버전으로 변환한다.
구조
init
if(!Test)
goto done;
loop:
Body
update
if(Test)
goto loop;
done:
cf ) 초기의 test 부분은 optimize 하는 옵션에 따라서 지워질 수 있다!
(=> "-O1", "-O2" 등에서 1, 2 와 같이 부여되는 옵션의 번호에 따라서 지워질 수가 있음)
switch 문은 jump table 이라는 것이 필요하다.
swtich 문의 각 case 별로 각 Code Block (Body 내용) 을 가지고 있다.
아래 그림의 switch문에서 x의 값에 따라서 다른 jump target 으로 jump 를 해서 code block 를 읽어야한다.
( jump target 이란, 각 case 에 대한 code block 을 가지고있는 메모리임 )
어디로 jump 를 뛰어야할지를 가지고 있는 것이 jump table 이다.
즉, jump table == address table
- jump target 메모리들의 주소값을 저장하는(가리키는) 테이블
(즉 포인터 테이블임)
위와 같은 c언어 코드를 컴파일하면 아래와 같아진다.
cmpq : $6, %rdi : case가 6까지만 존재했었다. x가 6을 넘는지 아닌지를 비교한다.
ja .L8 : x가 6보다 크면 .L8 (default)이라는 곳으로 점프하라는 뜻
=> switch 문에서 default 임
jmp : *.L4(,%rdi,8) : x가 6보다 작거나 같으면 case 6개중에 하나이므로,
"8x + *.L4" 로 계산된 메모리 주소로 점프한다.
=> 이때 L4 란 jump table 의 시작주소를 의미
1) Direct : 점프 뛰고 바로 주소주는 것
ex) jump .L8
2) inDirect : 점프를 하는데 address 를 계산하고 그 주소로 뛰는 것
ex) jmp *.L4(, %rdi, 8)
imulq : %rdx %rax 를 곱하면 그 결과가 rax 레지스터에 리턴됨(저장됨)
case 2는 break 문이 없으므로 return 하는 값이 없이 바로 case 3로 어가서 case 3로 수행한다.