while(1) work();
article thumbnail
반응형

개요

while(1)과 while(2) 중 누가 더 빠를까?

 

당연히 같지 않나? 라는 생각이 들면서도

 

(variable == 0) 을 판별하려면 variable의 좌측 비트부터 하나씩 확인해보며 모두 0인지 확인해야 하는 것 처럼

 

while(0b000000000...01) 과 while(0b000000000...10) 이다 보니

좌측에서부터 비트가 0인지 확인하는 원리라면 while(2)가 더 빠를수도 있지 않을까? 싶었다.

(while(1)보다 while(2)가 비트 "1"이 더 먼저 나오기 때문에 비교 연산 시 우위를 가져서)

 

하지만... 최근 C 컴파일러의 성능은 매우 뛰어나기 때문에 최적화로 인해 결국 같은 이진 코드를 가질 것 이라는 가설을 세우고 확인해보았다.

 

코드와 환경

Ubuntu 20.04 에서 gcc 9.4.0 버전을 사용했다.

아래 세 가지 코드를 아무 옵션도 주지 않고 gcc로 컴파일했다.

//1번 코드
int main() {
    int i = 0;

    while (1) {
        i++;
    }

    return 1;
}

//2번 코드
int main() {
    int i = 0;

    while (2) {
        i++;
    }

    return 1;
}

//3번 코드
int main() {
    int i = 0;

    for (;;) {
        i++;
    }

    return 1;
}

 

for(;;) 도 동일하게 컴파일 되는지 궁금해서 추가하였고,

반복문 내에서 무의미한 연산이 일어나도록 하였다.

컴파일 결과 해시 비교

sha1로 파일을 해시해보니 아래와 같은 결과가 나왔다.

1번 코드 : 1f17c26017ca3cdccbb159d03de9633aec177836

2번 코드 : acc6b251c3263835a4513548f02c52c4bf3e41c0

3번 코드 : 46aba440b660730cf6d6e1723cf219bc39233c32

 

어쩌면 결과가 다를 수도 있겠는데? 라는 생각이 들었다.

 

objdump 결과 비교

objdump를 이용해 컴파일된 세 파일을 비교해보았다.

Disassembly of section .init:

0000000000001000 <_init>:
    1000:       f3 0f 1e fa             endbr64
    1004:       48 83 ec 08             sub    $0x8,%rsp
    1008:       48 8b 05 d9 2f 00 00    mov    0x2fd9(%rip),%rax        # 3fe8 <__gmon_start__>
    100f:       48 85 c0                test   %rax,%rax
    1012:       74 02                   je     1016 <_init+0x16>
    1014:       ff d0                   callq  *%rax
    1016:       48 83 c4 08             add    $0x8,%rsp
    101a:       c3                      retq

Disassembly of section .plt:

0000000000001020 <.plt>:
    1020:       ff 35 a2 2f 00 00       pushq  0x2fa2(%rip)        # 3fc8 <_GLOBAL_OFFSET_TABLE_+0x8>
    1026:       f2 ff 25 a3 2f 00 00    bnd jmpq *0x2fa3(%rip)        # 3fd0 <_GLOBAL_OFFSET_TABLE_+0x10>
    102d:       0f 1f 00                nopl   (%rax)

Disassembly of section .plt.got:

