我一直在尝试实现一个小的模拟,以理解malloc()的内存分配。我创建了一个名为mem.c的共享库。我将库链接到主库,但无法传递模拟“堆”的正确地址。堆是由共享库中的malloc()调用创建的。
共享库中的地址: 0x55ddaff662a0主地址:0xffffffaff662a0
只有最后4个字节似乎是正确的。Rest设置为0xf。
但是,当我#包括"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
发布于 2021-05-11 12:54:19
从你的评论
我试图在不使用#include mem.h或mem.c的情况下实现。
然后,您必须以其他方式为您正在调用的函数提供一个原型。在没有显式函数原型的情况下,遵循K&R以及后来的ANSI C的传统,假定未声明的函数返回int
并接受int
类型的参数。
编辑:从本质上说,在第一次使用该函数之前,您需要在标题中写出通常所找到的内容。或者它是一个函数指针,您需要一个适当的变量来存储函数指针。
例如,要声明一个返回非类型化指针的函数,以及要编写的任意、未指定数量的参数
void *getAddr();
请注意,这里不需要使用extern
关键字,因为对于非静态函数声明,始终隐含着外部链接。
如果您希望在运行时动态链接(使用dlopen
/ LoadLibrary
→dlsym
/ GetProcAddress
),则需要定义一个函数指针变量
void* (*getAddr_fptr)();
您可以使用dlsym
与
*(void**)(&getAddr_fptr) = dlsym(…)
这种笨拙的编写方式是因为函数指针允许具有与数据指针不同的大小和对齐方式(有关详细信息,请参阅dlsym手册)。
如今,在大多数平台上,int
是一个4字节的类型,最常见的调用约定是通过寄存器传递前几个函数参数。在x86 (和x86_64)上,寄存器是AX、BX、CX和DX,可以以不同的大小访问,但可以以不同的大小读写(以允许大小转换)。这就解释了为什么只传递前4个字节:它是通过寄存器传递的,只有对寄存器的写入是4字节宽的写入。然后,当函数从寄存器中读取时,它使用更宽的类型进行读取,并将较高的值位设置为全部1。
发布于 2021-05-11 13:20:24
从评论中:
您的主代码中有
getAddr
的声明吗?不,我没有,但我试图在没有声明的情况下实现,这可能吗?
那就是你的问题了。如果没有声明,编译器将返回到int getAddr()
的默认声明。这与返回void *
的实际定义不兼容,通过不兼容声明调用函数会触发未定义行为。
可能发生的情况是,当函数的返回值实际被返回时,您只得到了4个低阶字节。假设您的系统是小终端,int
是4字节,void *
是8字节,这将解释低位数是相同的。
在调用函数之前,必须包含一个有效的声明。它不一定驻留在头文件中,但在调用发生时必须是可见的。
https://stackoverflow.com/questions/67493521
复制相似问题