因此 libgcc 将使用应用程序的 malloc 和 free(如果它已定义的话)以满足应用程序在某些库调用(例如 realpath)之后调用 free() 的需要。
在我的动态库中,我真的不想使用那个应用程序 malloc/free,因为我通常不信任它 - 我很乐意使用 libgcc 的 malloc 实现,这是大多数应用程序使用的,所以我声明了我自己的 malloc() 函数,该函数通过 dlsym() 调用 libgcc 的实现。
一切都很顺利,直到...我想调用 realpath(也许还有其他人)!作为一个简单的修复,我需要一种方法来执行与 dlsym() 等效的操作,但要在主要可执行文件(我不拥有)上执行此操作以获取应用程序的免费实现(如果有的话)。这样的事情存在吗?
我知道它必须这样做,因为动态链接器“做正确的事”,但普通程序员是否可以访问它,如何访问?
在 realpath 的特殊情况下,我知道我可以提供一个缓冲区,但这会带来缓冲区大小方面的未知危险。对于其他一些调用,我不能这样做。
我也可以使用 objcopy 沿着蜿蜒的符号重命名路径走下去,但如果可能的话,我不想这样做。
[后来]
我确实同意你关于 malloc 可能由另一个动态库定义的观点,我想使用那个版本,而应用程序仍然使用它的编译版本(我已经看到它确实继续使用它,即使 tcmalloc 是预加载的,例如。
我想这会扩展问题以询问是否有任何库定义了 malloc,如果应用程序定义了 malloc,我想挑选我在代码中的每个地方使用哪个版本的 malloc/free 来匹配行为必要时使用 libgcc,不需要时使用,所以我希望能够获得对它们的引用。
在短期内,在调用 libgcc 实现之前,我通过将代码中的 realpath() 替换为使用我的 malloc 预定义缓冲区的版本来解决我当前的问题,但我觉得这非常困难 -助手。
最佳答案
插入的malloc
可以来自任何地方,而不仅仅是可执行文件。它可以是另一个对象的动态部分中的 DT_NEEDED
条目引用的共享对象,或者是使用 LD_PRELOAD
注入(inject)过程镜像的库。
一般来说,许多库都有分配一些东西的函数,然后必须使用 free
释放这些东西。移植到 Windows 的软件不会这样做(因为 DLL 在那里有单独的堆),但除此之外,它并不少见。不仅有 realpath
,还有 strdup
、asprintf
,可能还有一些我不记得的其他函数。
在您的情况下,您应该只对此类指针调用 free
,并为您自己的内存释放函数使用不同的名称。一旦 malloc
被插入,就不可能安全地使用原始的 libc 分配器,因为它没有被正确初始化。例如,如果您在使用不同的插入式 malloc
的进程中调用 glibc malloc
函数,则 malloc
将不是线程安全的:初始化不是线程安全的,因为实现知道 pthread_create
将在创建第一个新线程之前调用 malloc
,从而初始化 malloc
,同时进程是单线程的。这就是初始化代码中没有同步的原因。
(libgcc 不提供 malloc
,顺便说一句。它来自 libc/glibc。)
关于c - 如何从动态库中检测主要可执行文件的函数定义 - 特别是 malloc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49180943/