我可以用 C++ 编写一个预加载库吗?除了在要拦截的函数前面添加 `extern "C"` 之外,我还需要做什么吗?

问题描述 投票:0回答:1

我正在开发一个个人项目,我需要拦截Linux API,如

open()
read()
等,我想对它们进行一些数据分析。我需要在库中保留一个 C++ 数据结构
std::map
,它将以线程安全的方式更新。

因为我想使用 C++ 的

std::map
,所以我正在考虑编写库 (
.so
) 来使用 C++ 进行预加载,并且要拦截的函数将在前面加上
extern "C"
,以防止 C++ 编译器进行名称修改。

但是,这是正确的做法吗?我应该纯粹用 C 编写共享库,并从头开始实现

map
数据结构吗?

c++ shared-libraries ld-preload extern-c
1个回答
0
投票

这是正确的做法吗?

这种方法没有什么特别错误的地方,但它可能会变得复杂(见下文)。

我应该纯粹用C编写共享库,并从头开始实现地图数据结构吗?

这将消除许多潜在的并发症。


那么有哪些并发症呢?

为了使用

std::map
,您必须将预加载
.so
链接到
libstdc++.so.6
,它将尝试在您的库之前初始化自身。

而且

libstdc++
又大又复杂。如果它的初始化调用
open()
read()
等,我不会感到惊讶。

这意味着您的图书馆必须准备好处理这些调用,然后才能预期

libstdc++.so
正常工作。

以下序列可能发生并导致您的库崩溃:

  • libstdc++.so
    调用
    open
    ,这是由您的图书馆插入的
  • 您的插入器尝试将某些内容放入
    std::map
    实例中,该实例再次调用
    libstdc++.so
  • 它会崩溃,因为它不希望自己对
    open
    的调用返回到
    libstdc++

上述的许多变体都是可能的,您获得的变体可能取决于您插入的确切函数集、您对

libstdc++
进行的调用集以及
libstdc++
的版本。

也就是说,它可能工作正常,直到您在不同的系统上尝试它,或者直到您更新您的

g++
,或者直到您添加新的插入器。或者它可能根本不起作用。

当然不是设计可以工作,所以你会玩俄罗斯轮盘赌。

© www.soinside.com 2019 - 2024. All rights reserved.