[C++] arm assembly 에서 본 virtual 여부차이

YumeIroVillain·2022년 7월 25일
0

개발노트

목록 보기
15/30

온라인 C++ 컴파일러
온라인 ARM 어셈블러

virtual 기재시

/******************************************************************************

                              Online C++ Compiler.
               Code, Compile, Run and Debug C++ program online.
Write your code in this editor and press "Run" button to compile and execute it.

*******************************************************************************/

#include <iostream>

using namespace std;

class Parent
{
    public:
        virtual void call() {
        // void call() {
            printf("Hello Parent!\n");
        }
};

class Child : public Parent {
    public:
        void call(){
            printf("Hello Child!\n");
        }
};

class Child2 : public Parent {
    public:
        void call(){
            printf("Hello Child2!\n");
        }
};

void importer(Parent* child){
    child->call();
}

int main()
{
    // Parent *A; // 가능
    // Parent *A = new Parent(); //에러
    Parent* A = new Child();
    Parent* B = new Child2();
    importer(A);
    importer(B);
    Child* C = new Child();
    Child2* D = new Child2();
    importer(C);
    importer(D);
    printf("Done.\n");
    return 0;
}
.LC0:
        .ascii  "Hello Parent!\000"
Parent::call():
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        movw    r0, #:lower16:.LC0
        movt    r0, #:upper16:.LC0
        bl      puts
        nop
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
.LC1:
        .ascii  "Hello Child!\000"
Child::call():
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        movw    r0, #:lower16:.LC1
        movt    r0, #:upper16:.LC1
        bl      puts
        nop
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
.LC2:
        .ascii  "Hello Child2!\000"
