C++中ABI的问题——1.ABI问题的产生

春招结束,发现面试的后面几面,会闻到c++的abi问题,大致问题就是,gcc编译的库,clang能用吗,或者在升级so文件的时候要注意什么,当时不知道,现在来总结一下。

这个abi问题,网上资料不是很多,有一些零零散散的,最后自己总结了一下以后,在这里做个笔记。

一般的软件为了模块分割,思路都是这样的:

模块写在so/dll文件中,使用exe加载并执行功能,更新只用更新dll、so就可以了。不用重新编译exe

这是一篇ABI兼容的文章 https://www.jianshu.com/p/895451c7b678

ABI兼容的目的就是为了保证改变了dll,so以后,不用重新编译exe就可以直接使用。

当ABI不兼容,或者ABI出错的时候,会发生什么呢?我们来看一个例子

先给出一个继承图:

vclass  ->    obj

//interface.h
#include<string>
class vclass{
public:
    std::string name;
    virtual std::string get_name()=0;
};
//lib.h,继承自interface,重写虚函数
#include"interface.h"
#include<string>
class obj : public vclass{
public:
    std::string get_name();//获得name
    obj(){
        name="子类";
    }
};
extern "C" vclass* get_obj(){  //使用C格式的函数命名
    return new obj;
}
//lib的实现
#include"lib.h"
std::string obj::get_name(){
    return name;
}

很简单的例子吧,就是实现了一个接口,然后返回name的值,随后我们在main中调用dlopen,来打开这个动态链接库:

#include<iostream>
#include<memory>
#include<dlfcn.h>
#include"interface.h"
using namespace std;
int main(){
    void *handle=dlopen("./lib.so",RTLD_NOW);//加载so文件
    using func= vclass*(*)(void);
    func get_obj;
    get_obj=(func)dlsym(handle,"get_obj");//从so中获取函数
    vclass *obj1=(get_obj());       //获取一个对象
    cout<<obj1->get_name()<<endl;   //能够成功得到子类的对象

    return 0;
}

 运行的结果很显而易见,直接会输出动态库中的"子类“

#makefile
lib:lib.h lib.cpp  
	g++ -g -fPIC -shared -o lib.so lib.cpp

main:main.cpp
	g++ -g main.cpp -o main -ldl 

ok,现在问题来了,现在有另外一个同事,由于某种需求,在父类加了一个虚函数xxxx(),并且在get_name()虚函数前(这个顺序非常重要,因为虚函数表):

#include<string>
class vclass{
public:
    std::string name;
    virtual std::string xxxx(){
        return "哈哈哈哈";
    }
    virtual std::string get_name()=0;
};

那么现在保持子类不动,main也不编译,直接重新编译 lib

#makefile
lib:lib.h lib.cpp  
	g++ -g -fPIC -shared -o lib.so lib.cpp

现在运行main,你就会发现,我的get_name()呢?去哪了?怎么变成哈哈哈哈了?

这就是ABI的一个特点。

因为加入了新的一个虚函数,使得原来虚函数表的顺序由:

get_name;

变成了:

xxxx

get_name

但是main.cpp 中的obj->get_name(),在汇编中只是访问虚函数表中特定偏移量的函数,在这个例子中,访问的是虚函数表中第一个函数。 那么我们通过修改虚函数表的大小,就会导致函数运行出错。所以,一旦涉及到需要动态运行so的,就要考虑到abi了。业界比较常用的,保持C++ ABI兼容的方法是Q指针和D指针,这个我们其他文章再慢慢道来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值