首页 > 解决方案 > 无法从 C 中的共享库返回正确的内存地址

问题描述

我一直在尝试实现一个小型模拟来了解 malloc() 的内存分配。我创建了一个名为 mem.c 的共享库。我将库链接到主库,但无法传递模拟“堆”的正确地址。堆是由共享库中的 malloc() 调用创建的。

共享库中的地址:0x55ddaff662a0 主库中的地址:0xffffffffaff662a0

只有最后 4 个字节似乎是正确的。休息设置为 0xf。

但是,当我在 main 中 #include "mem.c" 时,它可以正常工作。在不包括 mem.c 的情况下如何获得相同的结果。我试图在不包括 mem.c 或 mem.h 的情况下解决这个问题。我这样创建共享库:

gcc -c -fpic mem.c
gcc -shared -o libmem.so mem.o
gcc main.c -lmem -L. -o main

标签: clinuxbashpointersshared-libraries

解决方案


从你的评论

我试图在不使用#include mem.h 或 mem.c 的情况下实现。

然后,您必须通过其他方式为您正在调用的函数提供原型。如果没有明确的函数原型,遵循 K&R 和后来的 ANSI C 的传统,未声明的函数被假定返回 anint并采用 type 的参数int

编辑:本质上,您需要在第一次使用该功能之前的某个地方写下您通常在标题中找到的内容。或者它是一个函数指针,您需要一个适当的变量来存储函数指针。

例如,要声明一个返回无类型指针的函数,以及您要编写的任意、未指定数量的参数

void *getAddr();

请注意,extern此处不需要使用关键字,因为非静态函数声明始终隐含外部链接。

如果您想在运行时动态链接(使用dlopen/ LoadLibrarydlsym/ GetProcAddress),您将定义一个函数指针变量

void* (*getAddr_fptr)();

您可以使用dlsymwith设置它

*(void**)(&getAddr_fptr) = dlsym(…)

这种笨拙的写法是因为函数指针被允许具有与数据指针不同的大小和对齐方式(有关详细信息,请参见 dlsym 手册页)。

如今,在大多数平台上int是 4 字节类型,最常见的调用约定通过register传递前几个函数参数。在 x86(和 x86_64)上,寄存器是 AX、BX、CX 和 DX,可以以不同的大小访问,但可以以不同的大小读写(以允许大小转换)。这解释了为什么只传递前 4 个字节:它是通过寄存器传递的,只有对寄存器的写入是作为 4 字节宽的写入完成的。当函数然后从寄存器中读取时,它会使用更宽的类型,将较高值的位设置为全 1。


推荐阅读