예제 코드
// switch example in C long switch_eg(long x, long y, long z) { long w = 1; switch(x) { case 1: w = y*z; break; case 2: w = y/z; case 3: w += z; break; case 5: case 6: w -= z; break; default : w = 2; } return w; }
Jump Table
switch statement의 각 case에 대한 주소를 저장하는 배열.
코드는 점프테이블의 주소로 간접 점프하여 타겟 코드블록으로 이동한다.
(switch -> jump table -> code block)
// jumptable example in assembly
.section .rodata
.align 8
.L4 :
.quad .L8 // x = 0
.quad .L3 // x = 1
.quad .L5 // x = 2
.quad .L9 // x = 3
.quad .L8 // x = 4, 위 코드에서는 missing case
.quad .L7 // x = 5
.quad .L7 // x = 6
각 타겟은 8bytes이고 .L4에 base address를 두고있다.
x=0과 x=4 모두 default 주소로 점프한다.
이처럼 switch jump table은 missing case도 모두 고려하여 작성되기 때문에 switch문에 조건으로 들어갈 항목은 되도록이면 순차적인 값이 효율적이다.
- 직접 점프
jmp .L8.L8 label로 표시된 타겟 주소로 점프한다.
- 간접 점프
jmp *.L4(, %rdi, 8)base adress 기준 8*x(주소는 8bytes이기 때문) 만큼 더해진 주소로 점프한다.
Fall-through case
... long w = 1; switch (x) { ... case 2: w = y/z; case 3: w += z; break; ... } }case 2를 보면 수행 후 break를 통해 switch문을 탈출하지 않고 case 3으로 넘어간다.
switch문 전에 초기화 된 w값은 1이지만, case 2를 거쳐 수행된 case 3의 w 값은 1이 아니다.
그러나 case 3 단독 점프라면 w의 값은 1이어야 한다.
이런 혼란을 막기 위해 내부적으로 fall-through는 다음과 같이 동작한다.// fall-through handling in C case 2: w = y/z; goto merge; case 3: w = 1; merge : w += z;// fall-through handling in Assembly .L5: // Case 2 movq %rsi, %rax // 나눠지는 수 %rax로 복사 cqto // %rax에 있는 64비트 signed int를 128비트 signed bit로 확장 // 확장된 값이 RDX에 저장됨 idivq %rcx // y/z, 나눗셈 결과는 %rax에 저장 jmp .L6 // goto merge .L9: // Case 3 movl $1, %eax // w = 1 .L6: // merge: addq %rcx, %rax // w += z ret
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
안성용, "시스템소프트웨어", 부산대학교