Child2::call():
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        movw    r0, #:lower16:.LC2
        movt    r0, #:upper16:.LC2
        bl      puts
        nop
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
importer(Parent*):
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        ldr     r3, [r7, #4]
        ldr     r3, [r3]
        ldr     r3, [r3]
        ldr     r0, [r7, #4]
        blx     r3
        nop
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
Parent::Parent() [base object constructor]:
        push    {r7}
        sub     sp, sp, #12
        add     r7, sp, #0
        str     r0, [r7, #4]
        ldr     r2, .L7
        ldr     r3, [r7, #4]
        str     r2, [r3]
        ldr     r3, [r7, #4]
        mov     r0, r3
        adds    r7, r7, #12
        mov     sp, r7
        ldr     r7, [sp], #4
        bx      lr
.L7:
        .word   vtable for Parent+8
Child::Child() [base object constructor]:
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        ldr     r3, [r7, #4]
        mov     r0, r3
        bl      Parent::Parent() [base object constructor]
        ldr     r2, .L11
        ldr     r3, [r7, #4]
        str     r2, [r3]
        ldr     r3, [r7, #4]
        mov     r0, r3
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
.L11:
        .word   vtable for Child+8
Child2::Child2() [base object constructor]:
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        ldr     r3, [r7, #4]
        mov     r0, r3
        bl      Parent::Parent() [base object constructor]
        ldr     r2, .L15
        ldr     r3, [r7, #4]
        str     r2, [r3]
        ldr     r3, [r7, #4]
        mov     r0, r3
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
.L15:
        .word   vtable for Child2+8
.LC3:
        .ascii  "Done.\000"
main:
        push    {r4, r7, lr}
        sub     sp, sp, #12
        add     r7, sp, #0
        movs    r0, #4
        bl      operator new(unsigned int)
        mov     r3, r0
        mov     r4, r3
        movs    r3, #0
        str     r3, [r4]
        mov     r0, r4
        bl      Child::Child() [complete object constructor]
        str     r4, [r7, #4]
        movs    r0, #4
        bl      operator new(unsigned int)
        mov     r3, r0
        mov     r4, r3
        movs    r3, #0
        str     r3, [r4]
        mov     r0, r4
        bl      Child2::Child2() [complete object constructor]
        str     r4, [r7]
        ldr     r0, [r7, #4]
        bl      importer(Parent*)
        ldr     r0, [r7]
        bl      importer(Parent*)
        movw    r0, #:lower16:.LC3
        movt    r0, #:upper16:.LC3
        bl      puts
        movs    r3, #0
        mov     r0, r3
        adds    r7, r7, #12
        mov     sp, r7
        pop     {r4, r7, pc}
vtable for Child2:
        .word   0
        .word   typeinfo for Child2
        .word   Child2::call()
vtable for Child:
        .word   0
        .word   typeinfo for Child
        .word   Child::call()
vtable for Parent:
        .word   0
        .word   typeinfo for Parent
        .word   Parent::call()
typeinfo for Child2:
        .word   _ZTVN10__cxxabiv120__si_class_type_infoE+8
        .word   typeinfo name for Child2
        .word   typeinfo for Parent
typeinfo name for Child2:
        .ascii  "6Child2\000"
typeinfo for Child:
        .word   _ZTVN10__cxxabiv120__si_class_type_infoE+8
        .word   typeinfo name for Child
        .word   typeinfo for Parent
typeinfo name for Child:
        .ascii  "5Child\000"
typeinfo for Parent:
        .word   _ZTVN10__cxxabiv117__class_type_infoE+8
        .word   typeinfo name for Parent
typeinfo name for Parent:
        .ascii  "6Parent\000"
__static_initialization_and_destruction_0(int, int):
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        str     r1, [r7]
        ldr     r3, [r7, #4]
        cmp     r3, #1
        bne     .L21
        ldr     r3, [r7]
        movw    r2, #65535
        cmp     r3, r2
        bne     .L21
        movw    r0, #:lower16:_ZStL8__ioinit
        movt    r0, #:upper16:_ZStL8__ioinit
        bl      std::ios_base::Init::Init() [complete object constructor]
        movw    r2, #:lower16:__dso_handle
        movt    r2, #:upper16:__dso_handle
        movw    r1, #:lower16:_ZNSt8ios_base4InitD1Ev
        movt    r1, #:upper16:_ZNSt8ios_base4InitD1Ev
        movw    r0, #:lower16:_ZStL8__ioinit
        movt    r0, #:upper16:_ZStL8__ioinit
        bl      __aeabi_atexit
.L21:
        nop
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
_GLOBAL__sub_I_importer(Parent*):
        push    {r7, lr}
        add     r7, sp, #0
        movw    r1, #65535
        movs    r0, #1
        bl      __static_initialization_and_destruction_0(int, int)
        pop     {r7, pc}

보다시피 Child::call() 에 대한 라벨이 제작됨을 알 수 있다.


virtual 미기재시

/******************************************************************************

                              Online C++ Compiler.
               Code, Compile, Run and Debug C++ program online.
Write your code in this editor and press "Run" button to compile and execute it.

*******************************************************************************/

#include <iostream>

using namespace std;

class Parent
{
    public:
        // virtual void call() {
        void call() {
            printf("Hello Parent!\n");
        }
};

class Child : public Parent {
    public:
        void call(){
            printf("Hello Child!\n");
        }
};

class Child2 : public Parent {
    public:
        void call(){
            printf("Hello Child2!\n");
        }
};

void importer(Parent* child){
    child->call();
}

int main()
{
    // Parent *A; // 가능
    // Parent *A = new Parent(); //에러
    Parent* A = new Child();
    Parent* B = new Child2();
    importer(A);
    importer(B);
    Child* C = new Child();
    Child2* D = new Child2();
    importer(C);
    importer(D);
    printf("Done.\n");
    return 0;
}
.LC0:
        .ascii  "Hello Parent!\000"
Parent::call():
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        movw    r0, #:lower16:.LC0
        movt    r0, #:upper16:.LC0
        bl      puts
        nop
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
importer(Parent*):
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        ldr     r0, [r7, #4]
        bl      Parent::call()
        nop
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
.LC1:
        .ascii  "Done.\000"
main:
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        movs    r0, #1
        bl      operator new(unsigned int)
        mov     r3, r0
        str     r3, [r7, #4]
        movs    r0, #1
        bl      operator new(unsigned int)
        mov     r3, r0
        str     r3, [r7]
        ldr     r0, [r7, #4]
        bl      importer(Parent*)
        ldr     r0, [r7]
        bl      importer(Parent*)
        movw    r0, #:lower16:.LC1
        movt    r0, #:upper16:.LC1
        bl      puts
        movs    r3, #0
        mov     r0, r3
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
__static_initialization_and_destruction_0(int, int):
        push    {r7, lr}
        sub     sp, sp, #8
        add     r7, sp, #0
        str     r0, [r7, #4]
        str     r1, [r7]
        ldr     r3, [r7, #4]
        cmp     r3, #1
        bne     .L7
        ldr     r3, [r7]
        movw    r2, #65535
        cmp     r3, r2
        bne     .L7
        movw    r0, #:lower16:_ZStL8__ioinit
        movt    r0, #:upper16:_ZStL8__ioinit
        bl      std::ios_base::Init::Init() [complete object constructor]
        movw    r2, #:lower16:__dso_handle
        movt    r2, #:upper16:__dso_handle
        movw    r1, #:lower16:_ZNSt8ios_base4InitD1Ev
        movt    r1, #:upper16:_ZNSt8ios_base4InitD1Ev
        movw    r0, #:lower16:_ZStL8__ioinit
        movt    r0, #:upper16:_ZStL8__ioinit
        bl      __aeabi_atexit
.L7:
        nop
        adds    r7, r7, #8
        mov     sp, r7
        pop     {r7, pc}
_GLOBAL__sub_I_importer(Parent*):
        push    {r7, lr}
        add     r7, sp, #0
        movw    r1, #65535
        movs    r0, #1
        bl      __static_initialization_and_destruction_0(int, int)
        pop     {r7, pc}

보다시피, 애초에 아예 Child::call() 이라는 라벨자체가 만들어지지 않는다.
즉, virtual 키워드 없는 부모메소드는 자식에서 오버라이딩이 "불가함" 을 알 수 있다.

profile
HW SW 둘다 공부하는 혼종의 넋두리 블로그 / SKKU SSE 17 / SWM 11th

0개의 댓글