CPU는 가장 최근의 arithmetic, logical operation을 설명하는 single-bit 조건 코드(condition code) 레지스터들을 운영
// t = a + b;를 수행하기 위해 ADD 인스트럭션 사용
(unsigned) t < (unsigned) // CF: a Unsigned overflow
(t == 0) // ZF: Zero
(t < 0) // SF: Negative
(a < 0 == b < 0) && (t < 0 != a < 0) // OF: Signed overflow
testq %rax,%rax
testb $0x02,%al
: %al의 두 번째 비트(0x02 -> 0000 0010)가 1이 아니면 ZF를 1로 설정# int comp(data_t a, data_t b)
# a in %rdi, b in %rsi
comp:
cmpq %rsi, %rdi # Compare a:b
setl %al # Set low-order byte of %eax to 0 or 1
movzbl %al, %eax # Clear rest of %eax (and rest of %rax)
ret
4004d0: 48 89 f8 mov %rdi,%rax
4004d3: eb 03 jmp 4004d8 <loop+0x8>
4004d5: 48 d1 f8 sar %rax
4004d8: 48 85 c0 test %rax,%rax
4004db: 7f f8 jg 4004d5 <loop+0x5>
4004dd: f3 c3 repz retq
위와 같이 상대 주소 사용시 링커 단계 후 인스트럭션들이 다른 주소에 재배치 되어도 점프 목적지 값은 바뀌지 않음
if문을 conditional branch를 이용한 machine code를 C로 나타낸 코드
// if statement
if (test-expr)
then-statement
else
else-statement
// translate using conditional branches
t = test-expr;
if (!t)
goto false;
then-statement
goto done;
false:
else-statement
done:
else-statement
와 then-statement
에 대해 별도의 코드 블록을 생성함// general form of conditional expression
v = test-expr ? then-expr : else-expr;
// The standard way to compile this expression using conditional control
if (!test-expr)
goto false;
v = then-expr;
goto done;
false:
v = else-expr;
done:
// using condtional move
v = then-expr;
ve = else-expr;
t = test-expr;
if (!t) v = ve;
then-expr
과 else-expr
이 모두 계산된 후 test-expr
의 계산 결과에 따라 최종 jump 목적지가 결정됨val = Test(x) ? Hard1(x) : Hard2(x);
Hard1(x)
와 Hard2(x)
두 코드가 모두 수행되어 계산 비용이 많이 듦val = p ? *p : 0;
p
가 null
인 경우에도 먼저 포인터 p
가 가리키는 값 *p
를 역참조 하려고함long cread(long *xp) {
return (xp ? *xp : 0);
}
# long cread(long *xp)
# Invalid implementation of function cread
# xp in register %rdi
cread:
movq (%rdi), %rax # v = *xp
testq %rdi, %rdi # Test x
movl $0, %edx # Set ve = 0
cmove %rdx, %rax # If x==0, v = ve
ret Return v
xp
가 null
이여도 movq (%rdi), %rax
을 먼저 수행해 null 포인터 역참조 오류가 발생val = x > 0 ? x*=7 : x+=3;
x*=7
과 x+=3
이 x
의 값을 바꾸는 side effect 발생then-expr
과 else-expr
이 test-expr
에 값을 바꾸어 side effect를 발생시킴C에서 do-while
, while
, for
에 해당하는 직접적인 machine code 인스트럭션은 없지만, conditional test/jump를 함께 사용해서 반복문을 구현함
// general form
do
body-statement
while (test-expr);
// translate into goto statement
loop:
body-statement
t = test-expr;
if (t)
goto loop;
body-statement
가 적어도 한 번은 실행됨// C code
long fact_do(long n) {
long result = 1;
do {
result *= n;
n = n-1;
} while (n > 1);
return result;
}
// Equivalent goto version
long fact_do_goto(long n) {
long result = 1;
loop:
result *= n;
n = n-1;
if (n > 1)
goto loop;
return result;
}
# Corresponding assembly-language code
# long fact_do(long n)
# n in %rdi
fact_do:
movl $1, %eax # Set result = 1
.L2: # loop:
imulq %rdi, %rax # Compute result *= n
subq $1, %rdi # Decrement n
cmpq $1, %rdi # Compare n:1
jg .L2 # If >, goto loop
rep; ret # Return
// general form
while (test-expr)
body-statement
test-expr
을 먼저 계산해서 body-statement
를 실행하지 않을 수 있음// translate into goto statement
goto test;
loop:
body-statement
test:
t = test-expr;
if (t)
goto loop;
// C code
long fact_while(long n) {
long result = 1;
while (n > 1) {
result *= n;
n = n-1;
}
return result;
}
// Equivalent goto version
long fact_while_jm_goto(long n) {
long result = 1;
goto test;
loop:
result *= n;
n = n-1;
test:
if (n > 1)
goto loop;
return result;
}
# Corresponding assembly-language code
# long fact_while(long n)
# n in %rdi
fact_while:
movl $1, %eax # Set result = 1
jmp .L5 # Goto test
.L6: # loop:
imulq %rdi, %rax # Compute result *= n
subq $1, %rdi # Decrement n
.L5: # test:
cmpq $1, %rdi # Compare n:1
jg .L6 # If >, goto loop
rep; ret # Return
// translate into do-while statement
t = test-expr;
if (!t)
goto done;
do
body-statement
while (test-expr);
done:
// translate into goto statement
t = test-expr;
if (!t)
goto done;
// C code
long fact_while(long n) {
long result = 1;
while (n > 1) {
result *= n;
n = n-1;
}
return result;
}
// Equivalent goto version
long fact_while_gd_goto(long n) {
long result = 1;
if (n <= 1)
goto done;
loop:
result *= n;
n = n-1;
if (n != 1)
goto loop;
done:
return result;
}
# Corresponding assembly-language code
# long fact_while(long n)
# n in %rdi
fact_while:
cmpq $1, %rdi # Compare n:1
jle .L7 # If <=, goto done
movl $1, %eax # Set result = 1
.L6: # loop:
imulq %rdi, %rax # Compute result *= n
subq $1, %rdi # Decrement n
cmpq $1, %rdi # Compare n:1
jne .L6 # If !=, goto loop
rep; ret # Return
.L7: # done:
movl $1, %eax # Compute result = 1
ret # Return
if (n != 1)
인 이유는 루프가 n > 1 일 때만 진입 가능해 if (n > 1)
과 동일함// general form
for (init-expr; test-expr; update-expr)
body-statement
// translate into while statement
init-expr;
while (test-expr) {
body-statement
update-expr;
}
// using jump to middle
init-expr;
goto test;
loop:
body-statement
update-expr;
test:
t = test-expr;
if (t)
goto loop;
// using guarded do
init-expr;
t = test-expr;
if (!t)
goto done;
loop:
body-statement
update-expr;
t = test-expr;
if (t)
goto loop;
done:
long fact_for(long n) {
long i;
long result = 1;
for (i = 2; i <= n; i++)
result *= i;
return result;
}
// translate for loop into while statement
long fact_for_while(long n) {
long i = 2;
long result = 1;
while (i <= n) {
result *= i;
i++;
}
return result;
}
// translate while loop into goto statement
long fact_for_jm_goto(long n) {
long i = 2;
long result = 1;
goto test;
loop:
result *= i;
i++;
test:
if (i <= n)
goto loop;
return result;
}
# long fact_for(long n)
# n in %rdi
fact_for:
movl $1, %eax # Set result = 1
movl $2, %edx # Set i = 2
jmp .L8 # Goto test
.L9: # loop:
imulq %rdx, %rax # Compute result *= i
addq $1, %rdx # Increment i
.L8: # test:
cmpq %rdi, %rdx # Compare i:n
jle .L9 # If <=, goto loop
rep; ret # Return
-Og
옵션을 이용해 생성한 어셈블리 코드// switch statement
void switch_eg(long x, long n, long *dest) {
long val = x;
switch (n) {
case 100:
val *= 13;
break;
case 102:
val += 10;
/* Fall through */
case 103:
val += 11;
break;
case 104:
case 106:
val *= val;
break;
default:
val = 0;
}
*dest = val;
}
// translate into extended C
void switch_eg_impl(long x, long n, long *dest) {
/* Table of code pointers */
static void *jt[7] = {
&&loc_A, &&loc_def, &&loc_B,
&&loc_C, &&loc_D, &&loc_def,
&&loc_D
};
unsigned long index = n - 100;
long val;
if (index > 6)
goto loc_def;
/* Multiway branch */
goto *jt[index];
loc_A: /* Case 100 */
val = x * 13;
goto done;
loc_B: /* Case 102 */
x = x + 10;
/* Fall through */
loc_C: /* Case 103 */
val = x + 11;
goto done;
loc_D: /* Cases 104, 106 */
val = x * x;
goto done;
loc_def: /* Default case */
val = 0;
done:
*dest = val;
}
jt
에 각 레이블 주소를 원소로 저장n - 100
을 해서 범위를 0~6 사이로 만들어 unsigned long 타입 index
에 저장index
가 0~6 범위에 벗어나는 지를 6을 초과하는지 시험하는 방식으로 수행(unsigned)index
가 6을 초과하면 goto문을 이용해 loc_def
(Default case)로 점프# void switch_eg(long x, long n, long *dest)
# x in %rdi, n in %rsi, dest in %rdx
switch_eg:
subq $100, %rsi # Compute index = n-100
cmpq $6, %rsi # Compare index:6
ja .L8 # If >, goto loc_def
jmp *.L4(,%rsi,8) # Goto *jg[index]
.L3: # loc_A:
leaq (%rdi,%rdi,2), %rax # 3*x
leaq (%rdi,%rax,4), %rdi # val = 13*x
jmp .L2 # Goto done
.L5: # loc_B:
addq $10, %rdi # x = x + 10
.L6: # loc_C:
addq $11, %rdi # val = x + 11
jmp .L2 # Goto done
.L7: # loc_D:
imulq %rdi, %rdi # val = x * x
jmp .L2 # Goto done
.L8: # loc_def:
movl $0, %edi # val = 0
.L2: # done:
movq %rdi, (%rdx) # *dest = val
ret # Return
# jump tables
.section .rodata
.align # 8 Align address to multiple of 8
.L4:
.quad .L3 # Case 100: loc_A
.quad .L8 # Case 101: loc_def
.quad .L5 # Case 102: loc_B
.quad .L6 # Case 103: loc_C
.quad .L7 # Case 104: loc_D
.quad .L8 # Case 105: loc_def
.quad .L7 # Case 106: loc_D
jmp *.L4(,%rsi,8)
%rsi
에는 인덱스가 저장되어 있음%rsi
에 8을 곱함*
: 주소로 간접 점프(indirect jump)break
문이 없어 goto문이 없음(jump하지 않음)