두근두근 울렁울렁 가슴 뛰지만 무섭고도 두려워서 겁이 나지만 오늘 발견한 재미난 것 입니다 :)
발단은... 얼마 전 제가 사용하는 리눅스 배포본들 중 하나에 포함된 gcc 가 gcc-7.3.1 로 바뀌었습니다. 제가 사용하는 또 다른 배포본에서 gcc-6.4.0 으로 바뀐 뒤에도 상당히 오래동안 gcc-5.4.0 을 고집하다가 gcc-6 을 건너뛰고 gcc-7 로 가네요. 참고로, 현재 gcc 의 최신 시리즈는 8 입니다. 컴파일러가 달라졌으니 무엇이 바뀌는 것일까 궁금해졌습니다. 문서를 읽다가... 재미난 기능이 생겼더군요 :)
저는 어셈블리를 거의 모릅니다. 그렇지만 C 코드를 조금 변경하는 것이 어떤 영향을 줄까 궁금할 때 어셈블리로 출력해서 비교해보곤 해요. 예를 들어, -O0 옵션으로 최적화를 하지 않은 것과 -O2 옵션으로 최적화하는 것의 차이가 뭘까 궁금할 때 디버거까지 쓸 필요는 없겠죠. 만일, file.c 라는 C 코드를 file.s 라는 어셈블리 코드로 보고 싶다면 다음과 같은 명령을 내리면 됩니다. (최적화 옵션을 추가로 줘도 되겠죠.)
gcc -c file.c -o file.s -s -S
새로운 옵션으로
-fverbose-asm
이 생겼다네요. 예를 들어, C 코드가 아래와 같다면
int test (int n)
{
int i;
int total = 0;
for (i = 0; i < n; i++)
total += i * i;
return total;
}
다음과 같은 형식으로 변환해준다고 합니다. (이 예는 x86_64 에서 크기 최적화 옵션인 -Os 를 준 경우입니다.)
.text
.globl test
.type test, @@function
test:
.LFB0:
.cfi_startproc
# example.c:4: int total = 0;
xorl %eax, %eax # <retval>
# example.c:6: for (i = 0; i < n; i++)
xorl %edx, %edx # i
.L2:
# example.c:6: for (i = 0; i < n; i++)
cmpl %edi, %edx # n, i
jge .L5 #,
# example.c:7: total += i * i;
movl %edx, %ecx # i, tmp92
imull %edx, %ecx # i, tmp92
# example.c:6: for (i = 0; i < n; i++)
incl %edx # i
# example.c:7: total += i * i;
addl %ecx, %eax # tmp92, <retval>
jmp .L2 #
.L5:
# example.c:10: }
ret
.cfi_endproc