从汇编角度理解C++虚函数表

面试题分析 - 从汇编角度理解虚函数与虚表

前言:

最近在逛群的时候遇到群友的一个面试题感觉很有趣这里记录一下分析过程

问题:以下程序能否正常编译运行,如果能运行输出什么

class A {
public:
    void f1 () {
        printf ("A::f1\n");
    }
    virtual void f2 () {
        printf ("A::f2\n");
    }
};

class B {
public:
    virtual void f1 () {
        printf ("B::f1\n");
    } 
    virtual void f2 () {
        printf ("B::f2\n");
    }
};

int main () {
    B b;
    A *p = (A *)&b;
    p->f1 ();
    p->f2 ();
}

分析

环境:

编译环境:wsl

工具:gcc gdb

详细分析

首先,通过gdb运行程序, 我们把程序断点到29行

请添加图片描述

通过查看汇编 29行主要做了两个事情 初始化b的vptr ,来看一下两段汇编代码
lea 0xb445(%rip),%rax 将虚表地址存入 寄存器 rax
%rax,-0x18(%rbp) 将 虚表地址存入 寄存器rbp 偏移 -0x18的地址出 可以看出这里就是b的首地址也是vpt的地址,这里将vpt指向了虚表
在这里插入图片描述

然后再看第30行, 将a指向 b的地址

在这里插入图片描述

再看第31行 这里开始调用类A的f1函数,由于类A的f1不是虚函数所以并不会在编译后不会查询虚表而是直接调用 .text段的函数

在这里插入图片描述

最后再看调用A的f2函数,通过汇编可以看到

mov -0x10(%rbp),%rax 这里将vpt的地址存入 寄存器rax
mov (%rax),%rax 这里 相当于将 *vpt 将虚表的地址存入rax
mov (%rax),%rdx 这里相当于将 虚表第第一个地址存入 rax, 通过上面的分析可以知道,a指向的是b的地址,所以这里取的是类B的虚函数表地址,而b的虚函数表第一个地址存入的是类声明虚函数时存入的 B::f1的地址,所以这里真实取的是B::f1
mov -0x10(%rbp),%rax mov %rax,%rdi 这里相当于将this指针传入函数的第一个参数
call *%rdx 调用虚函数

最后输出:

A::f1
B::f1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值