如何获取 elf 二进制文件的堆起始地址

how to get heap start address of a elf binary

我用 C 编写了一个示例程序,它使用 libelf 来转储不同的部分。 但是我想转储堆和堆栈段的起始地址,该地址仅在进程“活动”时可用(运行ning)。

这就是我对从磁盘读取的二进制文件所做的。

elf_fd = open(elf_fname, O_RDWR);
    if(elf_fd < 0) {
        fprintf(stderr, "Failed to open \"%s\" reason=%s\n", elf_fname, strerror(errno));
        return -1;;
    }

followed by

        if(elf_version(EV_CURRENT) == EV_NONE) {
            fprintf(stderr, "Failed to initialize libelf\n");
            res = -1;
            goto done;
        }
    
elf->e = elf_begin(elf->fd, ELF_C_READ, NULL);
if(!elf->e) {
    int err = elf_errno();
    if (err != 0) {
        fprintf(stderr, "Failed to open ELF file code=%d reason=%s\n", err, 
        elf_errmsg(err));
    }
    res = -1;
    goto done;
}

当我读取磁盘上的二进制图像时,这工作正常

运行 时间我尝试的是而不是这样做 那就是使用 open

返回的 elf_fd
elf_fd = open(elf_fname, O_RDWR);
if(elf_fd < 0) {
    fprintf(stderr, "Failed to open \"%s\" reason=%s\n", elf_fname, strerror(errno));
    return -1;;
}

I instead do this
That is i get a handle from the pid of the current process

elf_fd = pidfd_open(getpid(), 0);
if (elf_fd == -1) {
    perror("pidfd_open");
    fprintf(stderr, "failed to open self %d\n", elf_fd);
    exit(EXIT_FAILURE);
}

它 returns 我是一个有效的描述符,但是当我将此描述符与

一起使用时
elf->e = elf_begin(elf->fd, ELF_C_READ, NULL);
if(!elf->e) {
    int err = elf_errno();
    if (err != 0) {
        fprintf(stderr, "Failed to open ELF file code=%d reason=%s\n", err, 
        elf_errmsg(err));
     }
}

它说“无效的描述符”。

问题是如何从其中获取实时进程的堆和堆栈基址

是的,我也在主调用的一开始就尝试过 sbrk(0) & 它似乎打印了堆起始地址,但这可能并不总是可靠的,因为在没有 malloc 调用之前可能没有堆 现在它似乎确实打印出来了。

Question is how can i get heap & stack base address of a live process from within it

请注意,堆和堆栈都与 ELF 格式没有任何关系,或者 libelf

没有“堆基址”这样的东西——大多数现代堆分配器将执行多重mmap调用从 OS 获取内存,然后将其“分发”给各种 malloc 请求。

i did also try at the very start in main call sbrk(0)

“Legacy”malloc 用于使用 sbrk() 获取内存,但很少有现代的这样做。如果您使用的 malloc 确实使用 sbrk,那么在 main 开始附近调用 sbrk(0) 是一个可用的近似值。

对于主线程堆栈,您可能希望这样做。一个很好的初步近似是采用 &argc,并将其四舍五入到页面边界。

如果你想获得更好的近似值,你可以使用这样一个事实,即在 Linux(可能还有其他 ELF 平台)上,内核在调用入口点之前将 specific values 放在堆栈上。遍历 __environ 值寻找最高地址将给出更好的近似值。