0000000000001030 <__cxa_finalize@plt>:
    1030:       f3 0f 1e fa             endbr64
    1034:       f2 ff 25 bd 2f 00 00    bnd jmpq *0x2fbd(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
    103b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

Disassembly of section .text:

0000000000001040 <_start>:
    1040:       f3 0f 1e fa             endbr64
    1044:       31 ed                   xor    %ebp,%ebp
    1046:       49 89 d1                mov    %rdx,%r9
    1049:       5e                      pop    %rsi
    104a:       48 89 e2                mov    %rsp,%rdx
    104d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
    1051:       50                      push   %rax
    1052:       54                      push   %rsp
    1053:       4c 8d 05 56 01 00 00    lea    0x156(%rip),%r8        # 11b0 <__libc_csu_fini>
    105a:       48 8d 0d df 00 00 00    lea    0xdf(%rip),%rcx        # 1140 <__libc_csu_init>
    1061:       48 8d 3d c1 00 00 00    lea    0xc1(%rip),%rdi        # 1129 <main>
    1068:       ff 15 72 2f 00 00       callq  *0x2f72(%rip)        # 3fe0 <__libc_start_main@GLIBC_2.2.5>
    106e:       f4                      hlt
    106f:       90                      nop

0000000000001070 <deregister_tm_clones>:
    1070:       48 8d 3d 99 2f 00 00    lea    0x2f99(%rip),%rdi        # 4010 <__TMC_END__>
    1077:       48 8d 05 92 2f 00 00    lea    0x2f92(%rip),%rax        # 4010 <__TMC_END__>
    107e:       48 39 f8                cmp    %rdi,%rax
    1081:       74 15                   je     1098 <deregister_tm_clones+0x28>
    1083:       48 8b 05 4e 2f 00 00    mov    0x2f4e(%rip),%rax        # 3fd8 <_ITM_deregisterTMCloneTable>
    108a:       48 85 c0                test   %rax,%rax
    108d:       74 09                   je     1098 <deregister_tm_clones+0x28>
    108f:       ff e0                   jmpq   *%rax
    1091:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    1098:       c3                      retq
    1099:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

00000000000010a0 <register_tm_clones>:
    10a0:       48 8d 3d 69 2f 00 00    lea    0x2f69(%rip),%rdi        # 4010 <__TMC_END__>
    10a7:       48 8d 35 62 2f 00 00    lea    0x2f62(%rip),%rsi        # 4010 <__TMC_END__>
    10ae:       48 29 fe                sub    %rdi,%rsi
    10b1:       48 89 f0                mov    %rsi,%rax
    10b4:       48 c1 ee 3f             shr    $0x3f,%rsi
    10b8:       48 c1 f8 03             sar    $0x3,%rax
    10bc:       48 01 c6                add    %rax,%rsi
    10bf:       48 d1 fe                sar    %rsi
    10c2:       74 14                   je     10d8 <register_tm_clones+0x38>
    10c4:       48 8b 05 25 2f 00 00    mov    0x2f25(%rip),%rax        # 3ff0 <_ITM_registerTMCloneTable>
    10cb:       48 85 c0                test   %rax,%rax
    10ce:       74 08                   je     10d8 <register_tm_clones+0x38>
    10d0:       ff e0                   jmpq   *%rax
    10d2:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
    10d8:       c3                      retq
    10d9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

00000000000010e0 <__do_global_dtors_aux>:
    10e0:       f3 0f 1e fa             endbr64
    10e4:       80 3d 25 2f 00 00 00    cmpb   $0x0,0x2f25(%rip)        # 4010 <__TMC_END__>
    10eb:       75 2b                   jne    1118 <__do_global_dtors_aux+0x38>
    10ed:       55                      push   %rbp
    10ee:       48 83 3d 02 2f 00 00    cmpq   $0x0,0x2f02(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
    10f5:       00
    10f6:       48 89 e5                mov    %rsp,%rbp
    10f9:       74 0c                   je     1107 <__do_global_dtors_aux+0x27>
    10fb:       48 8b 3d 06 2f 00 00    mov    0x2f06(%rip),%rdi        # 4008 <__dso_handle>
    1102:       e8 29 ff ff ff          callq  1030 <__cxa_finalize@plt>
    1107:       e8 64 ff ff ff          callq  1070 <deregister_tm_clones>
    110c:       c6 05 fd 2e 00 00 01    movb   $0x1,0x2efd(%rip)        # 4010 <__TMC_END__>
    1113:       5d                      pop    %rbp
    1114:       c3                      retq
    1115:       0f 1f 00                nopl   (%rax)
    1118:       c3                      retq
    1119:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

0000000000001120 <frame_dummy>:
    1120:       f3 0f 1e fa             endbr64
    1124:       e9 77 ff ff ff          jmpq   10a0 <register_tm_clones>

0000000000001129 <main>:
    1129:       f3 0f 1e fa             endbr64
    112d:       55                      push   %rbp
    112e:       48 89 e5                mov    %rsp,%rbp
    1131:       c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
    1138:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
    113c:       eb fa                   jmp    1138 <main+0xf>
    113e:       66 90                   xchg   %ax,%ax

0000000000001140 <__libc_csu_init>:
    1140:       f3 0f 1e fa             endbr64
    1144:       41 57                   push   %r15
    1146:       4c 8d 3d a3 2c 00 00    lea    0x2ca3(%rip),%r15        # 3df0 <__frame_dummy_init_array_entry>
    114d:       41 56                   push   %r14
    114f:       49 89 d6                mov    %rdx,%r14
    1152:       41 55                   push   %r13
    1154:       49 89 f5                mov    %rsi,%r13
    1157:       41 54                   push   %r12
    1159:       41 89 fc                mov    %edi,%r12d
    115c:       55                      push   %rbp
    115d:       48 8d 2d 94 2c 00 00    lea    0x2c94(%rip),%rbp        # 3df8 <__do_global_dtors_aux_fini_array_entry>
    1164:       53                      push   %rbx
    1165:       4c 29 fd                sub    %r15,%rbp
    1168:       48 83 ec 08             sub    $0x8,%rsp
    116c:       e8 8f fe ff ff          callq  1000 <_init>
    1171:       48 c1 fd 03             sar    $0x3,%rbp
    1175:       74 1f                   je     1196 <__libc_csu_init+0x56>
    1177:       31 db                   xor    %ebx,%ebx
    1179:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    1180:       4c 89 f2                mov    %r14,%rdx
    1183:       4c 89 ee                mov    %r13,%rsi
    1186:       44 89 e7                mov    %r12d,%edi
    1189:       41 ff 14 df             callq  *(%r15,%rbx,8)
    118d:       48 83 c3 01             add    $0x1,%rbx
    1191:       48 39 dd                cmp    %rbx,%rbp
    1194:       75 ea                   jne    1180 <__libc_csu_init+0x40>
    1196:       48 83 c4 08             add    $0x8,%rsp
    119a:       5b                      pop    %rbx
    119b:       5d                      pop    %rbp
    119c:       41 5c                   pop    %r12
    119e:       41 5d                   pop    %r13
    11a0:       41 5e                   pop    %r14
    11a2:       41 5f                   pop    %r15
    11a4:       c3                      retq
    11a5:       66 66 2e 0f 1f 84 00    data16 nopw %cs:0x0(%rax,%rax,1)
    11ac:       00 00 00 00

00000000000011b0 <__libc_csu_fini>:
    11b0:       f3 0f 1e fa             endbr64
    11b4:       c3                      retq

Disassembly of section .fini:

00000000000011b8 <_fini>:
    11b8:       f3 0f 1e fa             endbr64
    11bc:       48 83 ec 08             sub    $0x8,%rsp
    11c0:       48 83 c4 08             add    $0x8,%rsp
    11c4:       c3                      retq

 

세 파일 모두 토씨 하나 틀리지 않고 동일하게 디컴파일 되었다.

어? 근데 해시는 왜 달랐지?

 

hex 비교

결국 이진 파일을 hex로 변환해 비교해 보았다.

정말.. 딱 한글자 다르더라...

심볼 영역을 생각하지 못했다.. 멍청해라...!

당연히 해쉬가 다를 것인데 ㅜㅜ ㅋㅋㅋㅋ

 

GCC에서 -s 옵션을 주어 심볼 영역을 제거하고 컴파일 했더니 동일한 해쉬가 나왔다.

 

결론

1. while(1) while(2) for(;;) 모두 동일하게 컴파일 된다!

2. 나는 굉장히 바보같았다! 새벽이라.. 새벽이라 그런걸꺼야..

반응형

'알고리즘 > TIP' 카테고리의 다른 글

O(1)로 비트 갯수 세는 알고리즘 세가지  (1) 2022.02.27
profile

while(1) work();

@유호건

❤️댓글은 언제나 힘이 됩니다❤️ 궁금한 점이나 잘못된 내용이 있다면 댓글로 남겨주세요.

검색 태그